In [1]:
print(type(12))
print(type('python'))
In [2]:
class A:
pass
print(type(A))
通过这段代码可以看出,类对象 A
是由type()
产生的,也就是说 type
也可以用来产生新的对象,而且产生的是类对象,因此它是所有类对象的类:
In [3]:
print(type.__doc__)
class
定义类的语法实际上转化为 type(name, bases, dict)
,其中 name
参数为类的名字,bases
为继承父类的元组,dict
为类的属性和方法:
In [4]:
class A:
pass
# 实际上等于
B = type('A', (), {})
print(A.__name__ == B.__name__)
理论上说这就是元类的意义,但从实际的角度出发显然使用 class
语法更方便、合理,而元类的实际意义则是通过继承 type
类来构造一个新的元类,并进行特定的操作以产生具有特定行为的类对象。这样看来它的本质与普通的类对象没有差异,只不过继承的是 type
类。
在生成实例时是通过调用 __init__
方法进行初始化的,而实际上在此之前会先调用 __new__
方法用于创建实例,再通过 __init__
初始化,就好像 __new__
负责声明变量,而 __init__
负责对声明的变量进行初始化一样。这里有一个规则是 __new__(cls,)
的返回值必须是 cls
参数的实例,否则 __init__
将不会触发,例如在 enum.Enum
的定义中,由于枚举类型是单例模式,因此在定义 __new__
的时候没有返回其实例,也就不会进行初始化:
In [5]:
class Enum:
def __new__(cls, value):
print(cls, value)
return value
def __init__(self):
print("Will not be called!")
e = Enum(1)
通常情况下自己定义 __new__
需要通过调用父类的 __new__
方法创建一个 cls
的实例,同样在定义元类的时候则是调用上面提到的 type
的用法(因为元类继承自 type
):
In [6]:
class MetaEnum(type):
def __new__(metaclass, name, base, attrs):
print("Metaclass: {}\nName: {}\nParents: {}\nAttributes: {}".format(metaclass, name, base, attrs))
return super().__new__(metaclass, name, base, attrs)
In [7]:
class Enum(metaclass=MetaEnum):
# Python 2.7 中定义元类的方法是使用 __metaclass__ 变量
# [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
# 将 Python 3.0 以后语法改为 class Cls(metaclass=Meta)
test = 0
此时我们再来看 Enum
的类,已经不再是 type
而是其元类 MetaEnum
:
In [8]:
type(Enum)
Out[8]:
除了 __new__
方法之外,PEP 3115 还定义了 __prepare__
属性,用于设定初始化的命名空间(即 type
的第 3 个参数),还是以 enum.Enum
为例,我们需要限制枚举类型中属性名称不得重复使用,则可以通过元类限制类的行为:
In [9]:
# 定义新的字典类,在赋值新的 dict[k] = v 时
# 检查 k 是否重复
class _EnumDict(dict):
def __init__(self):
super().__init__()
self.members = []
def __setitem__(self, k, v):
if k in self.members:
raise TypeError("Attempted to reuse key: '{}'".format(k))
else:
self.members.append(k)
super().__setitem__(k, v)
class MetaEnum(type):
@classmethod
def __prepare__(metaclass, cls, bases):
return _EnumDict()
def __new__(metaclass, name, base, attrs):
return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
pass
class Color(Enum):
try:
red = 1
red = 2
except TypeError:# 这里没有使用 as err: 的原因是?
print("TypeError catched")
Python 中一切皆为对象,所有的对象都是某一类的实例,或是某一元类的实例,type
是自己的元类也是自己的实例: