python 面向对象十二 元类

2018-06-18 00:00:15来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

一、类也是对象

只要使用关键字class,Python解释器在执行的时候就会创建一个对象。下面的代码段:

1 class ObjectCreator(object):
2     pass

将在内存中创建一个对象,名字就是ObjectCreator。这个对象(类)自身拥有创建对象(类实例)的能力。

它的本质仍然是一个对象,于是乎你可以对它做如下的操作:

1)   你可以将它赋值给一个变量

2)   你可以拷贝它

3)   你可以为它增加属性

4)   你可以将它作为函数参数进行传递

 1 >>> class ObjectCreator(object):
 2 ...     pass
 3 ... 
 4 >>> print(ObjectCreator)    # 可以打印,因为也是个对象
 5 <class '__console__.ObjectCreator'>
 6 >>> print(type(ObjectCreator))
 7 <class 'type'>
 8 >>> def echo(o):
 9 ...     print(o)
10 ... 
11 >>> echo(ObjectCreator)     # 当做参数
12 <class '__console__.ObjectCreator'>
13 >>> hasattr(ObjectCreator, 'new_attribute') 
14 False
15 >>> ObjectCreator.new_attribute = 'foo'    # 增加属性
16 >>> hasattr(ObjectCreator, 'new_attribute')
17 True
18 >>> ObjectCreator.new_attribute
19 'foo'
20 >>> ObjectCreatorMirror = ObjectCreator    # 赋值给变量
21 >>> ObjectCreatorMirror()
22 <__console__.ObjectCreator object at 0x0000000002CB38D0>

二、使用type动态创建类

type可以接受一个类的描述作为参数,然后返回一个类。type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

1 >>> MyShinyClass = type('MyShinyClass', (), {})
2 >>> MyShinyClass
3 <class '__console__.MyShinyClass'>
4 >>> MyShinyClass()
5 <__console__.MyShinyClass object at 0x0000000002CB3978>
1 >>> MyShiny = type('MyShinyClass', (), {})
2 >>> MyShiny
3 <class '__console__.MyShinyClass'>
4 >>> MyShinyClass
5 <class '__console__.MyShinyClass'>
>>> Foo = type('Foo', (), {'bar': True})
>>> Foo.bar
True
>>> f = Foo()
>>> f.bar
True
1 >>> FooChild=type('FooChild', (Foo,),{})
2 >>> FooChild
3 <class '__console__.FooChild'>
4 >>> FooChild.bar
5 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可以动态创建类,是因为函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。

四、metaclass 

在用 class 语句自定义类时,默认 metaclass 是 type,我们也可以指定 metaclass 来创建类。 

五、自定义元类

元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。

 1 class UpperAttrMetaclass(type):
 2 
 3     def __new__(cls, name, bases, dct):
 4         print(name, bases, dct)
 5         attrs = ((name, value)
 6                  for name, value in dct.items() if not name.startswith('__'))
 7         uppercase_attr = dict((name.upper(), value) for name, value in attrs)
 8         return super(UpperAttrMetaclass,
 9                      cls).__new__(cls, name, bases, uppercase_attr)
10 
11 
12 class Foo(object, metaclass=UpperAttrMetaclass):
13     bar = 'bip'
14 
15 
16 print(hasattr(Foo, 'bar'))
17 # 输出: False
18 print(hasattr(Foo, 'BAR'))
19 # 输出:True
20 
21 f = Foo()
22 print(f.BAR)
23 # 输出:'bip'
 1 sensitive_words_list = ['asshole', 'fuck', 'shit']
 2 
 3 
 4 def detect_sensitive_words(st):
 5     '''检测敏感词汇'''
 6     words_detected = list(filter(
 7         lambda word: word in st.lower(), sensitive_words_list))
 8     if words_detected:
 9         raise NameError('Sensitive words {0} detected in the string "{1}".'
10                         .format(', '.join(map(lambda s: '"%s"' % s,
11                                               words_detected)), st)
12                         )
13 
14 
15 class CleanerMeta(type):
16 
17     def __new__(cls, class_name, bases, attrs):
18         detect_sensitive_words(class_name)  # 检查类名
19 
20         map(detect_sensitive_words, attrs.keys())  # 检查属性名
21 
22         print("Well done! You are a polite coder!")  # 如无异常,输出祝贺消息
23 
24         return super(CleanerMeta, cls).__new__(cls, class_name, bases, attrs)
25         # 重要!这行一定不能漏!!这回调用内建的类构造器来构造类,否则定义好的类将会变成 None
26 
27 
28 class APIBase(object, metaclass=CleanerMeta):
29 
30     pass
31 
32 
33 a = APIBase()
34 print(a.__class__)
35 print(a.__class__.__class__)
36 print(a.__class__.__class__.__class__)

输出:

Well done! You are a polite coder!
<class '__main__.APIBase'>
<class '__main__.CleanerMeta'>
<class 'type'>

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:python 面向对象十三 枚举类

下一篇:用 Django2.0 做 简单的BBS(前端用 Bootstrap)