Discuss / Python / metaclass

metaclass

Topic source

Mr_RightMen

#1 Created at ... [Delete] [Delete and Lock User]
# 元类就是用来创建这些类(对象)的,元类就是类的类,
# 1.拦截类的创建;2.修改类;3.返回修改之后的类
# 除了使用type()动态创建类以外,要控制类的创建行为,就可以使用metaclass。

# type实际上就是一个元类,因此type()函数可以创建class
# 要创建一个class对象,type()函数依次传入3个参数
# 1.class 名称;2.继承的父类集合;3.class的方法名称与函数绑定
def fn(self,name='world'):
    print('Hello,{0}'.format(name))
Hello = type('Hello',(object,),dict(hello=fn))

# 看下面这个例子
class UpperAttrMetaclass(type):

    def __new__(cls, clsname, bases, dct):
        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

# 我们知道在python中一切皆对象
# 那么下面我们的s其实就是一个类对象,它的__name__其实和Foo的__name__是一样的
# 看下面的方法是不是和type创建类有点像?
s = UpperAttrMetaclass('Foo',(object,),{'bar':'bip'})
print(hasattr(s,'bar'))
print(hasattr(s,'BAR'))
print(s.BAR)

class Foo(object,metaclass=UpperAttrMetaclass):
    bar='bip'
print(hasattr(Foo,'bar'))
print(hasattr(Foo,'BAR'))
print(Foo.BAR)
# 最后它们输出的结果其实是一模一样的,这就说明了类其实和我们普通的实例对象差不多,只不过普通实例是通过类创建,而类是通过元类创建
# 而__new__就是用来创建实例的,不论是普通的实例,还是类实例,总之就是个实例

# __new__()方法接收到的参数依次是:
# 1.当前准备创建的类的对象;2.类的名字;3.类继承的父类集合;4.类的方法集合。
# 实际上在我们实例化对象时,python默认执行了__new__操作,先创建类实例,然后才使用__init__初始化实例

# python新类允许用户重载__new__和__init__方法。__new__创建类实例,__init__初始化一个已被创建的实例。看下面的代码
class newStyleClass(object):
    def __new__(cls):
        print("__new__ is called")
        return super(newStyleClass, cls).__new__(cls)

    def __init__(self):
        print("__init__ is called")
        print("self is: ", self)

newStyleClass()
# 我们发现__new__函数先被调用,接着__init__函数在__new__函数返回一个实例的时候被调用,并且这个实例作为self参数被传入了__init__函数

# 这里需要注意的是,如果__new__函数返回一个已经存在的实例(不论是哪个类的),__init__不会被调用。看下面的代码
obj = 12
# obj can be an object from any class, even object.__new__(object)

class returnExistedObj(object):
    def __new__(cls):
        print("__new__ is called")
        return obj

    def __init(self):
        print("__init__ is called")

returnExistedObj()

ASAPUo

#2 Created at ... [Delete] [Delete and Lock User]

简单易懂,谢谢

ASAPUo

#3 Created at ... [Delete] [Delete and Lock User]

最后关于new调用后是否会调用init的问题,建议大家看下官方文档: Typical implementations create a new instance of the class by invoking the superclass’s new() method using super().new(cls[, ...]) with appropriate arguments and then modifying the newly-created instance as necessary before returning it.

If new() returns an instance of cls, then the new instance’s init() method will be invoked like init(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to new().

If new() does not return an instance of cls, then the new instance’s init() method will not be invoked.


  • 1

Reply