元类

object是类的基类,type是类的元类

type

类的类

class Foo:
    pass

print(type(Foo))
# <class 'type'>

我们可以通过type来实例一个类,一个类创建的过程就是类的类被调用的过程

def fn(self, name='world'): # 假如我们有一个函数叫fn
    print('Hello, %s.' % name)
    
Hello = type('Hello', (object,), dict(say_hello=fn))  # 第一个参数是类名字,第二个参数是父类的集合,
# 第三个参数是类的方法和属性的字典,键是属性或方法名,

# 上面的写法就相当于
class Hello():
    def say_hello(self, name='world'):
        print('Hello, %s.' % name)

上面的类并没有声明自己的元类,默认就是type,

class Moo(type):
    pass
class Aoo():
    pass
class Foo(metaclass=Moo):
    pass

print(type(Moo))  # <class 'type'>
print(type(Aoo))  # <class 'type'>
print(type(Foo))  # <class '__main__.Moo'>

另外还有很重要的一点,一个类继承了指定元类的类,那么这个类的元类就会是继承类的元类

定义了metaclass的类的子类

在python2中元类的定义时作为类的属性

class Moo(type):
    pass

class Foo():
    __metaclass__ = Moo

  当一个类继承了Foo时,会向上查找到__metaclass__属性,也就会由__metaclass__指定的类来实例类.

在python3中虽然metaclass是由参数传递的,但他同样拥有这样的性质,一个类继承了指定metaclass的类,都会有指定的metaclass产生.

class a(type):
    def __init__(self,*args,**kwarsg):
        print("造了个类")
        type.__init__(self,*args,**kwarsg)

class c(metaclass=a): # 造了个类
    pass 
class d(c):  # 造了个类
    pass
class b(d):  # 造了个类
    pass

我们也可以通过继承type来重写元类来控制类的产生

自定义的元类也要接收三个参数

同时也要了解一下类的一些方法:

  • __new__: 对象的创建,是一个静态方法。第一个參数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
  • __init__ : 对象的初始化, 是一个实例方法,第一个參数是self。
  • __call__ : 实例可call。注意不是类,是实例。
先有创建,才有初始化。即先__new__,而后__init__。
class Aoo():
    def __call__(self):
        return "haha"
a = Aoo()
print(a())

# 哈哈哈

一个简单实例

class a(type):
    def __new__(cls, *args, **kwargs):
        print(args)  # ('b', (), {'__module__': '__main__', '__qualname__': 'b'})
        print(kwargs) # {}
        return type.__new__(cls, *args, **kwargs)
    def __init__(cls, name, bases, attrs):
        type.__init__(cls, name, bases, attrs)
        print("造了个类")
    def __call__(cls):
        type.__call__(cls)
        print("实例了个类")

class b(metaclass=a): # 造了个类
    pass

b() # 实例了个类

根据__call__实现单例模式:

既然类是元类的实例,那么类被实例化时就就执行了元类的__call__方法,我们可以根据这个来实现单例模式的类

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):  # 他的实例化出来的类实例化时调用了这个方法,
        if cls not in cls._instances:  
            # 如果这个来没有实例化对象,就去执行type的__call__方法,并且把实例存储在cls._instances中
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]  # 返回实例

class MyClass(metaclass=Singleton):
   pass

a = MyClass()

还可以

MyClass = Singleton("MyClass",(object,),{"name":"pa"})
a = MyClass()
b = MyClass()
print(a is b)
# True

  更多方法我也不会

posted @ 2018-03-09 21:03  瓜田月夜  阅读(234)  评论(0编辑  收藏  举报