python-元类

类也是对象,可以的操作:

  • 把它赋值给变量
  • 拷贝它
  • 给它增加属性
  • 将它作为函数参数传递
>>> print ObjectCreator     # 你可以打印一个类,因为它其实也是一个对象
<class '__main__.ObjectCreator'>
>>> def echo(o):
…       print o
…
>>> echo(ObjectCreator)                 # 你可以将类做为参数传给函数
<class '__main__.ObjectCreator'>
>>> print hasattr(ObjectCreator, 'new_attribute')
Fasle
>>> ObjectCreator.new_attribute = 'foo' #  你可以为类增加属性
>>> print hasattr(ObjectCreator, 'new_attribute')
True
>>> print ObjectCreator.new_attribute
foo
>>> ObjectCreatorMirror = ObjectCreator # 你可以将类赋值给一个变量
>>> print ObjectCreatorMirror()
<__main__.ObjectCreator object at 0x8997b4c>

动态地创建类

可以在函数中创建类
用type

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
## 用法
MyShinyClass = type('MyShinyClass', (), {})  # 返回一个类对象
Foo = type('Foo', (), {'bar':True})

为类增加属性和方法

>>> def echo_bar(self):
…       print self.bar
…
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True

元类

用来创建类的东西,就是类的类
type就是创建类对象的类
__class__属性,表示对象对应的类
class.__class__能找到它的类的类

__metaclass__属性

class Foo(object):
	__metaclass__ = something…
[…]

过程

Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。

自定义元类

# 元类会自动将你通常传给‘type’的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''返回一个类对象,将属性都转为大写形式'''
    #  选择所有不以'__'开头的属性
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))

    # 将它们转为大写形式
    uppercase_attr = dict((name.upper(), value) for name, value in attrs)
 
    # 通过'type'来做类对象的创建
    return type(future_class_name, future_class_parents, uppercase_attr)
 
__metaclass__ = upper_attr  #  这会作用到这个模块中的所有类
 
class Foo(object):
    # 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中
    bar = 'bip'

测试

print hasattr(Foo, 'bar')
# 输出: False
print hasattr(Foo, 'BAR')
# 输出:True

f = Foo()
print f.BAR
# 输出:'bip'

使用super

class UpperAttrMetaclass(type):
    def __new__(cls, name, bases, dct):
        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)

对于元类本身,可以做的事情

  • 拦截类的创建
  • 修改类
  • 返回修改后的类

为何使用元类

元类的主要用途是创建API,比如:Django ORM

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

guy  = Person(name='bob', age='35')
print guy.age

如果这样,并不会返回IntegerField对象,而是返回int,甚至从数据库中取出数据

最后

尽量不要使用元类,如果需要修改

  • Monkey patching
  • class decorators

参考:http://blog.jobbole.com/21351/

posted @ 2017-04-06 11:19  zhangshihai1232  阅读(118)  评论(0)    收藏  举报