python元类
metaclass被称作是Python面向对象里最难理解,也是最难使用的魔术代码。
http://www.cnblogs.com/piperck/p/5840443.html
http://blog.jobbole.com/21351/
http://zhiyupan.me/2017/04/09/Python2-7%E8%BF%9B%E9%98%B6-%E4%B9%8B-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1-3/#more
type函数
type函数的强大之处在于既可以返回一个对象的类型,又可以创建出新的类型而无需使用class XZZZ(object)
的定义。
type(object) -> object's type type(name,bases,dict) ->a new type
def func(self,name='world'):
print 'hello ,{}!'.format(name)
def func(self,name='world'):
print ('hello ,{}!'.format(name))
hello = type('hello',(object,),dict(hello=func))
h = hello()
h.hello()
type函数的三个参数
- 要创建的class的名称
- 继承的父类的集合,因为python中支持多继承,单继承使用tuple单元素的写法
- class方法名称和函数绑定 这里吧func与成员方法hello绑定
通过type函数创建的类与直接写class是完全一样的,因为python解释器在class关键字时也是调用type函数完成定义。
metaclass
除了使用type()函数动态创建类以外,要控制类的创建行为,还可以使用metaclass。
先定义metaclass,创建类,创建示例
类就时metaclass创建出来的实例
。类似于C++中模板类。
class ListMetaClass(type): def new(cls,name,bases,attrs): attrs['add'] = lambda self,value: self.append(value) return type.new(cls,name,bases,attrs)
class MyList(list): metaclass = listMetaClass #指示使用ListMetaClass来定制类
#魔法 会指示python解释器 在创建MyList时要通过ListMetaClass.new()来创建
可以通过修改类的定义 比如加上新的方法 然后返回修改后的定义
new()方法接收的参数依次是:
- 准备创建的类的对象
- 类的名字
- 类继承的父类集合
- 类的方法集合
使用形式如type(类名,父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值) )
ORM
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters
元类的主要用途是创建API。一个典型的例子是Django ORM。
ORM 全称 “Object Relational Mapping”, 即对象关系映射, 就是把数据库关系的一行映射为一个对象, 也就是一个类对应一个表, 这样写代码更简单, 不用直接操作 SQL 语言.
class Person(models.Model):
name = models.CharField(max_length = 30)
age = models.IntegerField()
guy = Person(name = 'bob',age = '35')
print guy.age
这并不会返回一个IntegerField对象,而是返回一个int甚至可以从数据库中取出数据。
如果models.Model定义了__metaclass__
能够将Person类转变为一个复杂的hook。
重新认识类
首先,你知道了类其实是能够创建出类实例的对象。好吧,事实上,类本身也是实例,当然,它们是元类的实例。
Python
class Foo(object): pass id(Foo) 142630324 1 2 3 class Foo(object): pass id(Foo) 142630324 Python中的一切都是对象,它们要么是类的实例,要么是元类的实例,除了type。type实际上是它自己的元类,在纯Python环境中这可不是你能够做到的,这是通过在实现层面耍一些小手段做到的。其次,元类是很复杂的。对于非常简单的类,你可能不希望通过使用元类来对类做修改。你可以通过其他两种技术来修改类:
1) Monkey patching 2) class decorators
当你需要动态修改类时,99%的时间里你最好使用上面这两种技术。当然了,其实在99%的时间里你根本就不需要动态修改类