标签:fun def 父类 strip() 对象 为什么 注释 tle 方法
目录
元类属于python面向对象编程的深层魔法,99%的人都不得要领,一些自以为搞明白元类的人其实也只是自圆其说、点到为止,从对元类的控制上来看就破绽百出、逻辑混乱,今天我就来带大家来深度了解python元类的来龙去脉。
笔者深入浅出的背后是对技术一日复一日的执念,希望可以大家可以尊重原创,为大家能因此文而解开对元类所有的疑惑而感到开心!!!
class Foo: # Foo=元类()
pass
cmd = """
x=1
print('exec函数运行了')
def func(self):
pass
"""
class_dic = {}
# 执行cmd中的代码,然后把产生的名字丢入class_dic字典中
exec(cmd, {}, class_dic)
exec函数运行了
print(class_dic)
{'x': 1, 'func': <function func at 0x10a0bc048>}
如果说类也是对象,那么用class关键字的去创建类的过程也是一个实例化的过程,该实例化的目的是为了得到一个类,调用的是元类
用class关键字创建一个类,用的默认的元类type,因此以前说不要用type作为类别判断
class People: # People=type(...)
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('%s is eating' % self.name)
print(type(People))
<class 'type'>
创建类的3个要素:类名,基类,类的名称空间
People = type(类名,基类,类的名称空间)
class_name = 'People' # 类名
class_bases = (object, ) # 基类
# 类的名称空间
class_dic = {}
class_body = """
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print('%s is eating' %self.name)
"""
exec(
class_body,
{},
class_dic,
)
print(class_name)
People
print(class_bases)
(<class 'object'>,)
print(class_dic) # 类的名称空间
{'country': 'China', '__init__': <function __init__ at 0x10a0bc048>, 'eat': <function eat at 0x10a0bcd08>}
People1 = type(class_name, class_bases, class_dic)
print(People1)
<class '__main__.People'>
obj1 = People1(1, 2)
obj1.eat()
1 is eating
print(People)
<class '__main__.People'>
obj = People1(1, 2)
obj.eat()
1 is eating
class Mymeta(type): # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
def __init__(self, class_name, class_bases, class_dic):
print('self:', self) # 现在是People
print('class_name:', class_name)
print('class_bases:', class_bases)
print('class_dic:', class_dic)
super(Mymeta, self).__init__(class_name, class_bases,
class_dic) # 重用父类type的功能
分析用class自定义类的运行原理(而非元类的的运行原理):
拿到一个字符串格式的类名class_name=‘People‘
拿到一个类的基类们class_bases=(obejct,)
执行类体代码,拿到一个类的名称空间class_dic={...}
调用People=type(class_name,class_bases,class_dic)
class People(object, metaclass=Mymeta): # People=Mymeta(类名,基类们,类的名称空间)
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('%s is eating' % self.name)
self: <class '__main__.People'>
class_name: People
class_bases: (<class 'object'>,)
class_dic: {'__module__': '__main__', '__qualname__': 'People', 'country': 'China', '__init__': <function People.__init__ at 0x10a0bcbf8>, 'eat': <function People.eat at 0x10a0bc2f0>}
自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程
我们可以控制类必须有文档,可以使用如下的方式实现
class Mymeta(type): # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
def __init__(self, class_name, class_bases, class_dic):
if class_dic.get('__doc__') is None or len(
class_dic.get('__doc__').strip()) == 0:
raise TypeError('类中必须有文档注释,并且文档注释不能为空')
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta, self).__init__(class_name, class_bases,
class_dic) # 重用父类的功能
try:
class People(object, metaclass=Mymeta
): #People = Mymeta('People',(object,),{....})
# """这是People类"""
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('%s is eating' % self.name)
except Exception as e:
print(e)
类中必须有文档注释,并且文档注释不能为空
class Foo:
def __call__(self, *args, **kwargs):
print(args)
print(kwargs)
print('__call__实现了,实例化对象可以加括号调用了')
obj = Foo()
obj('nick', age=18)
('nick',)
{'age': 18}
__call__实现了,实例化对象可以加括号调用了
class Mymeta(type):
def __call__(self, *args, **kwargs):
print(self) # self是People
print(args) # args = ('nick',)
print(kwargs) # kwargs = {'age':18}
# return 123
# 1. 先造出一个People的空对象,申请内存空间
obj = self.__new__(self)
# 2. 为该对空对象初始化独有的属性
self.__init__(obj, *args, **kwargs)
# 3. 返回一个初始化好的对象
return obj
class People(object, metaclass=Mymeta):
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('%s is eating' % self.name)
# 在调用Mymeta的__call__的时候,首先会找自己(如下函数)的,自己的没有才会找父类的
# def __new__(cls, *args, **kwargs):
# # print(cls) # cls是People
# # cls.__new__(cls) # 错误,无限死循环
# obj = super(People, cls).__new__(cls)
# return obj
类的调用,即类实例化就是元类的调用过程,可以通过元类Mymeta的__call__方法控制
分析:调用Pepole的目的
先造出一个People的空对象
为该对空对象初始化独有的属性
返回一个初始化好的对象
obj = People('nick', age=18)
<class '__main__.People'>
('nick',)
{'age': 18}
print(obj.__dict__)
{'name': 'nick', 'age': 18}
class Mymeta(type):
n = 444
# def __call__(self, *args, **kwargs):
# obj = self.__new__(self) # self = Foo
# # obj = object.__new__(self) # self = Foo
# self.__init__(obj, *args, **kwargs)
# return obj
class A(object):
# n = 333
pass
class B(A):
# n = 222
pass
class Foo(B, metaclass=Mymeta): # Foo = Mymeta(...)
# n = 111
def __init__(self, x, y):
self.x = x
self.y = y
for i in Foo.mro():
print(i)
<class '__main__.Foo'>
<class '__main__.B'>
<class '__main__.A'>
<class 'object'>
print(Foo.n)
444
查找顺序:
先对象层:Foo->B->A->object
然后元类层:Mymeta->type
print(type(object))
<class 'type'>
obj = Foo(1, 2)
print(obj.__dict__)
{'x': 1, 'y': 2}
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
# 加上逻辑,控制类Foo的创建
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
def __call__(self, *args, **kwargs):
# 加上逻辑,控制Foo的调用过程,即Foo对象的产生过程
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)
# 修改属性为隐藏属性
obj.__dict__ = {
'_%s__%s' % (self.__name__, k): v
for k, v in obj.__dict__.items()
}
return obj
class Foo(object, metaclass=Mymeta): # Foo = Mymeta(...)
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
obj = Foo('egon', 18, 'male')
print(obj.__dict__)
{'_Foo__name': 'egon', '_Foo__age': 18, '_Foo__sex': 'male'}
标签:fun def 父类 strip() 对象 为什么 注释 tle 方法
原文地址:https://www.cnblogs.com/nickchen121/p/10992975.html