python 元类的call总结_在Python的new、init、call和元类中,python,newinitcall,以及

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__)

执行结果

{}

{'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__)

执行结果

{'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')

执行结果

{'__module__': '__main__', 'country': 'China', 'hello': , '__dict__': , '__weakref__': , '__doc__': None}

{'__module__': '__main__', '__qualname__': 'Person', 'country': 'China', 'hello': }

可以看出在初始化一个普通类的时候,先执行了元类的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

{'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是一样的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值