new和init
python在实例化一个对象的过程中,先执行__new__方法,产生一个空的对象,再执行__init__方法,给空的对象加上属性值。
class Person():
def __new__(cls, *args, **kwargs):
print('=======new=======')
print(cls)
obj = super().__new__(cls)
print(obj)
print(obj.__dict__)
return obj
def __init__(self, name, age):
print(self)
self.name = name
self.age = age
p = Person('xiao ming', 10)
print(p.__dict__)
执行结果
<class '__main__.Person'>
<__main__.Person object at 0x000001CE80E91470>
{}
<__main__.Person object at 0x000001CE80E91470>
{'name': 'xiao ming', 'age': 10}
可以看出__new__返回的obj和__init__中的self是同一个对象。
call
当一个对象可以调用的时候,这个生成这个对象的类或者这个类的父类内部必然有__call__方法。
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print('Person obj called')
p = Person('xiao ming', 10)
print(callable(p))
p()
执行结果
True
Person obj called
元类
在python中万物皆是对象,类也是一个对象。生成类这个对象的类称之为元类(即元类是类的类),python中的type就是元类。如果需要自定义元类,只需要继承type类即可。
类的创建可以通过使用class关键字,也可以通过使用type。官方给出type的注释如下:
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
"""
通过type来创建一个类:
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def hello(self):
print('hello world')
Person = type('Person', (object, ), {'country': country, '__init__': __init__, 'hello': hello})
print(Person)
p = Person('xiao ming', 11)
print(p)
print(p.__dict__)
执行结果
<class 'type'>
<class '__main__.Person'>
<__main__.Person object at 0x000002B6C7F7BC18>
{'name': 'xiao ming', 'age': 11}
自定义元类
当一个类继承了type类的时候,这个类就是一个自定义的元类。元类可以影响类的创建过程,也可以影响类的实例化过程。当定义一个类的时候,实际上会执行元类的__new__方法和__init__方法;当对一个类进行实例化的时候,会调用元类的__call__方法。
元类对类的创建的影响
class MyType(type):
def __new__(cls, what, bases=None, dict=None):
print(cls)
obj = super().__new__(cls, what, bases, dict)
print(obj)
print(obj.__dict__)
return obj
def __init__(self, what, bases=None, dict=None):
print(dict)
super().__init__(what, bases, dict)
class Person(metaclass=MyType):
country = 'China'
def hello(self):
print('hello world')
执行结果
<class '__main__.MyType'>
<class '__main__.Person'>
{'__module__': '__main__', 'country': 'China', 'hello': <function Person.hello at 0x000001FDE82122F0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'__module__': '__main__', '__qualname__': 'Person', 'country': 'China', 'hello': <function Person.hello at 0x000001FDE82122F0>}
可以看出在初始化一个普通类的时候,先执行了元类的new方法,又执行了元类的init方法。普通类new方法中产生的对象的__dict__是空的,但是元类的new方法中产生的对象的__dict__不是空的,这一点有所区别。当我们设计一个类的时候,需要对设计的类添加一些限制,可以通过自定义元类的方式来限制它。
元类对类的实例化的影响
假如有一个普通类A,实例化A的过程在代码中体现为A(),A其实是元类的一个对象,A()本质上就是调用了元类的__call__方法。正如之前说的,对象+()其实是执行了实例化该对象的类的__call__方法。
class MyType(type):
def __call__(self, *args, **kwargs):
print(args)
print(kwargs)
print('call MyType __call__ method')
obj = self.__new__(self, *args, **kwargs)
obj.__init__(*args, **kwargs)
return obj
class Person(metaclass=MyType):
country = 'China'
def __new__(cls, *args, **kwargs):
print('call Person __new__ method')
return super().__new__(cls)
def __init__(self, name, age):
print('call Person __init__ method')
self.name = name
self.age = age
def hello(self):
print('hello world')
p = Person('xiao ming', 11)
print(p)
print(p.__dict__)
执行结果
('xiao ming', 11)
{}
call MyType __call__ method
call Person __new__ method
call Person __init__ method
<__main__.Person object at 0x0000015053A3B710>
{'name': 'xiao ming', 'age': 11}
Process finished with exit code 0
通过修改自定义元类的__call__方法可以改变普通类的实例化行为。比如我们需要限制类的某些属性为私有属性,就可以通过修改元类的__call__方法来实现。自定义的元类妹有__call__方法时,就会去调用其父类(type)类的call方法,type类的call方法我没看到具体的实现,感觉上应该是调用了普通类的new方法和init方法,这个通过调试模式可以看出。
元类实现单例模式
import threading
class SingletonType(type):
_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with SingletonType._lock:
if not hasattr(cls, '_instance'):
obj = object.__new__(cls)
obj.__init__(*args, **kwargs)
setattr(cls, '_instance', obj)
return cls._instance
class Person(metaclass=SingletonType):
pass
p1 = Person()
p2 = Person()
print(id(p1))
print(id(p2))
执行结果
1926578362744
1926578362744
两个对象的ID是一样的