zoukankan      html  css  js  c++  java
  • python 面向对象十二 元类

    一、类也是对象

    只要使用关键字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'>
  • 相关阅读:
    Visual Studio调试托管代码
    Visual Studio调试本机代码
    Visual Studion调试器指南---编辑并继续
    Visual Studio 调试器指南---调试器中的表达式
    Visual Studio 调试器指南---查看调试器中的数据
    Visual Studio调试器指南---断点和跟踪点
    Visual Studio调试器指南---转储文件
    Visual Studio调试器指南---自动启动调试器
    Visual Studio调试器指南---实时调试
    Visual Studio调试器指南---使用线程和进程
  • 原文地址:https://www.cnblogs.com/gundan/p/8081809.html
Copyright © 2011-2022 走看看