我们都知道,当创建一个类后,可以通过它创建对象
1、对象可以在程序中动态的进行创建
2、对象可以通过__class__获取该对象所属的类
3、对象可以动态的添加属性
4、可以使用type查看对象的类型
通过实验,发现类同样可以实现上述四步,也就是说类其实也是由类创建出来的。这个用来创建类的类就叫元类
通过__class__属性得到类的类型都是byte,所以byte就是元类
一.type用法
1、查看当前对象的类型
2、创建类
语法:type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
原理:type()返回一个类对象(如下边的B,Person),类对象可以再生成对象(b,a,person)
class A(object):# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<正常创建类 def __init__(self): print('类A') # 语法:type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值)) B = type('B', (), {'name': '鬼子'})# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<type创建类 b = B() a = A() print(b.name) print(type(A)) print(type(B))
结果:
类A
鬼子
<class 'type'>
<class 'type'>
那么怎么让元类包含方法呢?lambda来啦!!!!!!
Person = type('Person', (), {'name': '鬼子', 'say': lambda a: print(a.name)}) person = Person() person.say()
结果:
鬼子
让我们再深入认识类以及元类
当我们创建一个类如:
class XX( ):
pass
到底执行了什么?
在该类定义的时候,它还没有在内存中生成,知道它被调用。Python做了如下的操作:
1)Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象)。
2)如果Python没有找到__metaclass__,它会继续在父类中寻找__metaclass__属性,并尝试做和前面同样的操作。
3)如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
4)如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
现在的问题就是,你可以在__metaclass__中放置些什么代码呢?
答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东西都可以。说白了每个类在定义时就已经通过type或者子类化type的东西创建了类对象。
二.自定义元类
元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过设定__metaclass__。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。
__metaclass__实际上可以被任意调用,它并不需要是一个正式的类。所以,我们这里就先以一个简单的函数作为例子开始。
# 自定义元类,使得由该元类创建的类所有参数都是大写,即使定义小写,也给变成大写<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # 元类会自动将你通常传给‘type’的参数作为自己的参数传入 def upper_attr(future_class_name, future_class_parents, future_class_attr): '''返回一个类对象,将属性都转为大写形式''' # 选择所有不以'__'开头的属性 attr = {} for name, value in future_class_attr.items(): if not name.startswith('__'): # 将它们转为大写形式 attr[name.upper()] = value # 通过'type'来做类对象的创建 return type(future_class_name, future_class_parents, attr) # 返回一个类 class Foo(object, metaclass=upper_attr): # __metaclass__ = upper_attr def __init__(self): pass bbb = 'a' __bbb = 'a' foo = Foo() print(hasattr(Foo, 'bbb')) # 输出: False print(hasattr(Foo, 'BBB')) # 输出:True print(hasattr(Foo, '__bbb')) # 输出: False print(hasattr(Foo, '__BBB')) # 输出:False结果:
False True False False