python作为一门万物皆对象的语言,每一个方法都由类产生,可类是如何产生的呢!这就必须提到提到元类,而理解元类,只需知道两句话:

  • 道生一,一生二,二生三,三生万物
  • 我是谁,我从哪里来,我要干什么

1、type(python的一切对象,都由type产生)
2、metaclass(元类,也叫类生成器)
3、class(也就是常用的类)
4、instance(类的实例)
5、methodattribute(实例方法和属性)

先看一个简单的,也是最常用的类。

# 创建一个Info类,二的源头
class Info():

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

    def output_name(self):
        print("My name is %s"%self.name)

# 从Info类实例化一个对象,二生三
a=Info("tom")

# 调用实例方法,三生万物
a.output_name()

输出结果
>>>My name is tom

其实,class Info只是一个函数的另一种写法。

def fn1(self):
    print("My name is %s" % self.name)

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

Info = type('Info', (object,), {"output_name": fn1,
                                "__init__": fn2})

a = Info("tom")
a.output_name()

输出结果
>>>My name is tom

以上,便是道生二的过程,由type直接生成一个类,而他的三个参数(name,bases,dict),则刚好映正:我是谁,我从哪里来,我要干什么。

name:我是谁,区分与其他一切的命名,这里为Info
bases:我从哪里来,当前类所继承的父类,object为python中最初级的一个类
dict:我要干什么,将类的方法和属性包装成一个字典传入,具体事件的实现方法

元类—道生一,一生二

上面只是type直接生成了class,也就是"道直接生成二"的过程,现在讲讲道生一,一生二的过程。
假如要写一个类,在不定义一个output方法的同时,又想该类的实例成员自带output的天赋(即自带output方法)。

class InfoMetaClass(type):

    def __new__(cls, name, bases, attrs):
        attrs["output_name"]=lambda self,value:print("My name is %s"%value)
        return type.__new__(cls, name, bases, attrs)

# 创建一个Info类,二的源头
class Info(object, metaclass=InfoMetaClass):

    pass

# 从Info类实例化一个对象,二生三
a=Info()

# 调用实例方法,三生万物
a.output_name("tom")

输出结果
>>>
My name is tom

可以看到,即使Info类中未定义output_name方法,但是他的实例化对象是有该方法的,因为他的元类赋予了它该方法。

其中元类的__new__方法中

  • cls:未元类本身
  • name:为使用该元类的类的类名
  • bases:继承的父类
  • attrs: 包含类的方法和属性的字典

下面为一具体的例子,统计一个类中所有以”a“开头的方法和属性。

# 由type创建一个元类,道生一
class InfoMetaClass(type):

    def __new__(cls, name, bases, attrs):
        # 定义一个my_dict的字典存放所有以”a“开头的方法和属性
        attrs["my_dict"]={}
        for k,v in attrs.items():
            if k.startswith("a"):
                attrs["my_dict"][k]=v
        return type.__new__(cls, name, bases, attrs)

# 由元类创建一个类,一生二
class Info(object, metaclass=InfoMetaClass):

    a_name="tom"
    b_name="jenny"

    def a_output_name(self):
        return a.a_name

    def a_output_age(self):
        return 25

    def s_hello(self):
        return "hello"

# 从Info类实例化一个对象,二生三
a=Info()

# 调用实例方法,三生万物
print(a.my_dict)

输出结果
>>>
{'a_name': 'tom', 'a_output_name': <function Info.a_output_name at 0x0000014FD2DDE950>, 'a_output_age': <function Info.a_output_age at 0x0000014FD2DDE9D8>}