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]

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

  1. python面向对象(六)之元类

    元类 1. 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: In [13]: class ObjectCreator(object): . ...

  2. python中对象、类型和元类之间的关系

    在python中对象.类型和元类构成了一个微妙的世界. 他们有在这个世界里和平共处,相辅相成.它们遵循着几条亘古不变的定律: 1.python中无处不对象 2.所有对象都有三种特性:id.类型.值 3 ...

  3. python面向对象反射-框架原理-动态导入-元类-自定义类-单例模式-项目的生命周期-05

    反射 reflect 反射(reflect)其实是反省,自省的意思 反省:指的是一个对象应该具备可以检测.修改.增加自身属性的能力 反射:通过字符串获取对象或者类的属性,进行操作 设计框架时需要通过反 ...

  4. Python中对象、类型、元类之间的关系

    Python里的对象.类型和元类的关系很微妙也很有意思. 1989年圣诞节期间,上帝很无聊,于是创造了一个世界. 对象 在这个世界的运转有几条定律. 1.一切都是对象 对象(object)是这个世界的 ...

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

    Python 黑魔法---描述器(descriptor) Python黑魔法,前面已经介绍了两个魔法,装饰器和迭代器,通常还有个生成器.生成器固然也是一个很优雅的魔法.生成器更像是函数的行为.而连接类 ...

  6. Python之描述器

    1.描述器的表现 用到三个魔术方法,__get__(), __set__(), __delete__() 方法签名如下 object.__get__(self,instance,owner) obje ...

  7. 《Effective Python》笔记——第4章 元类及属性

    一.用属性取代get和set方法 常规的get和set方法如下: class OldResistor(): def __init__(self, ohms): self.__ohms = ohms d ...

  8. Python语言特性之2:元类

    问题:Python中的元类(metaclasses)是什么?一般使用它干什么? 原地址:http://stackoverflow.com/questions/100003/what-is-a-meta ...

  9. Java类载入器(二)——自己定义类载入器

      用户定制自己的ClassLoader能够实现以下的一些应用: 自己定义路径下查找自己定义的class类文件,或许我们须要的class文件并不总是在已经设置好的Classpath以下,那么我们必须想 ...

随机推荐

  1. Java 实现32位MD5加密

    MD5介绍[链接] Java代码实现 public class Md5Util { private String Md5Util(String s) { try { MessageDigest md ...

  2. java.sql.SQLException: **** [SQLServer]对象名 "XXXX"无效

    原因:进到数据库里面,但是没有选择数据库. 方法:检查数据源配置,这玩意容易看出.难得是多数据库操作时,切换数据源!

  3. Mysql bug: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone.

    在 MySQL 中执行命令试下: set global time_zone='+8:00': 解释:在访问数据库时出现时区无法识别问题,在通过在数据库连接URL后,加上?serverTimezone= ...

  4. linux上快速搭建宝塔面板来操作便捷功能

    关于宝塔 Linux版请确保纯净系统安装(支持CentOS.Ubuntu.Debian.Fedora.Deepin),Web端管理,QQ群及论坛技术支持一键LAMP/LNMP.创建网站FTP.数据库. ...

  5. SUSE11虚拟机安装与Oracle 11g安装

    SUSE11虚拟机安装与Oracle 11g安装 本文中所需所有参数均位于文末附录中 新建虚拟机,选择SUSE11 64位 启动虚拟机后,选择第二项安装 选择语言 跳过CD检查 选择全新安装 选择默认 ...

  6. ES6(es2015)新增实用方法汇总

    Array 1.map() [1,2,3,4].map(function(item, index, array){ return  item * 2; }) 对数组中的每一项执行一次回调函数,三个参数 ...

  7. 深入理解Oracle中的随机函数

    --Oracle中取随机值的函数 .dbms_random包 dbms_random包提供了一系列的随机值获取函数以及相关存储过程.下面详细讲解常用的函数和过程. ()dbms_random.rand ...

  8. Java中Semaphore(信号量)的使用

    Semaphore的作用: 在java中,使用了synchronized关键字和Lock锁实现了资源的并发访问控制,在同一时间只允许唯一了线程进入临界区访问资源(读锁除外),这样子控制的主要目的是为了 ...

  9. 百度地图JS 搜索悬浮窗功能

    这个需求的效果类似下面的截图,主要还是利用百度地图中自定义控件的功能,挺简单的.文档地址在这 http://lbsyun.baidu.com/index.php?title=jspopular 效果图 ...

  10. Winform DevExpress控件库(二) 使用SplashScreenManager控件定制程序加载页面

    SplashScreenManager控件:主要作用是显示在进行耗时操作时的等待界面: 位于 工具箱 -> Navigation & Layout(导航栏与布局类控件) 目录下: 在工具 ...