元类
一:元类介绍
“元类就是深度的魔法,99%的用户应该根本不必为此操心。
如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。
那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”
—— Python界的领袖 Tim Peters
一切都源自一句话:在Python中,一切皆对象
元类:类他爹
定义类,可以控制对象的产生
元类,可以控制类的产生
# 元类 ==> People类 ==> obj
class People(object):
school = 'Tinghua'
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
obj = People('xxq', 18)
# 调用People类 ==> 对象obj
# 调用元类 ==> People类
# 查看类(类型)
print(type(obj)) # <class '__main__.People'>
print(type(People)) # <class 'type'> # 默认的元类是:type
结论:
默认的元类是:type
,默认情况下,我们用class关键字定义的类 都是由type
产生的
二:class
关键字 底层做了哪些事?
1.先拿到1个类名
class_name = 'People'
2.拿到 类的父类
class_bases = (object,)
3.再拿到类的名称空间(运行类体代码得到的)
class_dic = {}
class_body = '''
school = 'Tinghua'
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
'''
exec(class_body, {}, class_dic)
# print(class_dic)
补充:exec的使用
dic = {} # 空字典
s = '''
a = 1
b = 2
c = 3
'''
exec(s, {}, dic)
print(dic)
4.调用元类(传入类的3大要素:类名、基类、类的名称空间) 得到1个元类的对象,然后将元类的变量赋值给People(这个People就是我们用class自定义的类)
People = type(class_name, class_bases, class_dic)
5.完整思路
# 1.先拿到1个类名
class_name = 'People'
# 2.拿到 类的父类
class_bases = (object,)
# 3.再拿到类的名称空间(运行类体代码得到的)
class_dic = {}
class_body = '''
school = 'Tinghua'
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
'''
exec(class_body, {}, class_dic)
# print(class_dic)
# 4.调用元类(传入类的3大要素:类名、基类、类的名称空间) 得到1个元类的对象,然后将元类的变量赋值给People(这个People就是我们用class自定义的类)
People = type(class_name, class_bases, class_dic)
三:自定义元类
1.先拿到1个类名:'People'
2.拿到 类的父类:(object,)
3.再拿到类的名称空间(运行类体代码得到的){...}
4.调用元类(传入类的3大要素:类名、基类、类的名称空间) 得到1个元类的对象,然后将元类的变量赋值给People(这个People就是我们用class自定义的类)
People = Mymeta('People', (object,), {...})
1.自定义元类
只有继承了type的类 才是自定义的元类
可以通过自定义的元类来规范类的产生
import re
class Mymeta(type): # 只有继承了type的类 才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
print(self) # 类
# print(class_name)
# print(class_bases)
# print(class_dic)
# 规范类名
if not re.match('[A-Z]', class_name):
raise BaseException('类名必须用驼峰体')
# 至少继承一个类
if len(class_bases) == 0:
raise BaseException('至少继承一个类')
# 文档注释
# print('文档注释:', class_dic.get('__doc__'))
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('必须要有文档注释,并且注释内容不能为空')
# People = Mymeta('People', (object,), {...})
class People(object, metaclass=Mymeta):
'''
这是我的文档注释
'''
school = 'Tinghua'
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
2.探究是否可调用
①自定义的类实例化的对象和其他int、list都不可调用
class Foo:
pass
obj1 = Foo()
obj2 = int(10)
obj3 = list([1, 2, 3])
# obj1()
# TypeError: 'Foo' object is not callable
# obj2()
# TypeError: 'int' object is not callable
# obj3()
# TypeError: 'list' object is not callable
②自定义的类加上__call__
方法后,实例化的对象,是可以直接通过加()
被调用的
调用对象 其实就是在调用对象类中 定义的绑定方法:__call__
class Foo:
def __call__(self, *args, **kwargs):
print('=========')
print(self)
print(args)
print(kwargs)
obj1 = Foo()
obj1(1, 2, 3, a=1, b=2) # 调用对象 其实就是在调用对象类中 定义的绑定方法:__call__
# (1, 2, 3)
# {'a': 1, 'b': 2}
3.自定义元类 控制类的调用
import re
class Mymeta(type): # 只有继承了type的类 才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
print(self) # 类
# print(class_name)
# print(class_bases)
# print(class_dic)
# 规范类名
if not re.match('[A-Z]', class_name):
raise BaseException('类名必须用驼峰体')
# 至少继承一个类
if len(class_bases) == 0:
raise BaseException('至少继承一个类')
# 文档注释
# print('文档注释:', class_dic.get('__doc__'))
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('必须要有文档注释,并且注释内容不能为空')
def __call__(self, *args, **kwargs):
# 1.先创建一个空对象
# 2.调用类的__init__方法,将空对象连同括号内的参数 一同传给__init__
# 3.将初始化好的对象 赋值给变量名obj
return 123
# People = Mymeta('People', (object,), {...})
class People(object, metaclass=Mymeta):
'''
这是我的文档注释
'''
school = 'Tinghua'
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
people_obj = People() # <class '__main__.People'>
print(people_obj) # 123
4.自定义元类 控制类的调用 - 进阶
import re
class Mymeta(type): # 只有继承了type的类 才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
print(self) # 类
# print(class_name)
# print(class_bases)
# print(class_dic)
# 规范类名
if not re.match('[A-Z]', class_name):
raise BaseException('类名必须用驼峰体')
# 至少继承一个类
if len(class_bases) == 0:
raise BaseException('至少继承一个类')
# 文档注释
# print('文档注释:', class_dic.get('__doc__'))
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('必须要有文档注释,并且注释内容不能为空')
# people_obj = People() 触发了下面的__call__
def __call__(self, *args, **kwargs):
# 1.先创建一个人的空对象
people_obj = object.__new__(self)
# 2.调用类的__init__方法,将空对象连同括号内的参数 一同传给__init__
# People.__init__
self.__init__(people_obj, *args, **kwargs)
# 3.将初始化好的人对象 赋值给变量名people_obj
return people_obj
# People = Mymeta('People', (object,), {...})
class People(object, metaclass=Mymeta):
'''
这是我的文档注释
'''
school = 'Tinghua'
# people_obj,'xxq',18
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
people_obj = People('xxq', 18) # <class '__main__.People'>
print(people_obj) # <__main__.People object at 0x00000200F400DD90>
print(people_obj.name) # xxq
print(people_obj.age) # 18
print(people_obj.say) # <bound method People.say of <__main__.People object at 0x000001E2AE41DD90>>
# 调用People类的时候,发生了什么
# 1.先创建一个人(people)的空对象
# 2.调用类的__init__方法,将空独享连同括号内的参数 一同传给__init__
# 3.将初始化好的人对象 赋值给变量名people_obj
5.自定义元类 将类的属性隐藏
import re
class Mymeta(type): # 只有继承了type的类 才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
print(self) # 类
# print(class_name)
# print(class_bases)
# print(class_dic)
# 规范类名
if not re.match('[A-Z]', class_name):
raise BaseException('类名必须用驼峰体')
# 至少继承一个类
if len(class_bases) == 0:
raise BaseException('至少继承一个类')
# 文档注释
# print('文档注释:', class_dic.get('__doc__'))
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException('必须要有文档注释,并且注释内容不能为空')
# people_obj = People() 触发了下面的__call__
def __call__(self, *args, **kwargs):
# 1.先创建一个人的空对象
people_obj = object.__new__(self)
# 2.调用类的__init__方法,将空对象连同括号内的参数 一同传给__init__
# People.__init__
self.__init__(people_obj, *args, **kwargs)
print(people_obj.__dict__)
people_obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in people_obj.__dict__.items()}
# 3.将初始化好的人对象 赋值给变量名people_obj
return people_obj
# People = Mymeta('People', (object,), {...})
class People(object, metaclass=Mymeta):
'''
这是我的文档注释
'''
school = 'Tinghua'
# people_obj,'xxq',18
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print(f'Hello {self.name}!')
people_obj = People('xxq', 18)
# <class '__main__.People'>
# {'name': 'xxq', 'age': 18}
print(people_obj.__dict__)
# {'_People__name': 'xxq', '_People__age': 18}