元类
MetaClass(元类),元类创建了Python中所有的对象。简单的理解,就是创建类的类,即创建类之后,再由类来创建实例进行应用。使用元类可以在创建类时动态修改类定义。为了使用元类动态修改类定义,程序需要先定义元类。简单理解为:元类就是用来创建类的东西
注意,不要从字面上去理解元类的含义,事实上,MetaClass 中的 Meta 这个词根,起源于希腊语词汇 meta,包含“超越”和“改变”的意思。
在python 中 类同样表示一种对象,这个对象拥有创建对象(创建实例)的能力, 它本质是一个对象,于是乎,可以对它做如下操作
- 1、可以将它赋值给一个变量
2、可以拷贝它
3、可以为它增加属性
4、可以将他作为函数的属性传递
动态创建类
因为类也是对象,所以可以再运行的时候创建他们,就像其他任何对象一样,可以在函数中创建类,使用关键字即可
def create_class(name):
if name == "foo":
class Foo(object): # 当使用class关键字时,Python解释器自动创建这个对象。
pass
return Foo # 返回的是类 不是实例
else:
class Bar():
pass
return Bar
myClass = create_class("foo")
print(myClass) # <class '__main__.create_class.<locals>.Foo'>
my = myClass() # 创建实例对象
print(my) # <__main__.create_class.<locals>.Foo object at 0x0000022B9C5AA390>
type 回顾
查看类型
print(type(1)) # <class 'int'>
print(type("aaa")) # <class 'str'>
print(type(myClass)) # <class 'type'>
print(type(my)) #<class '__main__.create_class.<locals>.Foo'>
# 可以发现 type(myClass) 的类型为 type 继续测试
class aaa(object):
pass
class bbb(object):
pass
print(type(aaa)) # <class 'type'>
print(type(bbb)) # <class 'type'>
# 可以发现 通过 type 查看所有的类的类型 都是 type 类型
type 的另一个作用
- 动态创建类
type可以接受一个类的描述作为参数,返回一个类
格式:type(类名,由父类名称组成的元祖(针对继承的情况 可以为空),包含属性的字典(名称和值))
例:
ccc = type("Ccc",(),{"name":"chase"})
print(ccc) # <class '__main__.Ccc'>
print(ccc().name) # chase
print(type(ccc)) # <class 'type'>
help(ccc) # 使用help 查看ccc类 输出结果如下
"""
Help on class Ccc in module __main__:
class Ccc(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| name = 'chase'
"""
使用创建带由父类的示例
ccc = type("Ccc",(),{"name":"chase"})
ddd = type("Ddd",(ccc,),{}) # type中的第二个参数是父类的引用名称,不是字符串
class Eee(object):
eName = "EEE"
pass
fff = type("Fff",(Eee,),{"name":"FFF"})
print(fff.eName) # EEE
print(fff.name) # FFF
help(fff)
"""
Help on class Fff in module __main__:
class Fff(Eee)
| Method resolution order:
| Fff
| Eee
| builtins.object
|
| Data and other attributes defined here:
|
| name = 'FFF'
|
| ----------------------------------------------------------------------
| Data descriptors inherited from Eee:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes inherited from Eee:
|
| eName = 'EEE'
"""
使用type 创建带有方法的类
def run(self):
print("实例方法")
@staticmethod
def static_run():
print("静态方法")
@classmethod
def class_run(cls):
print("类方法,name为:%s" % cls.name)
Foo = type("Foo",(),{"name":"fooName","run":run,"static_run":static_run,"class_run":class_run})
foo = Foo()
foo.run() # 实例方法
foo.static_run() # 静态方法
Foo.class_run() # 类方法,name为:fooName
help(Foo)
"""
Help on class Foo in module __main__:
class Foo(builtins.object)
| Methods defined here:
|
| run(self)
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| class_run() from builtins.type
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| static_run()
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| name = 'fooName'
"""
type 元类
函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
元类就是创建类这种对象的东西。type就是Python的内建元类,当然了,你也可以创建自己的元类。
__metaclass__属性
当执行如下代码时间
class Foo(Bar):
pass
Python做了如下的操作:
1、Foo中有__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象)
2、如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
3、如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
4、如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
自定义元类
元类的主要目的就是为了当创建类时能够自动地改变类。
网上摘抄的一个例子
假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定__metaclass__。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。
幸运的是,__metaclass__实际上可以被任意调用,它并不需要是一个正式的类。所以,我们这里就先以一个简单的函数作为例子开始。
来源:网络
- python2 中
#-*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):
# class_name 会保存类的名字 Foo
# class_parents 会保存类的父类 object
# class_attr 会以字典的方式保存所有的类属性
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 调用type来创建一个类
return type(class_name, class_parents, new_attr)
class Foo(object):
__metaclass__ = upper_attr # 设置Foo类的元类为upper_attr
bar = 'bip'
print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))
f = Foo()
print(f.BAR)
- python3中
def upper_attr(class_name, class_parents, class_attr):
#遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name,value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
#调用type来创建一个类
return type(class_name, class_parents, new_attr)
class Foo(object, metaclass=upper_attr):
bar = 'bip'
print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True
f = Foo()
print(f.BAR) # bip
- 用一个真正的class来当做元类。
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
def __new__(cls, class_name, class_parents, class_attr):
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 方法1:通过'type'来做类对象的创建
return type(class_name, class_parents, new_attr)
# 方法2:复用type.__new__方法
# 这就是基本的OOP编程,没什么魔法
# return type.__new__(cls, class_name, class_parents, new_attr)
# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
bar = 'bip'
# python2的用法
# class Foo(object):
# __metaclass__ = UpperAttrMetaClass
# bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'