元类
元类
元类的定义
元类其实就是产生类的类,需要注意的是,元类和父类有非常大的不同。
- 父类与子类是在面向对象的继承中的定义。通过继承子类能够使用父类的数据和方法
- 元类是在类的产生阶段的概念。只有产生类的类才能称为元类
- 元类不能直接通过继承的方式指定
元类的引入
在学习数据类型的时候,关键字type
的作用是查看数据类型。
print(type('oliver')) # <class 'str'>
print(type(25)) # <class 'int'>
print(type({'name': 'oliver', 'age': 25})) # <class 'dict'>
print(type(['oliver', 25])) # <class 'list'>
学习面向对象编程以后,我们知道python中可以说是万物皆对象
。自然而然,数据和类都应该是对象。根据查看数据类型的过里的<class 'str'>
里面的class
,我们大概能知道str
其实是一个类名。而这里查看的其实也不是数据类型,而是产生该对象的类。如果把关键字type
括号里的数据看做对象的话,也可以把类名当做对象放进此处。
class Person:
pass
class People:
pass
class Human:
pass
print(type(Person)) # <class 'type'>
print(type(People)) # <class 'type'>
print(type(Human)) # <class 'type'>
根据结果<class 'type'>
可以发现,产生类(对象)的类其实是类type
。这里的类type
是Python中的默认元类。另外元类是可以通过一些特殊的方法进行指定的。
创建类的方式
方式一:class关键字
class C1(object):
pass
print(C1) # <class '__main__.C1'>
方式二:type(类名, 父类, 类的名称空间)
print(type('C1', (), {})) # <class '__main__.C1'>
以上两种方式创建类的方式的结果其实是一样的。
元类进阶
定义元类的作用
元类能够创建类,也就意味着我们可以通过编写元类的类体代码对所要创建的类进行定制(添加一些创建类的条件)
元类的使用与指定
class MyClass():
pass
print(type(MyClass)) # <class 'type'>
class A(MyClass):
pass
print(type(A)) # <class 'type'>
继承MyClass以后,类A的元类依然是类type。也就是说,类继承父类只是能够调用父类的方法,而不是由父类创建。而是通过关键字参数metaclass=元类名
指定的
class MyClass():
pass
print(type(MyClass)) # <class 'type'>
class A(metaclass=MyClass):
pass
print(type(A)) # <class '__main__.MyClass'>
元类如何创建定制的类
- 类创建对象的过程中可以在类的
__init__
方法内进行对象的实例化 - 元类创建类(类也是对象)的时候也可以在元类的
__init__
方法内进行定制
class MyClass(type):
def __init__(cls, cls_name, cls_bases, cls_dict):
if cls_name.istitle(): # 判断类名是否首字母大写、其余字母小写
if len(cls_name) < 6: # 限制类名长度
super().__init__(cls_name, cls_bases, cls_dict)
else:
raise Exception('类名长度必须小于6')
else:
raise Exception('类名首字母未大写')
print(type(MyClass)) # <class 'type'>
class Amy(metaclass=MyClass):
pass
print(Amy)
class amy(metaclass=MyClass):
pass # Exception: 类名首字母未大写
class Amy_City(metaclass=MyClass):
pass # Exception: 类名长度必须小于6
print(type(Amy)) # <class '__main__.MyClass'>
__call__
方法
__call__
方法: 在对象加括号调用时,自动执行产生该对象的类里的__call__
方法,并获取__call__
方法的返回值。
__call__
方法执行流程:
1. 产生空对象(其实是调用__new__
方法)
2. __init__
实例化对象
3. 返回对象
class MyClass(type):
def __init__(cls, cls_name, cls_bases, cls_dict):
if cls_name.istitle(): # 判断首字母是否大写,其余小写
if len(cls_name) < 6: # 限制类名长度
super().__init__(cls_name, cls_bases, cls_dict)
else:
raise Exception('类名长度必须小于6')
else:
raise Exception('类名首字母未大写')
def __call__(self, *args, **kwargs):
if args: # 判断位置参数是否有位置参数
raise Exception('参数必须是关键字参数')
else:
super().__call__(*args, **kwargs) # 没有的时候执行元类的__call__方法
return self
class beta_bbb(metaclass=MyClass):
def __init__(self, b):
self.b = b
class A(metaclass=MyClass):
def __init__(self, name):
self.name = name
obj1 = A(name='oliver')
print(obj1.__dict__)
print(obj1) # <class '__main__.A'>
class amy_city(metaclass=MyClass):
def __init__(self, name):
self.name = name
obj1 = amy_city(name='oliver')
print(obj1.__dict__)
class Amycity(metaclass=MyClass):
def __init__(self, name):
self.name = name
obj1 = Amycity(name='oliver')
print(obj1.__dict__)
class Century(metaclass=MyClass):
def __init__(self, c):
self.c = c
__new__
方法
'''
__new__ 产生空对象 名称空间空的
__init__ 实例化对象 添加数据进入名称空间
'''
class MyClass(type):
def __new__(cls, *args, **kwargs):
print('__new__ 执行') # __new__ 执行 产生空对象
return super().__new__(cls, *args, **kwargs)
def __init__(cls, cls_name, cls_bases, cls_dict):
print('__init__ 执行') # __init__ 执行 # 实例化对象
super().__init__(cls_name, cls_bases, cls_dict)
class Class(metaclass=MyClass):
def __init__(self, name):
self.name = name
print('实例化对象的过程中执行')
print(Class)
a = Class('a')
print(a)