面向对象2元类

时间:2022-11-08 17:22:42

1.对象的一些内置方法

面向对象2元类面向对象2元类
#__str__:在对象被打印的时候自动触发,可以用来定义对象被打印时的输出信息
#注意:必须返回一个字符串类型的值

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return '<name:%s age:%s>'%(self.name,self.age)
lqz=People('lqz',18)
print(lqz)

#__del__:在对象呗删除时先自动触发该方法,可以用来回收对象以外其他相关资源,比如系统资源
# class Foo:
#     def __init__(self,x,filepath,encoding='utf-8'):
#         self.x=x
#         self.f=open(filepath,'rt',encoding=encoding)
#
#     def __del__(self):
#         print('run.....')
#         # 回收对象关联的其他资源
#         self.f.close()
#
# obj=Foo(1,'a.txt')
# # del obj
# print('主===========>')

#__call__:调用对象(就是对象加括号)时会调用该方法
View Code

2.元类

在python中,type和object的关系要理一下。

可以这么理解,在新式类中,object是所有类的超类。而type是object的类型,同时object又是type的超类。

可以把object和type理解成鸡生蛋,蛋生鸡的关系。

在python中,一切皆对象,而对象都是类实例化得到的

面向对象2元类面向对象2元类
class OldboyTeacher:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def score(self):
        print('%s is scoring' %self.name)

tea1=OldboyTeacher('egon',18,'male')
print(type(tea1))
print(type(OldboyTeacher))
View Code

OldboyTeacher=元类(...),内置的元类是type

关系:

1.调用元类----》自定义的类

2.调用自定义的类---->自定义的对象

class关键字创建自定义类的底层工作原理,分为四步

面向对象2元类面向对象2元类
#class关键字创建自定义类的底层工作原理,分为四步
#1.先拿到类名:'OldboyTeacher'
#2.再拿到类的基类们:(object,)
#3.然后拿到类的名称空间(执行类体代码,将产生的名字放到类的名称空间也就是一个字典里,补充exec)
#4.调用元类实例化得到自定义的类: OldboyTeacher=type('OldboyTeacher',(object,),{...})
# class OldboyTeacher: #OldboyTeacher=type(...)
#     school = 'Oldboy'
#     def __init__(self,name,age,sex):
#         self.name=name
#         self.age=age
#         self.sex=sex
#
#     def score(self):
#         print('%s is scoring' %self.name)
# print(OldboyTeacher)
#自定义类的三个关键组成部分
#1.类名
#2.类的基类们
#3.类的名称空间

#不依赖class关键字创建一个自定义类
#1.拿到类名
class_name='OldboyTeacher'
#2.拿到类的基类们
class_bases=(object,)
#3.拿到类的名称空间
class_dic={}
path={}
class_body="""
school = 'Oldboy'

def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex

def score(self):
    print('%s is scoring' %self.name)
"""
exec(class_body,{},class_dic)
print(class_dic)
#4.调用type得到自定义的类
OldboyTeacher=type(class_name,class_bases,class_dic)
print(OldboyTeacher)
tea=OldboyTeacher('lqz',18,'male')
print(tea.__dict__)
View Code

 

3.自定义元类

自定义元类是有模板的,如果有自定义逻辑,拿出来修改一下就行了

面向对象2元类面向对象2元类
#模板
class Mymeta(type):#但凡继承了type的类才能称之为自定义的元类,否则就只是一个普通的类
    def __init__(self,class_name,class_bases,class_dict):
        super().__init__(class_name,class_bases,class_dict)
        print(class_name)
        print(class_bases)
        print(class_dict)
class OldboyTeacher(object,metaclass=Mymeta):
    school='Oldboy'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def score(self):
        print('%s is scoring'%self.name)
View Code

自定义元类,可以控制类的产生

面向对象2元类面向对象2元类
class MyException(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg



#控制类的产生
#1.类名必须用驼峰体
#2.类体必须有文档注释
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dict):
        super().__init__(class_name,class_bases,class_dict)
        if class_name.islower():
            raise MyException('必须使用驼峰体,傻叉')
        doc=class_dict.get('__doc__')
        if doc is None or len(doc)==0:
            raise TypeError('类体中必须要有注释,傻叉')
class Oldboyteacher(object,metaclass=Mymeta):
    ' '
    school = 'Oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def score(self):
        print('%s is scoring' % self.name)

print(Oldboyteacher)
View Code

自定义元类来控制类的调用过程

面向对象2元类面向对象2元类
#实例化OldboyTeacher,或者说调用OldboyTeacher会
#1.先产生一个空对象
#2.执行__init__方法,完成对象的初始属性操作
#3.返回初始化好的那个对象
#调用OldboyTeacher(...)就是在调用OldboyTeacher的类中的__call__,那么在__call__中就需要做上述三件事

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        #1.先产生一个空对象(准备)
        tea_obj=self.__new__(self)#tea_obj是OldboyTeacher这个类的对象
        #2.执行__init__方法,完成对象的初始属性操作
        self.__init__(tea_obj,*args,**kwargs)
        #3.返回初始化好的那个对象
        return tea_obj

class OldboyTeacher(object,metaclass=Mymeta):
    school = 'Oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def score(self):
        print('%s is scoring' %self.name)

tea=OldboyTeacher('lqz',18,'male')
print(tea.__dict__)
View Code

类的属性查找顺序

先找自己继承的父类,一直找到object类,还找不到则再找自己的元类,再到type类

注意:这里查找顺序,是把OldboyTeacher当成了对象,而不是当成类看待

面向对象2元类面向对象2元类
class Mymeta(type):  # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
    n=444
    def __call__(self, *args, **kwargs): #self=OldboyTeacher这个类
        # 1. 先产生一个空对象
        tea_obj = self.__new__(self)  # tea_obj是OldboyTeacher这个类的对象
        # print(self.__new__ is object.__new__)
        # tea_obj=object.__new__(self)

        # 2. 执行__init__方法,完成对象的初始属性操作
        self.__init__(tea_obj, *args, **kwargs)
        # 3. 返回初始化好的那个对象
        return tea_obj


class Bar:
    # n = 33
    pass

class Foo(Bar):
    # n = 222
    pass

class OldboyTeacher(Foo, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    # n = 111
    school = 'Oldboy'

    def __init__(self, name, age, sex):
        self.name = name #None.name='egon'
        self.age = age
        self.sex = sex

    def score(self):
        print('%s is scoring' % self.name)

    def __new__(cls, *args, **kwargs):
        # print('=====>')
        return super().__new__(cls)

print(OldboyTeacher.n)
View Code