python中的__new__、__init__、__call__以及元类

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值