文章目录
1、元类
python中一切皆为对象
1.1、元类的定义
python中一切皆为对象,那么我们自定义类本质也是一个对象,既然所有的对象都是调用类得到的,那么我们自定义的类必然也是调用了一个类得到的,这个类称为元类
元类 => 我们自定义的类 => 实例化得到对象
结论: 默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的
1.2、class关键字在底层的运行
(1) 先拿到一个类名
class_name = 'Teacher'
(2) 然后拿到类的父类
class_bases = (object,)
(3) 再运行类体代码,将产生的名字放到名称空间中
class_dic = {}
class_body = """
school_name = '北京大学'
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print('<{}:{}>'.format(self.name, self.age))
"""
exec(class_body,{},class_dic)
(4) 调用元类(传入类的三大要素: 类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Teacher,Teacher就是我们用class自定义的那个类
1.3、自定义元类
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
pass
class Teacher(object, metaclass=Mymeta):
school_name = '北京大学'
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print('<{}:{}>'.format(self.name, self.age))
1、先拿到一个类名: "Teacher"
2、然后拿到类的父类:(object,)
3、再运行类体代码,将产生的名字放到名称空间中{...}
4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Teacher,Teacher就是我们用class自定义的那个类
1.4、自定义元类来控制Teacher类的产生
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
# 可以增加逻辑对传递的参数进行逻辑判断
if class_name.islower():
raise BaseException('类名必须采用驼峰法')
if len(class_bases) == 0:
raise BaseException('至少要继承一个父类')
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('文档注释不能为空')
class Teacher(object, metaclass=Mymeta):
"""
文档注释
"""
school_name = '北京大学'
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print('<{}:{}>'.format(self.name, self.age))
1.5、自定义元类来控制Teacher类的调用
# __call__的使用
class Foo:
def __call__(self, *args, **kwargs):
print(self)
print(args)
print(kwargs)
obj = Foo()
obj(1, 2, a='111', b='222') # 调用对象其实就是在调用对象类中定义的绑定方法__call__
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
# 可以增加逻辑对传递的参数进行逻辑判断
if class_name.islower():
raise BaseException('类名必须采用驼峰法')
if len(class_bases) == 0:
raise BaseException('至少要继承一个父类')
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('文档注释不能为空')
# res = Teacher('allen',18)
def __call__(self, *args, **kwargs):
# 1、先创建一个老师的空对象
teacher_obj = object.__new__(self)
# 2、调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
self.__init__(teacher_obj, *args, **kwargs)
# 3、将初始化好的老师对象赋值给变量名res
return teacher_obj
class Teacher(object, metaclass=Mymeta):
"""
文档注释
"""
school_name = '北京大学'
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print('<{}:{}>'.format(self.name, self.age))
res = Teacher('allen', 18)
print(res.__dict__) # {'name': 'allen', 'age': 18}
1.6、自定义元类控制init方法中创建私有属性
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
# 可以增加逻辑对传递的参数进行逻辑判断
if class_name.islower():
raise BaseException('类名必须采用驼峰法')
if len(class_bases) == 0:
raise BaseException('至少要继承一个父类')
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('文档注释不能为空')
# res = Teacher('allen',18)
def __call__(self, *args, **kwargs):
# 1、先创建一个老师的空对象
teacher_obj = object.__new__(self)
# 2、调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
self.__init__(teacher_obj, *args, **kwargs)
# 拿到初始化好的对象按照隐藏属性的方法修改字典
teacher_obj.__dict__ = {'_{}__{}'.format(self.__name__, k): v for k, v in teacher_obj.__dict__.items()}
# 3、将初始化好的老师对象赋值给变量名res
return teacher_obj
class Teacher(object, metaclass=Mymeta):
"""
文档注释
"""
school_name = '北京大学'
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print('<{}:{}>'.format(self.name, self.age))
res = Teacher('allen', 18)
print(res.__dict__) # {'_Teacher__name': 'allen', '_Teacher__age': 18}
1.7、属性查找
class Mymeta(type):
n = 444
class Bar(object):
n = 333
class Foo(Bar):
n = 222
class Teacher(Foo, metaclass=Mymeta):
n = 111
school = '北京大学'
def __init__(self, name, age):
self.n = 0
self.name = name
self.age = age
# 站在对象的角度(对象 => 所在类 => 父类 => object)
obj = Teacher('allen', 18)
print(obj.n)
# 站在类的角度(类本身 => 父类 => 元类)
print(Teacher.n)