- 浏览: 565162 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (618)
- java (109)
- Java web (43)
- javascript (52)
- js (15)
- 闭包 (2)
- maven (8)
- 杂 (28)
- python (47)
- linux (51)
- git (18)
- (1)
- mysql (31)
- 管理 (1)
- redis (6)
- 操作系统 (12)
- 网络 (13)
- mongo (1)
- nginx (17)
- web (8)
- ffmpeg (1)
- python安装包 (0)
- php (49)
- imagemagic (1)
- eclipse (21)
- django (4)
- 学习 (1)
- 书籍 (1)
- uml (3)
- emacs (19)
- svn (2)
- netty (9)
- joomla (1)
- css (1)
- 推送 (2)
- android (6)
- memcached (2)
- docker、 (0)
- docker (7)
- go (1)
- resin (1)
- groovy (1)
- spring (1)
最新评论
-
chokee:
...
Spring3 MVC 深入研究 -
googleyufei:
很有用, 我现在打算学学Python. 这些资料的很及时.
python的几个实用网站(转的) -
hujingwei1001:
太好了找的就是它
easy explore -
xiangtui:
例子举得不错。。。学习了
java callback -
幻影桃花源:
太好了,謝謝
Spring3 MVC 深入研究
如果你和我一样,曾经对method和function以及对它们的各种访问方式包括self参数的隐含传递迷惑不解,建议你耐心的看下去。这里还提到了Python属性查找策略,使你清楚的知道Python处理obj.attr和obj.attr=val时,到底做了哪些工作。
Python中,对象的方法也是也可以认为是属性,所以下面所说的属性包含方法在内。
先定义下面这个类,还定义了它的一个实例,留着后面用。
使用dir(t)列出t的所有有效属性:
- >>> dir(t)
- ['__class__' , '__delattr__' , '__dict__' , '__doc__' , '__getattribute__' ,
- '__hash__' , '__init__' , '__module__' , '__new__' , '__reduce__' , '__reduce_ex__' ,
- '__repr__' , '__setattr__' , '__str__' , '__weakref__' , 'hello' , 'name' ]
属性可以分为两类,一类是Python自动产生的,如__class__,__hash__等,另一类是我们自定义的,如上面的hello,name。我们只关心自定义属性。
类和实例对象(实际上,Python中一切都是对象,类是type的实例)都有__dict__属性,里面存放它们的自定义属性(对与类,里面还存放了别的东西)。
- >>> t.__dict__
- {}
- >>> T.__dict__
- <dictproxy object at 0x00CD0FF0 >
- >>> dict(T.__dict__) #由于T.__dict__并没有直接返回dict对象,这里进行转换,以方便观察其中的内容
- {'__module__' : '__main__' , 'name' : 'name' ,
- 'hello' : <function hello at 0x00CC2470 >,
- '__dict__' : <attribute '__dict__' of 'T' objects>,
- '__weakref__' : <attribute '__weakref__' of 'T' objects>, '__doc__' : None }
- >>>
有些内建类型,如list和string,它们没有__dict__属性,随意没办法在它们上面附加自定义属性。
到现在为止t.__dict__是一个空的字典,因为我们并没有在t上自定义任何属性,它的有效属性hello和name都是从T得到的。T的__dict__中包含hello和name。当遇到t.name语句时,Python怎么找到t的name属性呢?
首先,Python判断name属性是否是个自动产生的属性,如果是自动产生的属性,就按特别的方法找到这个属性,当然,这里的name不是自动产生的属性,而是我们自己定义的,Python于是到t的__dict__中寻找。还是没找到。
接着,Python找到了t所属的类T,搜索T.__dict__,期望找到name,很幸运,直接找到了,于是返回name的值:字符串‘name’。如果在T.__dict__中还没有找到,Python会接着到T的父类(如果T有父类的话)的__dict__中继续查找。
这不足以解决我们的困惑,因为事情远没有这么简单,上面说的其实是个简化的步骤。
继续上面的例子,对于name属性T.name和T.__dict__['name']是完全一样的。
但是对于hello,情形就有些不同了
- >>> T.hello
- <unbound method T.hello>
- >>> T.__dict__['hello' ]
- <function hello at 0x00CC2470 >
- >>>
可以发现,T.hello是个unbound method。而T.__dict__['hello']是个函数(不是方法)。
推断:方法在类的__dict__中是以函数的形式存在的(方法的定义和函数的定义简直一样,除了要把第一个参数设为self)。那么T.hello得到的应该也是个函数啊,怎么成了unbound method了。
再看看从实例t中访问hello
是一个bound method。
有意思,按照上面的查找策略,既然在T的__dict__中hello是个函数,那么T.hello和t.hello应该都是同一个函数才对。到底是怎么变成方法的,而且还分为unbound method和bound method。
关于unbound和bound到还好理解,我们不妨先作如下设想:方法是要从实例调用的嘛(指实例方法,classmethod和staticmethod后面讲),如果从类中访问,如T.hello,hello没有和任何实例发生联系,也就是没绑定(unbound)到任何实例上,所以是个unbound,对t.hello的访问方式,hello和t发生了联系,因此是bound。
但从函数<function hello at 0x00CC2470>到方法<unbound method T.hello>的确让人费解。
一切的魔法都源自今天的主角:descriptor
查找属性时,如obj.attr,如果Python发现这个属性attr有个__get__方法,Python会调用attr的__get__方法,返回__get__方法的返回值,而不是返回attr(这一句话并不准确,我只是希望你能对descriptor有个初步的概念)。
Python中iterator(怎么扯到Iterator了?)是实现了iterator协议的对象,也就是说它实现了下面两个方法__iter__和next()。类似的,descriptor也是实现了某些特定方法的对象。descriptor的特定方法是__get__,__set__和__delete__,其中__set__和__delete__方法是可选的。iterator必须依附某个对象而存在(由对象的__iter__方法返回),descriptor也必须依附对象,作为对象的一个属性,它而不能单独存在。还有一点,descriptor必须存在于类的__dict__中,这句话的意思是只有在类的__dict__中找到属性,Python才会去看看它有没有__get__等方法,对一个在实例的__dict__中找到的属性,Python根本不理会它有没有__get__等方法,直接返回属性本身 。descriptor到底是什么呢:简单的说,descriptor是对象的一个属性,只不过它存在于类的__dict__中并且有特殊方法__get__(可能还有__set__和__delete)而具有一点特别的功能,为了方便指代这样的属性,我们给它起了个名字叫descriptor属性。
可能你还是不明白,下面开始用例子说明。
先定义这个类:
- class Descriptor(object):
- def __get__(self , obj, type=None ):
- return 'get' , self , obj, type
- def __set__(self , obj, val):
- print 'set' , self , obj, val
- def __delete__(self , obj):
- print 'delete' , self , obj
这里__set__和__delete__其实可以不出现,不过为了后面的说明,暂时把它们全写上。
下面解释一下三个方法的参数:
self当然不用说,指的是当前Descriptor的实例。obj值拥有属性的对象。这应该不难理解,前面已经说了,descriptor是对象的稍微有点特殊的属性,这里的obj就是拥有它的对象,要注意的是,如果是直接用类访问descriptor(别嫌啰嗦,descriptor是个属性,直接用类访问descriptor就是直接用类访问类的属性),obj的值是None。type是obj的类型,刚才说过,如果直接通过类访问descriptor,obj是None,此时type就是类本身。
三个方法的意义,假设T是一个类,t是它的一个实例,d是T的一个descriptor属性(牛什么啊,不就是有个__get__方法吗!),value是一个有效值:
读取属性时,如T.d,返回的是d.__get__(None, T)的结果,t.d返回的是d.__get__(t, T)的结果。
设置属性时,t.d = value,实际上调用d.__set__(t, value),T.d = value,这是真正的赋值,T.d的值从此变成value。删除属性和设置属性类似。
下面用例子说明,看看Python中执行是怎么样的:
重新定义我们的类T和实例t
d是T的类属性,作为Descriptor的实例,它有__get__等方法,显然,d满足了所有的条件,现在它就是一个descriptor!
- >>> t.d #t.d,返回的实际是d.__get__(t, T)
- ('get' , <__main__.Descriptor object at 0x00CD9450 >, <__main__.T object at 0x00CD0E50 >, <class '__main__.T' >)
- >>> T.d #T.d,返回的实际是d.__get__(None, T),所以obj的位置为None
- ('get' , <__main__.Descriptor object at 0x00CD9450 >, None , <class '__main__.T' >)
- >>> t.d = 'hello' #在实例上对descriptor设置值。要注意的是,现在显示不是返回值,而是__set__方法中
- print 语句输出的。
- set <__main__.Descriptor object at 0x00CD9450 > <__main__.T object at 0x00CD0E50 > hello
- >>> t.d #可见,调用了Python调用了__set__方法,并没有改变t.d的值
- ('get' , <__main__.Descriptor object at 0x00CD9450 >, <__main__.T object at 0x00CD0E50 >, <class '__main__.T' >)
- >>> T.d = 'hello' #没有调用__set__方法
- >>> T.d #确实改变了T.d的值
- 'hello'
- >>> t.d #t.d的值也变了,这可以理解,按我们上面说的属性查找策略,t.d是从T.__dict__中得到的
- T.__dict__['d' ]的值是'hello' ,t.d当然也是'hello'
- 'hello'
data descriptor和non-data descriptor
象上面的d,同时具有__get__和__set__方法,这样的descriptor叫做data descriptor,如果只有__get__方法,则叫做non-data descriptor。容易想到,由于non-data descriptor没有__set__方法,所以在通过实例对属性赋值时,例如上面的t.d = 'hello',不会再调用__set__方法,会直接把t.d的值变成'hello'吗?口说无凭,实例为证:
- class Descriptor(object):
- def __get__(self , obj, type=None ):
- return 'get' , self , obj, type
- class T(object):
- d = Descriptor()
- t = T()
- >>> t.d
- ('get' , <__main__.Descriptor object at 0x00CD9550 >, <__main__.T object at 0x00CD9510 >, <class '__main__.T' >)
- >>> t.d = 'hello'
- >>> t.d
- 'hello'
- >>>
在实例上对non-data descriptor赋值隐藏了实例上的non-data descriptor!
是时候坦白真正详细的属性查找策略 了,对于obj.attr(注意:obj可以是一个类):
1.如果attr是一个Python自动产生的属性,找到!(优先级非常高!)
2.查找obj.__class__.__dict__,如果attr存在并且是data descriptor,返回data descriptor的__get__方法的结果,如果没有继续在obj.__class__的父类以及祖先类中寻找data descriptor
3.在obj.__dict__中查找,这一步分两种情况,第一种情况是obj是一个普通实例,找到就直接返回,找不到进行下一步。第二种情况是obj是一个类,依次在obj和它的父类、祖先类的__dict__中查找,如果找到一个descriptor就返回descriptor的__get__方法的结果,否则直接返回attr。如果没有找到,进行下一步。
4.在obj.__class__.__dict__中查找,如果找到了一个descriptor(插一句:这里的descriptor一定是non-data descriptor,如果它是data descriptor,第二步就找到它了)descriptor的__get__方法的结果。如果找到一个普通属性,直接返回属性值。如果没找到,进行下一步。
5.很不幸,Python终于受不了。在这一步,它raise AttributeError
利用这个,我们简单分析一下上面为什么要强调descriptor要在类中才行。我们感兴趣的查找步骤是2,3,4。第2步和第4步都是在类中查找。对于第3步,如果在普通实例中找到了,直接返回,没有判断它有没有__get__()方法。
对属性赋值时的查找策略 ,对于obj.attr = value
1.查找obj.__class__.__dict__,如果attr存在并且是一个data descriptor,调用attr的__set__方法,结束。如果不存在,会继续到obj.__class__的父类和祖先类中查找,找到 data descriptor则调用其__set__方法。没找到则进入下一步。
2.直接在obj.__dict__中加入obj.__dict__['attr'] = value
顺便分析下为什么在实例上对non-data descriptor赋值隐藏了实例上的non-data descriptor。
接上面的non-data descriptor例子
在t的__dict__里出现了d这个属性。根据对属性赋值的查找策略,第1步,确实在t.__class__.__dict__也就是T.__dict__中找到了属性d,但它是一个non-data descriptor,不满足data descriptor的要求,进入第2步,直接在t的__dict__属性中加入了属性和属性值。当获取t.d时,执行查找策略,第2步在T.__dict__中找到了d,但它是non-data descriptor,步满足要求,进行第3步,在t的__dict__中找到了d,直接返回了它的值'hello'。
说了这么半天,还没到函数和方法!
算了,明天在说吧
简单提一下,所有的函数(方法)都有__get__方法,当它们在类的__dict__中是,它们就是non-data descriptor。
发表评论
-
Django静态文件处理总结
2015-05-13 13:59 538原文地址:http://blog.csdn.net/wenxu ... -
原 异步非阻塞机制与多线程阻塞机制在处理并发耗时等待任务上的效率对比分析
2015-04-21 10:05 696原文地址:http://my.oschina.net/mall ... -
Django报错“_mysql_exceptions.Warning: Incorrect string value: ‘\xE6\xB5…’ for colu
2015-03-25 15:50 1000原文地址:http://www.tuicool.com/art ... -
django使用mysql时的中文存储问题 - [python]
2015-03-25 15:36 1505原文地址:http://www.blogbus.com/831 ... -
NIO学习笔记——解决“服务器端cpu占用率高”
2015-01-29 10:17 991原文地址:http://blog.csdn ... -
python 调用 php 实例
2014-06-23 14:09 2627原文地址:http://hi.baidu.com/ji_hai ... -
php调用python
2014-06-23 14:08 794原文地址:http://blog.163.com/darwin ... -
uwsgi python ssl编译问题记录
2014-06-19 14:24 878uwsgi python ssl编译问题记录 发表于6个月前( ... -
python2.7 安装ssl模块
2014-06-19 14:22 3221python2.7 安装ssl模块 2012-02-28 13 ... -
Centos6.5下升级Python 2.6.6 to python 2.7.3
2014-06-19 13:53 656Centos6.5下升级Python 2.6.6 to pyt ... -
翻译:redis-py 说明文件 (2012-05-30 17:55:52)
2014-06-04 10:22 459翻译:redis-py 说明文件 (2012-05-30 17 ... -
关于Redis的Python客户端的连接池问题
2014-06-04 10:21 626关于Redis的Python客户端的连接池问题 在一 ... -
Windows下 Python 安装包的配置
2014-03-22 10:23 6571、下载安装 Python python-2.7.2.msi ... -
[翻译]深入理解Tornado——一个异步web服务器
2014-03-07 15:16 1643[翻译]深入理解Tornado— ... -
多版本Python共存[支持使用pip安装包]
2014-02-28 10:59 1146多版本Python共存[支持使 ... -
Django 数据库访问性能优化
2013-09-05 15:22 684Django 数据库访问性 ... -
Python六大开源框架对比:Web2py略胜一筹
2013-08-21 11:29 829Python是一门动态、面向对象语言。其最初就是作为一门面向 ... -
Python 代码调试技巧
2013-08-15 18:11 874使用 pdb 进行调试 pdb 是 python 自带的 ... -
python urlencode 编码
2013-07-05 13:28 965urlencode 调用方法 urlencode的参 ... -
window下使用virtualenv
2013-06-30 15:26 1113--- window下使用virtualenv -- ...
相关推荐
### 详解 Python 中 `__get__` 和 `__getattr__` 与 `__getattribute__` 的区别 在 Python 编程语言中,对象的属性访问机制是非常灵活且强大的。当我们试图通过点号(`.`)操作符去访问一个对象的属性时,Python 会...
静态方法,Python中get,set的写法。对应文件:ClassElement5,文章:https://blog.csdn.net/yysyangyangyangshan/article/details/84504401
account = sdk.get_account('<your_account_address>') balance = account.get_balance() print(f'账户余额: {balance}') ``` `ontology_python_sdk`还支持智能合约的部署和调用。开发者可以使用SDK的`deploy_...
data = jq.data.get_fund_trading_data(fund_code, start_date=start_date, end_date=end_date, frequency='1min') # 获取分钟数据 # 对数据进行处理... ``` 4. **数据处理**:获取到数据后,通常需要进行一些...
Python是一种高级、解释型、交互式和面向对象的脚本语言。在"PythonCode"这个压缩包中,我们可以预见到包含了一系列与Python编程相关的代码示例。这些示例可能覆盖了Python的基础语法、数据结构、函数、类和模块等多...
3. **API介绍**:详述Python-netsnmp库提供的各种函数和类,包括初始化session、执行GET和SET请求、处理traps的方法。 4. **示例代码**:提供实际的代码示例,展示如何使用库来查询网络设备的状态、设置配置参数,...
for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() ``` 3. **游戏循环**: 游戏的核心是主循环,它会一直运行直到游戏结束。在这个循环里,我们会更新游戏状态,绘制...
`pygame.event.get()`用于获取用户按键或鼠标点击等事件,然后根据这些事件更新游戏状态。例如,如果检测到用户按下空格键,`Ship`类可以发射子弹。 游戏循环是游戏的心脏,通常由`while`循环实现,持续检查游戏...
current_temperature = airzone.get_current_temperature() print(f"当前温度:{current_temperature}℃") # 设置目标温度 airzone.set_target_temperature(25) # 更多功能... ``` 这个库的使用可能涉及到网络...
在实际应用中,`snmp_Get_Set_Trap`工具通常配合脚本语言(如Python、Perl或Bash)和任务调度器(如Cron)使用,以实现自动化监控和管理任务。例如,你可以定期通过GET检查设备状态,通过SET执行配置变更,或者设定...
每个`Element`对象都有`tag`(标签名)、`text`(元素内的文本)和`attrib`(属性字典)等属性,以及`children`(子元素列表)。 ```python for child in root: print(f"Tag: {child.tag}, Text: {child.text}, ...
1. **get_local_time()**:获取本地时间,对于记录和同步操作可能很有用。 2. **robot_event_callback(event)**:这是一个事件回调函数,当机器人发生特定事件时会被调用。 3. **raise_error(error_type, error_code...
def get_string(self, key): return self.redis_client.get(key) ``` 2. **哈希操作**:存储和检索键值对,其中键是哈希表的字段,值是对应的值。 ```python def set_hash(self, key, mapping): self.redis_...
outs = net.forward(get_output_layers(net)) ``` 总的来说,OpenCV官方教程中文版为Python开发者提供了一个全面的指南,涵盖了图像和视频处理的基础操作,以及高级计算机视觉技术。通过深入学习这个教程,开发者...
这个名为"新建文件夹.zip_mad68x_python_tensorflow_人脸识别_人脸识别 python"的压缩包包含了一系列与人脸识别相关的Python脚本,分别是train_faces.py、is_my_face.py、get_my_faces.py和set_other_faces.py。...
在Python编程语言中,tushare是一个非常实用的金融数据接口库,主要提供中国及全球股票、期货、期权、基金、外汇、债券等金融数据。本教程将详细讲解如何使用tushare库来抓取股票实时数据,包括获取美股数据。 首先...
pyGame是基于Python的多媒体处理模块集合,它包含了一系列用于游戏开发的库,如图像处理、音频管理、事件处理和窗口管理等。pyGame是SDL(Simple DirectMedia Layer)库的Python绑定,因此你可以利用SDL的强大功能,...
例如,`turn_on()`方法可能会用于开启灯泡,`set_brightness(value)`用于设置亮度,`set_color_temperature(temp)`用于调整色温,而`set_color(r, g, b)`则用于设定RGB颜色。每个方法内部都会构造对应的HTTP请求,...
标题中的“redis_redis_python_”暗示了我们讨论的是如何使用...而对于MySQL,`pymysql`或`mysql-connector-python`等库则提供了SQL操作的接口。在实际应用中,这样的组合常常用于实现数据缓存、数据库读写分离等场景。
if "Connected" in device.call("GetProperties").get_value().keys(): print(f"Device found: {path}") server = BlueZ.Server() server.register_service(SERVICE_UUID, "MyBluetoothService") ...