一 引言--类也是对象

先看一个例子:

class Foo(object):
    pass

f = Foo()
print(f)            # <__main__.Foo object at 0x000001D1E43CD8D0>  f是通过Foo类实例化的对象

上述代码中,f是通过 Foo 类实例化的对象。其实,不仅f是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会在内存创建一个名字为Foo对象,所以,Foo类本身也是一个对象。因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:f对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建

print(type(f))      # <class '__main__.Foo'>   表示f对象由Foo类创建
print(type(Foo))    # <class 'type'>   表示Foo对象由type类创建

既然类也是对象,那我们可以将其作为一个对象去使用,可以:

  • 把类赋值给一个变量
  • 把类作为函数参数进行传递
  • 把类作为函数的返回值
  • 在运行时动态地创建类

python里foo是什么意思 foo在python_python

class Foo(object):
    pass

a = Foo             # 将类赋值给一个变量
print(a)            # <class '__main__.Foo'>

def func(obj):
    print(obj)

func(Foo)           # 将类作为参数传给函数,输出结果:<class '__main__.Foo'>

def func2():
    return Foo      # 将类作为函数的返回值

res = func2()
print(res)          # <class '__main__.Foo'>

示例

二 如何创建类

2.1 常规方式

class Foo(object):
    
    def __init__(self):
        pass
    
    def func1(self):
        pass

2.2 通过type创建

def __init__(self):
    pass

def func1(self):
    pass

Foo = type('Foo', (object,), {'xxx':'xxx','__init__':__init__,'func1': func1})
# type第一个参数:类名
# type第二个参数:当前类的基类,可以为空
# type第三个参数:类的成员,字典格式

print(Foo)          # <class '__main__.Foo'>
print(Foo.xxx)      # xxx
print(Foo.func1)    # <function func1 at 0x000001BF23651268>

# 构造出来的类等同于:
class Foo(object):
    
    xxx = 'xxx'
    
    def __init__(self):
        pass

    def func1(self):
        pass

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class

正常情况下,我们都用class Xxx...来定义类,但是,type()函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。

三 元类

3.1 何为元类

通过上面的描述,我们知道了Python中的类也是对象。元类就是用来创建这些类(对象)的,我们可以理解为:元类是类的类,是类的模板。元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为

元类的实例化的结果为我们用class定义的类,正如上面的例子:f1对象是Foo类的一个实例,Foo类(对象)是 type 类的一个实例

type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象

python里foo是什么意思 foo在python_python里foo是什么意思_02

补充:我们可以通过type()函数或者__class__属性获取对象的的类,该点仅适用于Python3。因为在经典类中,类(class)和类型(type)并不完全相同,经典类的实例总是继承自一个名为instance的内置类型。如果obj是一个经典类的实例,那么obj.__class__就表示该类,但type(obj)始终是instance类型。

python里foo是什么意思 foo在python_自定义_03

python里foo是什么意思 foo在python_python

a = 111
str1 = 'joe1991'
list1 = [1,2,3]

def func():
    pass

class Foo(object):
    pass

f = Foo()

print(type(a))              # <class 'int'>
print(a.__class__)          # <class 'int'>

print(type(str1))           # <class 'str'>
print(str1.__class__)       # <class 'str'>

print(type(list1))          # <class 'list'>
print(list1.__class__)      # <class 'list'>

print(type(func))           # <class 'function'>
print(func.__class__)       # <class 'function'>

print(type(f))              # <class '__main__.Foo'>
print(f.__class__)          # <class '__main__.Foo'>

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

# 对于任何一个__class__的__class__属性又是什么
print(a.__class__.__class__)            # <class 'type'>
print(str1.__class__.__class__)         # <class 'type'>
print(list1.__class__.__class__)        # <class 'type'>
print(func.__class__.__class__)         # <class 'type'>
print(f.__class__.__class__)            # <class 'type'>
print(Foo.__class__.__class__)          # <class 'type'>
# 可以看到,最终都是type

View Code

3.2 metaclass

一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,我们也可以通过继承type来自定义元类,这时我们就需要用到metaclass来指定我们自定义的元类

我们可以这样来理解metaclass:

当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例

但是如果我们想创建出类呢?那就必须根据metaclass(这里的metaclass可以是自定义的,或者type)创建出类,所以:先定义metaclass,然后创建类

连接起来就是:先定义metaclass,就可以创建类,最后创建实例

所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”

class Foo(object):   # py2
    __metaclass__ = xxx


class Foo(metaclass = xxx):   # py3
    pass

补充说明:在类被定义的时候,并没有在内存中生成,直到它被调用。然后Python会在当前类中寻找metaclass属性,如果存在,Python会在内存中通过metaclass创建一个类对象,如果没有则会一直向上寻找,如果一直找不到,python就会用内置的type来创建这个类对象

3.3 类的创建过程

class Foo(object):   # 不指定metaclass时,默认由type创建

    def __init__(self, xxx):
        self.xxx = xxx

    def __call__(self, *args, **kwargs):
        print(self, args, kwargs)


f = Foo('ooo')      # Foo实例化,不会楚发__call__

f(1,2,3)            # 对象f加括号执行才会触发__call__

# 总结:如果说类Foo是元类type的实例,那么在元类type内肯定也有一个__call__,会在调用Foo('ooo')时触发执行,然后返回一个初始化好了的对象obj

接下来我们自定义元类来完成这一过程

python里foo是什么意思 foo在python_python_05

python里foo是什么意思 foo在python_自定义_03

python里foo是什么意思 foo在python_python

class MyMetaclass(type):

    def __init__(self,  *args, **kwargs):
        super(MyMetaclass,self).__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        obj = cls.__new__(cls, *args, **kwargs)     # 若当前生成类无__new__方法,会一直向上寻找至object
        cls.__init__(obj, *args, **kwargs)
        return obj  # 一定要返回obj,因为实例化对象时就是获取__call__的返回值

class Foo(object, metaclass=MyMetaclass):

    def __init__(self, name):
        self.name = name

    def __new__(cls,  *args, **kwargs):
        return object.__new__(cls,)


# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象

obj = Foo('joe')
print(obj.__dict__)

源码

总结:

1. 类由元类(包括type或者自定义元类)创建,创建时自动元类中的__init__方法,所以我们可以元类的__init__方法中控制类的创建行为

2. 类()执行元类的__call__方法(类的__new__方法以及__init__方法),然后返回类的实例对象

注意:

在python3的__new__方法中,若返回object.__new__(cls, *args, **kwargs)会报错:TypeError: object() takes no parameters,修改为:object.__new__(cls )即可,python2中无异常

3.4 自定义元类简单应用

python里foo是什么意思 foo在python_自定义_03

python里foo是什么意思 foo在python_python

class MyMetaclass(type):

    def __init__(self, class_name, class_bases, class_dic):  # 这里接收的参数实则为传入type()中参数:类名、基类元组、属性字典

        if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():
            raise TypeError('必须为类指定文档注释')

        if not class_name.istitle():
            raise TypeError('类名首字母必须大写')

        super(MyMetaclass,self).__init__(class_name, class_bases, class_dic)

    def __call__(cls, *args, **kwargs):
        obj = object.__new__(cls)         # 若当前生成类无__new__方法,会一直向上寻找至object
        cls.__init__(obj, *args, **kwargs)
        return obj

class Foo(object, metaclass=MyMetaclass):
    """
    自定义元类玩玩
    """

    def __init__(self, name):
        self.name = name

    def __new__(cls,  *args, **kwargs):
        return object.__new__(cls,)


# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象

obj = Foo('joe')
print(obj.__dict__)

View Code

3.5 基于元类实现单例模式

python里foo是什么意思 foo在python_自定义_03

python里foo是什么意思 foo在python_python

class MySingleton(type):

    def __init__(self, *args, **kwargs):
        self.__instance = None          # 初始化self.__instance = None
        super(MySingleton,self).__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(MySingleton,self).__call__(*args, **kwargs)
        return self.__instance


class Foo(object, metaclass=MySingleton):   # 执行元类中的__new__方法和__init__方法,且仅会执行一次

    def __init__(self):
        pass

f1 = Foo()
f2 = Foo()

print(f1 is f2)  # True