本篇笔记学习自:Improve Your Python: Metaclasses and Dynamic Classes With Type
- type()的使用
>>> type(1)
<class 'int'>
>>> type('foo')
<class 'str'>
>>> type(3.0)
<class 'float'>
>>> type(float)
<class 'type'>
- type的类型?
上面的 type(float) 为什么是<class 'type'>呢?我们再来看一个例子:
>>> class Foo(object):
... pass
...
>>> type(Foo)
<class 'type'>
还有这个:
>>> type(type)
<class 'type'>
type是所有类型的类型,包括它自己。type是一个元类,或者是一个创建所有类的东西。
- 创建自己的元类
Just like regular classes, metaclasses can be user-defined. To use it, you set a class's metaclass attribute to the metaclass you built. A metaclass can be any callable, as long as it returns a type. Usually, you'll assign a class's metaclass to a function that, at some point, uses a variant of type we've not yet discussed: the three parameter variety used to create classes.
就像普通的类,元类也可以是用户自定义的。使用自定义元类时,你需要设置一个类的metaclass属性为你创建的那个元类。元类可以是任何可调用的函数,只要它返回一种类型。
当我们写下下面的代码就是创建类的过程,首先解释器会检查是否有metaclass这个属性,没有就调用type来创建类(类也是对象)。
class Foo(Bar):
pass
现在的问题就是,你可以在metaclass中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东东都可以。
- type的缺点
当我们调用type并且传入三个参数的时候——type(name, bases, dict)创建一种新的类型。
以下的两份代码作用是相同的,运行后,Foo都指向了一个继承自object的类:
class Foo(object):
pass
Foo = type('Foo', (), {})
添加方法:
def always_false(self):
return False
Foo.always_false = always_false
或者可以这样子做:
Foo = type('Foo', (), {'always_false': always_false})
类的继承:
FooBar = type('FooBar', (Foo), {})
- 这有什么鬼用?
虽然不经常用到,但是在一些场合,用type来创建类比较合适,比如在一些需要动态创建类的场合,只有程序允许起来,我们才有足够的信息知道要怎么去创建类,这些场合用type来动态创建类比较合适。
元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定metaclass。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。
- 自定义元类的例子——将类的属性都改为大写
元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的
类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通
过在模块级别设定metaclass。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有
的属性都改成大写形式就万事大吉了。
首先我们需要一个元类:
# 元类会自动将你通常传给‘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
__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'
拓展阅读:
1.stackoverflow上面的问答
2.上面链接回答的翻译
类也是对象,创建类的就是元类。