python类:描述器Descriptors和元类MetaClasses

http://blog.csdn.net/pipisorry/article/details/50444769

描述器(Descriptors)

描述器决定了对象属性是如何被访问的。描述器的作用是定制当你想引用一个属性时所发生的操作。

构建描述器的方法是至少定义以下三个方法中的一个。需要注意,下文中的instance是包含被访问属性的对象实例,而owner则是被描述器修辞的类。

  • __get__(self, instance, owner) – 这个方法是当属性被通过(value = obj.attr)的方式获取时调用,这个方法的返回值将被赋给请求此属性值的代码部分。
  • __set__(self, instance, value) – 这个方法是当希望设置属性的值(obj.attr = ‘value’)时被调用,该方法不会返回任何值。
  • __delete__(self, instance) – 当从一个对象中删除一个属性时(del obj.attr),调用此方法。

译者注:对于instance和owner的理解,考虑以下代码:

classCelsius(object):

def__init__(self, value=0.0):

self.value=float(value)

def__get__(self, instance, owner):

returnself.value

def__set__(self, instance, value):

self.value=float(value)

classTemperature(object):

celsius=Celsius()

temp=Temperature()

temp.celsius#calls Celsius.__get__

上例中,instance指的是temp,而owner则是Temperature。

LazyLoading Properties例子:

importweakref

classlazyattribute(object):

def__init__(self, f):

self.data=weakref.WeakKeyDictionary()

self.f=f

def__get__(self, obj, cls):

ifobjnotinself.data:

self.data[obj]=self.f(obj)

returnself.data[obj]

classFoo(object):

@lazyattribute

defbar(self):

print"Being lazy"

return42

f=Foo()

printf.bar

# Being lazy

# 42

printf.bar

# 42

描述器很好的总结了Python中的绑定方法(bound method)这个概念,绑定方法是经典类(classic classes)的实现核心。在经典类中,当在一个对象实例的字典中没有找到某个属性时,会继续到类的字典中查找,然后再到基类的字典中,就这么一直递归的查找下去。如果在类字典中找到这个属性,解释器会检查找到的对象是不是一个Python函数对象。如果是,则返回的并不是这个对象本身,而是返回一个柯里化(currying function)的包装器对象。当调用这个包装器时,它会首先在参数列表之前插入实例,然后再调用原函数。

译者注:
1. 柯里化 – http://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96
2. function,method,bound method及unbound method的区别。首先,函数(function)是由def或lambda创建的。当一个函数在class语句块中定义或是由type来创建时,它会转成一个非绑定方法(unbound method),而当通过类实例(instance)来访问此方法的时候,它将转成绑定方法(bound method),绑定方法会自动将实例作为第一个参数传入方法。综上所述,方法是出现在类中的函数,绑定方法是一个绑定了具体实例的方法,反之则是非绑定方法。

综上,描述器被赋值给类,而这些特殊的方法就在属性被访问的时候根据具体的访问类型自动地调用。

[Descriptor Protocol]

皮皮blog

元类(MetaClasses)

元类提供了一个改变Python类行为的有效方式。

元类的定义是“一个类的类”。任何实例是它自己的类都是元类。

classdemo(object):

pass

obj=demo()

print"Class of obj is {0}".format(obj.__class__)

print"Class of obj is {0}".format(demo.__class__)

# Class of obj is <class ‘__main__.demo‘>

# Class of obj is <type ‘type‘>

在上例中,我们定义了一个类demo,并且生成了一个该类的对象obj。首先,可以看到obj的__class__是demo。有意思的来了,那么demo的class又是什么呢?可以看到demo的__class__是type。

所以说type是python类的类,换句话说,上例中的obj是一个demo的对象,而demo本身又是type的一个对象。

所以说type就是一个元类,而且是python中最常见的元类,因为它使python中所有类的默认元类。

因为元类是类的类,所以它被用来创建类(正如类是被用来创建对象的一样)。但是,难道我们不是通过一个标准的类定义来创建类的么?的确是这样,但是python内部的运作机制如下:

    • 当看见一个类定义,python会收集所有属性到一个字典中。
    • 当类定义结束,python将决定类的元类,我们就称它为Meta吧。
    • 最后,python执行Meta(name, bases, dct),其中:

a. Meta是元类,所以这个调用是实例化它。
b. name是新建类的类名。
c. bases是新建类的基类元组
d. dct将属性名映射到对象,列出所有的类属性。

那么如何确定一个类(A)的元类呢?简单来说,如果一个类(A)自身或其基类(Base_A)之一有__metaclass__属性存在,则这个类(A/Base_A)就是类(A)的元类。否则type就将是类(A)的元类。[Python高级编程技巧]

皮皮blog

__slots__

默认情况下,Python 用一个字典来保存一个对象的实例属性。这使得我们可以在运行的时候动态的给类的实例添加新的属性:
test = Test()
test.new_key = ‘new_value‘
然而这个字典浪费了多余的空间 — 很多时候我们不会创建那么多的属性。因此通过__slots__可以告诉 Python 不要使用字典而是固定集合来分配空间。
class Test(object):
    # 用列表罗列所有的属性
    __slots__ = [‘name‘, ‘value‘]
    def __init__(self, name=‘test‘, value=‘0‘):
        self.name = name
        self.value = value

test = Test()
# 此时再增加新的属性则会报错
test.new_key = ‘new_value‘
# AttributeError: ‘Test‘ object has no attribute ‘new_key‘

__call__

通过定义类中的__call__方法,可以使该类的实例能够像普通函数一样调用。
class AddNumber(object):
    def __init__(self):
        self.num = 0

def __call__(self, num=1):
        self.num += num

add_number = AddNumber()
print(add_number.num) # 0
add_number() # 像方法一样的调用
print(add_number.num) # 1
add_number(3)
print(add_number.num) # 4
通过这种方式实现的好处是,可以通过类的属性来保存状态,而不必创建一个闭包或者全局变量。

from:http://blog.csdn.net/pipisorry/article/details/50444769

ref:Python “黑魔法” 之 Meta Classes

[Special method names?]

时间: 2024-08-10 15:08:10

python类:描述器Descriptors和元类MetaClasses的相关文章

Python 黑魔法 --- 描述器(descriptor)

Python 黑魔法---描述器(descriptor) Python黑魔法,前面已经介绍了两个魔法,装饰器和迭代器,通常还有个生成器.生成器固然也是一个很优雅的魔法.生成器更像是函数的行为.而连接类行为和函数行为的时候,还有一个描述器魔法,也称之为描述符. 我们不止一次说过,Python的优雅,很大程度在于如何设计成优雅的API.黑魔法则是一大利器.或者说Python的优雅很大程度上是建立在这些魔法巧技基础上. 何谓描述器 当定义迭代器的时候,描述是实现迭代协议的对象,即实现__iter__方

Python之描述器

1.描述器的表现 用到三个魔术方法,__get__(), __set__(), __delete__() 方法签名如下 object.__get__(self,instance,owner) object.__set__(self,instance,value) object.__delete(self,instance) self指代当前实例,调用者 instance是owner的实例 owner是属性的所输的类 #描述器A调用并赋值给了类B的属性,当调用类B或者实例b时,去类A执行__get

函数装饰器和类装饰器实现单例类

单例类,指的是这个类只能创建一个实例,创建完成后,其他类实例都无法再创建.今天我们来看一下,使用函数装饰器和类装饰器怎么实现这种特殊一点的类. 函数装饰器实现 装饰器算是类里面比较难的内容之一,但是实际上它的思想并不复杂.简单点说,就是在你原来内容的基础上,在外面给你加点东西,实现类似装饰的效果.但是它是怎么实现的呢?一般来说,都是通过拦截函数调用来实现的,比如:用装饰器装饰函数的时候,它拦截函数调用,装饰类的时候,它拦截类实例的创建调用,即拦截类初始化__init__函数.知道这个原理以后,我

描述器 descriptors

描述器的表现 用到3个魔术方法:__get__(),__set__(),__delete__(),用到这三个方法其一的类就是描述器. 方法签名如下: object.__get__(self,instance,owner),self是实例本身,instance是owner的实例. object.__set__(self,instance,value) object.__delete__(self,instance) self指代当前实例,调用者. instance是owner的实例,owner是属

python Class:面向对象高级编程 元类:type

type的用法: 1.普通的type用法:检查类型 class my(object):     def hello(self, name='world'):         print('Hello, %s.' % name) h = my()        print(type(my))         print(type(h)) 运行结果: <type 'type'> <class '__main__.my'> my是class, 所以它的类型是type, h是class的实

Python之路(十二):描述符,类装饰器,元类

python基础之面向对象(描述符.类装饰器及元类) 描述符 描述符(__get__,__set__,__delete__)   # 这里着重描述了python的底层实现原理 1. 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议. __get__():调用一个属性时,触发 __set__():为一个属性赋值时,触发 __delete__():采用del删除属性时,触发 1 class

Python基础- 类和对象(使用、继承、派生、组合、接口、多态、封装、property、staticmethod、classmethod、反射、slots、上下文管理协议、元类)

标签: python对象 2017-07-01 16:28 79人阅读 评论(0) 收藏 举报  分类: python(11)  版权声明:本文为广大朋友交流学习,如有纰漏望不吝赐教,若存在版权侵犯请及时与我联系 目录(?)[+] 一.初识类和对象 在python3中类型就是类 先定义类在产生相对应的对象,也就是现有了概念再有了实体 class Garen: camp = 'Demacia' def attack(self): print('attack') 1.如何使用类 在python3:

python面向对象高级:反射、魔法方法、元类

自省/反射什么是反射?自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的.并且在python里,反射可以使得程序运行时对象拥有增删改查它本身属性或行为的一种能力如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作.还有那些特殊属性,像__dict__,__name__及__doc__反射的使用场景? 即插即用,即可以事先定义好接口,接口只有在被完成后才会真正执行 比如:如果和别人共同合作开发项目,但是需要用到对方的类的方法,对方还没完成 f1=FtpC

理解 Python 中的元类

本文编程环境:Jupyter NoteBook python3 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在 Python 中这一点仍然成立: class ObjectCreator(object): pass my_object = ObjectCreator() my_object <__main__.ObjectCreator at 0x233e50a8ba8> 但是,Python 中的类还远不止如此.类同样也是一种对象.只要你使用关键字 class,P