1.python 中类型
(1) type 判断类型
python
是一种动态类型语言,换句话说每个变量可以在程序里任何地方改变它的类型。想要获取变量的类型信息,可以使用type
:
>>> a = 2
>>> type(a)
int
>>> a = '1'
>>> type(a)
str
>>> type(str)
type
>>> type(type)
type
>>> class Test1 (object):
pass
>>> class Test2 (Test1):
pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True
- 每个变量都有自己的类型
- 变量的类型是可以随时改变的
- type 只会返回对象的直接 type,就是定义该对象的类
- 类的 type 还是 type,这说明 type 定义了 python 中所有类的某些基本属性
(2) type 创建类型
Help on class type in module __builtin__:
class type(object)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
类的创建
class Foo(object):
def __init__(self):
self.a = 1
def magic(self):
return self.a
#第二种创建方式
def __init__(self):
self.a = 1
def magic(self):
return self.a
Foo = type('Foo', (object,), {"__doc__": "A class that does nothing.", "__init__": __init__, "magic": magic})
foo = Foo()
print foo
print foo.a # 1
print foo.magic # <bound method Foo.magic of <__main__.Foo object at 0x100fa5d50>>
print foo.magic() # 1
type 的三个参数分别是:
- name: 要生产的类名
- bases:包含所有基类的 tuple
- dict:类的所有属性,是键值对的字典
现在再回顾一下 “python 中一切皆对象”这句话,可能会更容易理解。
2.metaclass 就是类的类
我们在前面看到怎么使用 type 来动态创建类,其实在 python 内部也进行着同样的步骤。这就是 metaclass
的概念!
想弄明白 metaclass
,我们要搞清楚 class
。因为类似于 class
定义了 instance
的行为, metaclass
则定义了 class 的行为。可以说, class
是 metaclass
的 instance
。
想弄明白 metaclass
,我们要搞清楚 class
。因为类似于 class 定义了 instance
的行为, metaclass
则定义了 class
的行为。可以说, class
是 metaclass
的 instance
。
类的创建过程
class MyClass(object):
pass
不会立即去创建这个类,而是把这段代码当做正常的code block
来执行,结果就是生成一个命名空间(namespace),就是包含了要生成类(class-to-be)所有属性的字典,然后才会调用 __new__
函数,把类名、类的父类、类的属性传递过去,生成这个类。
3.自定义metaclass
继承 type 这个类,覆盖已有的内置函数,就可以创建自己的 metaclsss
。
下面的内容都会基于一个这样的并metaclass
:它为要创建的类自动添加一个属性 __cizixs
class MyMetaclass(type):
def __init__(cls, name, bases, attrs):
cls.__cizixs = "Don't panic"
print("In MyMetaclass for {}".format(name))
super(MyMetaClass, cls).__init__(name, bases, attrs)
其实还可以覆写 __new__
函数来达到相同的目的:
class MyMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['__cizixs'] = "Don't panic"
print("In MyMetaclass for {}".format(name))
return super(MyMetaclss, cls).__new__(cls, name, bases, attrs)
class Foo(object):
__metaclass__ = MyMetaclass
pass
# In MyMetaclass for Foo
foo = Foo()
print foo.__cizixs # Don't panic
4.__call__
__call__
is called when the already-created class is "called" to instantiate a new object
class MyMeta(type):
def __call__(cls, *args, **kwds):
print '__call__ of ', str(cls)
print '__call__ *args=', str(args)
return type.__call__(cls, *args, **kwds)
class MyKlass(object):
__metaclass__ = MyMeta
def __init__(self, a, b):
print 'MyKlass object with a=%s, b=%s' % (a, b)
print 'gonna create foo now...'
foo = MyKlass(1, 2)
打印
gonna create foo now...
__call__ of <class '__main__.MyKlass'>
__call__ *args= (1, 2)
MyKlass object with a=1, b=2
5.总结
- 系统默认的type 作为
__metaclass__
,我们可以覆盖这个值。 - 我们可以覆盖
def __new__(cls, name, bases, attrs):
和def __init__(cls, name, bases, attrs):
自定义行为,如单例模式的控制
6.demo
(1)string.Template
class Template:
"""A string class for supporting $-substitutions."""
__metaclass__ = _TemplateMetaclass
delimiter = '$'
idpattern = r'[_a-z][_a-z0-9]*'
def __init__(self, template):
self.template = template
class _TemplateMetaclass(type):
pattern = r"""
%(delim)s(?:
(?P<escaped>%(delim)s) | # Escape sequence of two delimiters
(?P<named>%(id)s) | # delimiter and a Python identifier
{(?P<braced>%(id)s)} | # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
"""
def __init__(cls, name, bases, dct):
super(_TemplateMetaclass, cls).__init__(name, bases, dct)
if 'pattern' in dct:
pattern = cls.pattern
else:
pattern = _TemplateMetaclass.pattern % {
'delim' : _re.escape(cls.delimiter),
'id' : cls.idpattern,
}
cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
使用
>>> from string import Template
>>> Template("$name is $value").substitute(name='me', value='2')
'me is 2'
With a metaclass
, the pattern class attribute is getting created just once when the module is being loaded and the class Template (or its subclass) definition is being executed. This saves time when Template objects are created, and makes sense because at class creation time we have all the information we need to compile the regex - so why delay this operation?
【1】http://eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example