源自一句话:在 Python 中,一切皆对象,而对象都是由类实例化得到的
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)) # <class '__main__.OldboyTeacher'>
print(type(OldboyTeacher)) # <class 'type'>
对象 tea1 是调用 OldboyTeacher 类得到的,如果说一切皆对象,那么 OldboyTeacher 也是一个对象,只要是对象,都是调用一个类实例化得到的,即OldboyTeacher = 元类(...)
,内置的元类是 type
关系:
- 调用元类 ---> 自定义的类
- 调用自定义的类 ---> 自定义的对象
调用元类实例化得到自定义的类:OldboyTeacher = type(...)
class OldboyTeacher():
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)
自定义类的三个关键组成部分:
- 类名
- 类的基类
- 类的名称空间
'''
class关键字创建自定义类的底层工作原理, 分为四步:
1. 先拿到类名: 'OldboyTeacher'
2. 再拿到类的基类: (object, )
3. 然后拿到类的名称空间
怎么拿??? (执行类体代码, 将产生的名字放到类的名称空间, 也就是一个字典里)
(而类体代码都是一堆字符, 所以要exec函数执行这堆字符, 将执行结果放入字典)
4. 调用元类实例化得到自定义的类: OldboyTeacher = type('OldboyTeacher', (object, ...), {...})
'''
不依赖 class 关键字创建一个自定义类
# 1. 拿到类名
class_name = 'OldboyTeacher'
# 2. 拿到类的基类
class_bases = (object, )
# 3. 拿到类的名称空间
class_dic = {}
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)
# print(OldboyTeacher.__dict__)
tea1 = OldboyTeacher("egon", 18, "male")
print(tea1.__dict__)
自定义元类来控制类的产生
- 但凡继承了
type
的类,才能称之为自定义的元类,否则就只是一个普通的类
# 模版
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
print(self)
print(class_name)
print(class_bases)
print(class_dic)
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
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)
- 控制类的产生
# 1. 控制类名必须用驼峰命名法
class Mymeta(type): # 但凡继承了type的类, 才能称之为自定义的元类, 否则就只是一个普通的类
def __init__(self, class_name, class_bases, class_dic):
if class_name.islower():
raise TypeError('类名必须使用驼峰命名法')
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
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)
# 2. 控制类体必须有文档注释, 且文档注释不能为空
class Mymeta(type): # 但凡继承了type的类, 才能称之为自定义的元类, 否则就只是一个普通的类
def __init__(self, class_name, class_bases, class_dic):
if class_name.islower():
raise TypeError('类名必须使用驼峰命名法')
doc = class_dic.get('__doc__')
if doc is None or len(doc) == 0 or len(doc.strip("
")) == 0:
raise TypeError('类体中必须有文档注释, 且文档注释不能为空')
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
'''这是注释'''
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.__dict__)
自定义元类来控制类的调用过程
class Mymeta(type): # 但凡继承了type的类, 才能称之为自定义的元类, 否则就只是一个普通的类
pass
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
school = 'Oldboy'
def __init__(self, name, age ,sex):
self.name = name
self.age = age
self.sex = sex
def __call__(self, *args, **kwargs):
print(self)
print(args)
print(kwargs)
def score(self):
print('%s is scoring' %self.name)
tea1 = OldboyTeacher("egon", 18, "male")
tea1(1,2,a=1,b=2) # 对象之所以能调用, 是因为对象所在的类有一个__call__函数
- 推导:如果一切皆对象,那么 OldboyTeacher 也是一个对象,该对象之所以能调用,肯定是这个对象的类中也有一个
__call__
函数
class Mymeta(type): # 但凡继承了type的类, 才能称之为自定义的元类, 否则就只是一个普通的类
def __call__(self, *args, **kwargs):
print(self)
print(args)
print(kwargs)
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
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)
tea1 = OldboyTeacher("egon", 18, "male") # 会触发OldboyTeacher的类, 即元类中的__call__函数
- 调用类实例化会:
- 先产生一个空对象
- 执行
__init__
方法,完成对象的初始化属性操作 - 返回初始化后的那个对象
- 调用 OldboyTeacher 就是在调用元类中的
__call__
函数, 所以这三件事是在调用__call__
中执行
class Mymeta(type): # 但凡继承了type的类, 才能称之为自定义的元类, 否则就只是一个普通的类
def __call__(self, *args, **kwargs): # self=OldboyTeacher这个类, args=("egon", 18, "male"), kwargs={}
# 1. 先产生一个空对象
tea_obj = self.__new__(self) # 将OldboyTeacher这个类传入, __new__会产生这个类的对象
# 所以tea_obj是OldboyTeacher这个类的一个对象, 目前是个空对象
# 2. 执行__init__方法, 完成对象的初始化属性操作
# 初始化还是到OldboyTeacher这个类中找__init__方法, 按参数一个个传值
# __init__中的self是对象, 在这里就是tea_obj
self.__init__(tea_obj, *args, **kwargs)
# 3. 返回初始化后的那个对象
return tea_obj
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
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)
tea1 = OldboyTeacher("egon", 18, "male") # 会触发OldboyTeacher的类, 即元类中的__call__函数
print(tea1)
print(tea1.__dict__)
- 练习:自定义元类来控制类的调用,把属性变为私有
class Mymeta(type): # 但凡继承了type的类, 才能称之为自定义的元类, 否则就只是一个普通的类
def __call__(self, *args, **kwargs): # self=OldboyTeacher这个类, args=("egon", 18, "male"), kwargs={}
tea_obj = self.__new__(self) # 将OldboyTeacher这个类传入, __new__会产生这个类的对象
self.__init__(tea_obj, *args, **kwargs)
# print(tea_obj.__dict__)
tea_obj.__dict__ = {('_%s__%s' %(self.__name__, k)):v for k,v in tea_obj.__dict__.items()}
return tea_obj
class OldboyTeacher(object, metaclass=Mymeta): # OldboyTeacher = Mymeta('OldboyTeacher', (object, ), {...})
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)
tea1 = OldboyTeacher("egon", 18, "male") # 会触发OldboyTeacher的类, 即元类中的__call__函数
# print(tea1)
print(tea1.__dict__)
属性查找
class Mymeta(type):
n = 444
def __call__(self, *args, **kwargs): # self=OldboyTeacher这个类
# 推荐使用这种
tea_obj = self.__new__(self)
# print(self.__new__ is object.__new__)
# tea_obj = object.__new__(self)
self.__init__(tea_obj, *args, **kwargs)
return tea_obj
class Bar:
# n = 333
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
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)
tea1 = OldboyTeacher("egon", 18, "male") # 会触发OldboyTeacher的类, 即元类中的__call__函数
# print(OldboyTeacher.n)
# 对象自己 --> Foo --> Bar --> object --> 元类 -- > type
# print(object.__new__)