python2.x中的新类型类(New-style class)与python3.x的类一致,均继承object类,而不继承object的类称为经典类(classic class),而对于这两种类,一般实例属性截取函数(generic instance attribute interception methods)的行为有所不同,其在3.x和2.x的新类型类中,不再被__x__操作符重载函数名(operator overloading name)的内建操作调用,对于该操作符重载函数名的搜索直接在类中搜索,而非实例中,而对于显式名的属性获取,包括__x__名,仍然要路经__getattr__,因此这是对于内建操作行为的主要影响,这种影响进而又影响到属性截取以及代理类。比如一个类定义了__getitem__索引重载函数,x是该类的一个实例,对于经典类来说,x[I]与x.__getitem__(I)等价,而对于新类型类来说,x[I]不再被__getattr__获取,而显式x.__getitem__仍然可以被获取。

1.对属性截取的影响:

首先看__getattr__在经典类与新类型类中表现的差异。

(1)在新类型类中(下列代码在3.x中实现):

>>> class c:
 data='spam'
 def __getattr__(self,name):
  print('getattr->'+name)
  return getattr(self.data,name)
 
>>> x=c()
>>> x[0]
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    x[0]
TypeError: 'c' object does not support indexing

构造了一个名为c的类,类长__getattr__方法可截取实例属性,然后打印截取到的属性名,最后返回实例对象的data对象的name方法结果。而对于x[0]内建操作表达式,则抛出了异常,该异常为c对象不支持索引,因此可以看出x[0]是直接在类中进行搜索,而跳过了实例属性截取函数__getattr__。

>>> getattr->__getitem__
x.__getitem__(0)
getattr->__getitem__
's'

而x.__getitem__(0)方法可以被__getattr__获取,类似的,对于其他内建操作,比如,x+'eggs',与x.__add__('eggs'),也有相同的反应。

>>> getattr->__add__
x.__add__('eggs')
getattr->__add__
'spameggs'
>>> x+'eggs'
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
x+'eggs'
TypeError: unsupported operand type(s) for +: 'c' and 'str'
>>> type(x).__getitem__(x,0)
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    type(x).__getitem__(x,0)
AttributeError: type object 'c' has no attribute '__getitem__'

当用x的类(即c)调用__getitem__,可以预想到的,抛出AttributeError,因为c并没有__getitem__方法。

(2)以上代码在经典类中(在2.x中实现):

>>>  class c:
data='spam'
def __getattr__(self,name):
print('getattr->'+name)
return getattr(self.data,name) File "<pyshell#0>", line 2
class c:
^
IndentationError: unexpected indent
>>> class c:
data='spam'
def __getattr__(self,name):
print('getattr->'+name)
return getattr(self.data,name) >>> x=c()
>>> x[0]
getattr->__getitem__
's'
>>> getattr->__getitem__
x.__getitem__(0)
getattr->__getitem__
's'
>>> getattr->__add__
x.__add__('eggs')
getattr->__add__
'spameggs'
>>> x+'eggs'
getattr->__coerce__
getattr->__add__
'spameggs'

可以看到,在经典类型中,测试全部通过。

>>> type(x).__getitem__(0)

Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
type(x).__getitem__(0)
TypeError: descriptor '__getitem__' requires a 'instance' object but received a 'int'

但是,尝试用c类调用__getitem__,却抛出异常,主要是描述符(descriptor)的参数错误造成的,关于描述符的总结,将在后面的文章中专门整理。

2.对代理类的影响

实际上,在属性截取中,已经提到,在新类型类中,当直接用隐式的内建操作表达式,如x[i],x+等,抛出AttributError的异常,因为这种情况下,是直接从类开始搜索的,而c类中没有,所以才抛出了异常,那该怎么办呢?一个很自然的办法就是在类中,对要代理的隐式内建操作表达式进行重新定义,所以类就具备了要代理操作属性。

>>> class c:
data='spam'
def __getattr__(self,name):
print('getattr->'+name)
return getattr(self.data,name)
def __getitem__(self,i):
print('getitem:'+str(i))
return self.data[i]
def __add__(self,other):
print('add->'+other)
return getattr(self.data,'__add__')(other)

上述代码在3.x中实现,通过对类c重新定义__getitem__,__add__重新定义实现了代理索引和加操作。

>>> x=c()
>>> x.upper()
getattr->upper
'SPAM'

可以看到__getattr__截取了一般方法upper()。

>>> x[0]
getitem:0
's'
>>> x.__getitem__(0)
getitem:0
's'
>>> x+'eggs'
add->eggs
'spameggs'
>>> x.__add__('eggs')
add->eggs
'spameggs'

可以看到,代理成功。

(3)进一步的理解

事实上,子类继承基类(超类)的属性或者方法若在子类中没有重载,而子类实例若调用该属性,将不被__getattr__拦截,直接调用基类的属性。如下代码:

>>> class c:
def test(self):
print('test from c') >>> class d(c):
def __getattr__(self,attr):
print('getattr'+attr) >>> x=d()
>>> x.test()
test from c

__getattr__在python2.x与python3.x中的区别及其对属性截取与代理类的影响的更多相关文章

  1. python的基本知识,range在python2.x中和python3.x中的区别

    这些是最开始学习python时的笔记,今天整理一下,在这里记录一下. 各种基础代码解释 for key,item in enumerate(li): print(key,item) inp=input ...

  2. python2.* 版本 与 3.* 版本中的区别

    目录 Unicode编码 print函数 raw_input() 和 input( ) 不等运算符 数据类型 除法 map 和 filter Unicode编码 python2.x 解释器默认编码格式 ...

  3. Python2.X和Python3.X中的urllib区别

    Urllib是Python提供的一个用于操作URL的模块,在Python2.X中,有Urllib库,也有Urllib2库,在Python3.X中Urllib2合并到了Urllib中,我们爬取网页的时候 ...

  4. Python2.X和Python3.X中Tkinter模块的文件对话框、下拉列表的不同

    Python2.X和Python3.X文件对话框.下拉列表的不同 今天初次使用Python Tkinter来做了个简单的记事本程序.发现Python2.x和Python3.x的Tkinter模块的好多 ...

  5. .Net基础——程序集与CIL HttpClient封装方法 .Net Core 编码规范 C#中invoke和beginInvoke的使用 WebServeice 动态代理类

    .Net基础——程序集与CIL   1. 程序集和CIL: 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll ...

  6. python2.x 到 python3.x 中“url”部分变化

    这部分是笔者在亲身项目中遇到的一些变化,并不全,后面将会更新. (1) urllib.urlopen    改为:   urllib.request.urlopen (2) urllib2   删除 ...

  7. python---基础知识回顾(五)(python2.7和python3.5中的编码)

    Unicode 和 UTF-8 有何区别? python基础之字符编码 以上两篇看懂即可,那下面的就不需要看了 python标准数据类型 Bytes python--数据类型bytes Python ...

  8. IE 中单元格的 colspan 属性在某些情况下会影响 TABLE 元素的自动布局

    今天在写一个jsp页面时,遇到一个如下的问题:在一个table中写了如下内容,table中定义了4列,在firefox中能正常显示,而在ie8中,显示不正常, 如下如图1:第二,三,四列宽度发生变化, ...

  9. python2.x和python3.x的区别

    一.python2.x和python3.x中raw_input( )和input( )区别 1.在Python2.x中raw_input( )和input( ),两个函数都存在,其中区别为 raw_i ...

随机推荐

  1. when_did_you_born-瞟来的wp

    继上文,这次开始嫖when_did_you_born这题.前面的步骤大致是一样的就不赘述了,直接到代码分析. 字符串 这次呢在main函数处 按下F5进入调试 查看反汇编代码 可以清楚的看到它的逻辑一 ...

  2. 第1节 IMPALA:1、impala的基本介绍

    impala的介绍: impala是cloudera公司开源提供的一款高效率的sql查询工具 impala可以兼容hive的绝大多数的语法,可以完全的替代表hive impala与hive的关系:紧耦 ...

  3. mysql 命令行导入导出.sql文件

    window下 1.导出整个数据库mysqldump -u 用户名 -p 数据库名 > 导出的文件名mysqldump -u dbuser -p dbname > dbname.sql 2 ...

  4. 微信小程序IOS真机调试发生了SSL 错误,无法建立与该服务器的安全连接

    小程序 真机调试 IOS request:fail 发生了SSL 错误,无法建立与该服务器的安全连接,解决方法服务器中打开Powerhell,执行以下代码,然后重启服务器 # Enables TLS ...

  5. decompiler of java

    运维了两个java项目,但是没有源代码,整天都是各种问题,各方面都不配合.我也只是个小小的兵,但是工作还是要做. 转机 偶然想试一试decomplier,就找到了gd-gui,感觉用着挺好的,到把项目 ...

  6. vue打包部署(含2.0)

    到这里vue的所有平时使用的知识点都写完了 先补充一下vue2.x的安装 ## 全局脚手架 npm install vue/cli -g ## 查看版本 vue --version ## 新建项目 v ...

  7. Day4 - H - Following Orders POJ - 1270

    Order is an important concept in mathematics and in computer science. For example, Zorn's Lemma stat ...

  8. Combobox出现System.Data.DataRowView的原因

    这种情况多次遇到.有时候明明完全相同的代码,在不同的场景运行却是两种结果, 其中一种坏的结果就是 comboBox所有的项都显示为System.Data.DataRowView 今天仔研究了一下,应该 ...

  9. NIO三大组件简介

    NIO简介 NIO 是面向缓冲区(或者说面向块)编程的, 因为Buffer底层本质上就是内存块.数据被读取到一个缓冲区, 稍后再被它处理, 需要时数据可在缓冲区前后移动, 从而增加了处理过程中的灵活性 ...

  10. linux下anaconda的安装和使用

    1.将python3设置为默认 直接执行这两个命令即可: sudo update-alternatives --install /usr/bin/python python /usr/bin/pyth ...