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的理解,考虑以下代码:
上例中,instance指的是temp,而owner则是Temperature。
LazyLoading Properties例子:
描述器很好的总结了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),绑定方法会自动将实例作为第一个参数传入方法。综上所述,方法是出现在类中的函数,绑定方法是一个绑定了具体实例的方法,反之则是非绑定方法。
综上,描述器被赋值给类,而这些特殊的方法就在属性被访问的时候根据具体的访问类型自动地调用。
元类(MetaClasses)
元类提供了一个改变Python类行为的有效方式。
元类的定义是“一个类的类”。任何实例是它自己的类都是元类。
在上例中,我们定义了一个类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高级编程技巧]
__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的更多相关文章
- python面向对象(六)之元类
元类 1. 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: In [13]: class ObjectCreator(object): . ...
- python中对象、类型和元类之间的关系
在python中对象.类型和元类构成了一个微妙的世界. 他们有在这个世界里和平共处,相辅相成.它们遵循着几条亘古不变的定律: 1.python中无处不对象 2.所有对象都有三种特性:id.类型.值 3 ...
- python面向对象反射-框架原理-动态导入-元类-自定义类-单例模式-项目的生命周期-05
反射 reflect 反射(reflect)其实是反省,自省的意思 反省:指的是一个对象应该具备可以检测.修改.增加自身属性的能力 反射:通过字符串获取对象或者类的属性,进行操作 设计框架时需要通过反 ...
- Python中对象、类型、元类之间的关系
Python里的对象.类型和元类的关系很微妙也很有意思. 1989年圣诞节期间,上帝很无聊,于是创造了一个世界. 对象 在这个世界的运转有几条定律. 1.一切都是对象 对象(object)是这个世界的 ...
- Python 黑魔法 --- 描述器(descriptor)
Python 黑魔法---描述器(descriptor) Python黑魔法,前面已经介绍了两个魔法,装饰器和迭代器,通常还有个生成器.生成器固然也是一个很优雅的魔法.生成器更像是函数的行为.而连接类 ...
- Python之描述器
1.描述器的表现 用到三个魔术方法,__get__(), __set__(), __delete__() 方法签名如下 object.__get__(self,instance,owner) obje ...
- 《Effective Python》笔记——第4章 元类及属性
一.用属性取代get和set方法 常规的get和set方法如下: class OldResistor(): def __init__(self, ohms): self.__ohms = ohms d ...
- Python语言特性之2:元类
问题:Python中的元类(metaclasses)是什么?一般使用它干什么? 原地址:http://stackoverflow.com/questions/100003/what-is-a-meta ...
- Java类载入器(二)——自己定义类载入器
用户定制自己的ClassLoader能够实现以下的一些应用: 自己定义路径下查找自己定义的class类文件,或许我们须要的class文件并不总是在已经设置好的Classpath以下,那么我们必须想 ...
随机推荐
- 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用第三方组件
Unity开发中,常常会用到一些第三方组件.本文以实例介绍如何在热更新脚本中使用这些第三方组件. 首先说明几个基本步骤: 第三方组件通常是以dll或者源码方式提供的,它们本身往往无法热更. 我们在脚本 ...
- 如何为分布式系统优雅的更换RPC
为啥需要更换RPC? 很多小伙伴都遇到过需要为分布式系统调用更换RPC的问题,为什么会遇到这种事呢?其实,在系统搭建初期,需求简单,架构简单,最重要的是请求量也少,所以很多系统都采用快速原型开发模式, ...
- Filter,FilterChain,FilterConfig
实例: package com.zillion.app.filter; import java.io.IOException; import javax.servlet.Filter; import ...
- JSON.parse()在火狐中的BUG
//用sessionStorage解决load页面刷新问题 { //sessionStorage.removeItem("loadInfo"); var loadInfo=de ...
- django.db.utils.ProgrammingError: 1146 的解决办法
在models中设置完数据库相关的东西后执行命令 python manage.py makemigrations 此处无错误 再次执行 python manage.py migrate 发生报错 错误 ...
- 小白到大神,Python 密集知识点汇总
Python 基础 1. 变量 你可以把变量想象成一个用来存储值的单词.我们看个例子. Python 中定义一个变量并为它赋值是很容易的.假如你想存储数字 1 到变量 "one" ...
- 安卓图片Bitmap一些旋转处理
Bitmap convert(Bitmap a, int width, int height) { int w = a.getWidth(); int h = a.getHeight(); Bitma ...
- JAVA中的常量定义在class中还是interface中比较合理?
本文地址:http://blog.csdn.net/sushengmiyan 本文作者:苏生米沿 java中使用的常量可以集中定义在一个文件中. 有两种解决方案: 1.在Constants.java中 ...
- [精简版]snowing snow
CSS <style> body { background: #eee; } @keyframes mysnow { 0% { bottom: 100%; opacity: 0; } 50 ...
- Java编程思想阅读收获
15年8月份买了一本Java编程思想第四版中文版.之所以买中文版是因为我试读了同事的英文版发现自己英语水平还是有限,单词虽然认识,但对很多句子把握不准,这样看书太慢了,要理解英文还要理解技术有些hol ...