元类回顾
什么是元类?
**最本质的概念: **能够实例化产生类的类,就是元类; type是python解释器内置的元类
或继承type这个类的类就是元类(自定义的元类)
class关键字底层原理: 通过type类来实例化得到类
调用了type()
只传一个参数有什么用?
打印这个对象的类型
print(type(1)) # 结果为: <class 'int'>
传三个参数就是class关键字的底层原理
def __init__(self, name):
self.name=name
Person = type('Person', (object,), {'a': 3, '__init__': __init__})
p = Person('nick')
p.name
# 等同于
class Person(object,):
a = 3
def __init__(self, name):
self.name=name
exec 就是执行字符串的代码, 当成Python解释器
ss = '''
x = 1
print(x)
'''
g = {}
l = {}
exec(ss, g, l)
自定义元类: 来控制类的产生; 继承type
class My_class(type):
def __init__(self, name, bases, dic):
# 如果dic里面没有name属性,抛出错误
a = dic.get('name')
if a:
raise Exception('没有name属性,不可创建')
def __call__(self, *args, **kwargs):
pass
class Person(metaclass=My_class): # Person = MY_class('Person', (object,), {...}) My_class类实例化, 会把三个参数传到My_class的__init__方法中
def __init__(self, name ):
self.name = name
p = Person('hys') # Person() 类实例化的时候会自动触发Person类的__init__的执行
更深层的意思
class My_class(type):
def __init__(self, name, bases, dic):
# self 是Person 这个类(对象)
print(self.__dict__) # 相当于Person.__dict__
# 在这个位置,其实self也就是说Person这个类,内部已经有东西了,名称空间已经有东西了
# 所以在这个地方,可以通过dic来判断名称空间
# 也可以直接通过self.__dict__/self.name(属性)来判断
# 如果dic里面没有name属性,抛出错误
a = dic.get('name')
if a:
raise Exception('没有name属性,不可创建')
def __call__(self, *args, **kwargs):
pass
class Person(metaclass=My_class): # Person = MY_class('Person', (object,), {...}) My_class类实例化, 会把三个参数传到My_class的__init__方法中
def __init__(self, name):
self.name = name
print(Person.__dict__)
p = Person('hys') # Person() 类实例化的时候会自动触发Person类的__init__的执行
总结:可以通过自定义元类,重写__init__方法来控制类的产生
通过元类控制类的调用过程, 实例化产生对象的过程
class My_class(type):
def __call__(self, *args, **kwargs):
# 该方法必须返回一个对象(类对象)吗, 这个地方return返回什么 p=Person('hys') p就是什么
# 第一步:产生一个空对象
# object.__new__(self) 传一个参数(类), 就会产生一个该类的空对象
obj = object.__new__(self) # obj 是Person类的空对象
print(self.__new__ is object.__new__) # True
# 第二步:初始化该对象, 把初始值放到对象中
# 因为 obj 是Person类的空对象, obj.__init__ 调用自己的绑定方法, 也就是说Person类中写的__init__方法
obj.__init__(*args, **kwargs)
# 还可以类来调用
# Person.__init__(obj, *args, **kwargs)
self.__init__(obj, *args, **kwargs)
# 第三步:把该对象返回
return obj
class Person(metaclass=My_class):
# class Person():
def __init__(self, name ):
self.name = name
def __call__(self, *args, **kwargs):
print('sbsh')
#原来的理解:Person('hys') 会调用Person类的__init__方法
#有了元类后:这个位置首先会调用元类的__call__方法, 所以再__call__方法中调用了Person类的__init__方法,来完成对象的初始化
p = Person('hys')
p() # 这个位置会调用类的__call__方法
模板:控制对象的产生
class My_class(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self)
obj.__init__(*args, **kwargs)
return obj
class Person(metaclass=My_class):
def __init__(self, name ):
self.name = name
def __call__(self, *args, **kwargs):
print('sbsh')
p = Person('hys')
作业: 把实例化传的参数,定义成字典的形式
class My_class(type):
def __call__(self, name, age):
obj = object.__new__(self)
# obj.__init__(*args, **kwargs)
obj.__dict__['attr']=['name':name, 'age': age]
return obj
class Person(metaclass=My_class):
def __init__(self, name, age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print('sbsh')
p = Person('hys', age)
# 这样才能拿到
print(p.attr[name])
# 不用init方法,但是能完成对象的初始化
练习:
-
在元类中控制把自定义类的数据属性都变成大写
-
在元类中控制自定义的类无需__init__方法
1.元类帮其完成创建对象,以及初始化操作;
2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
3.key作为用户自定义类产生对象的属性,且所有属性变成大写
-
在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性
-
基于元类实现单例模式

浙公网安备 33010602011771号