Python核心编程笔记 - 第13章 面向对象编程(二)

来源:互联网 发布:易云幕墙计算软件 编辑:程序博客网 时间:2024/06/05 01:36

描述符

严格来说,描述符实际上可以是任何新式类,但这个类必须至少要实现以下3个特殊方法中的一个: __get__(), __set__(), __delete__().

同时实现__get__()和__set__()的类被称作数据描述符;
并不是所有的描述符都实现了__set__()方法,因此算非数据描述符。

优先级别:

  • 类属性
  • 数据描述符
  • 实例属性
  • 非数据描述符
  • 默认为__getattr__()

示例代码:

class SampleProxy(object):    def __get__(self, obj, typ=None):        print "get into __get__() method"        return 100  ## always return 100    def __set__(self, obj, val):        print "in __set__() method"        self.obj = 200  ## always set 200 to it, not 'val'class C1(object):    ff = SampleProxy()c1 = C1()c1.ff = 'hello'  # in __set__() methodprint c1.ff      # get into __get__() method \n 100

metaclass (元类)

metaclass是用于创建类的类,它用来定义一个类该被如何创建。

metaclass一般用于创建类。在执行类的定义时,解释器必须要知道这个类的正确的metaclass。解释器会先去寻找类属性__metaclass__,若此属性存在,就以此属性作为元类;若没有,则向上查找父类中的__metaclass__。所以新式类若没有任何父类,就会从对象或类型中继承。
若仍然没有发现__metaclass__属性,解释器会检查名字为__metaclass__的全局变量;若有,就使用它。否则,该类就是一个传统类。传统类使用types.ClassType作为元类。
若你定义了一个传统类,并且设置它的__metaclass__=type,这就是在将这个传统类升级为一个新式类。

metaclass通常传递3个参数到构造器:name、bases(从基类继承数据的元组) 和 attrd(类的属性字典)

示例程序:

from warnings import warnclass ReqStrSugRepr(type):    def __init__(cls, name, bases, attrd):        super(ReqStrSugRepr, cls).__init__(name, bases, attrd)        if '__str__' not in attrd:            raise TypeError("Class requires overriding of __str__()")        if '__repr__' not in attrd:            warn('Class suggests overriding of __repr__()\n', stacklevel=3)print '*** Defined ReqStrSugRepr (meta)class\n'class Foo(object):    __metaclass__ = ReqStrSugRepr    def __str__(self):        return 'Instance of class: ', self.__class__.__name__    def __repr__(self):        return self.__class__.__name__print '***Defined Foo class \n'  # will be Okayclass Bar(object):    __metaclass__ = ReqStrSugRepr    def __str__(self):        return 'Instance of class: ', self.__class__.__name__print '***Defined Bar class \n'  # will have a warnclass FooBar(object):    __metaclass__ = ReqStrSugRepr  # will get TypeErrorprint '*** Defined FooBar class\n'
1 0