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. javaBean、EJB、POJO

    1.JavaBean 最初是由 Sun 公司提出的一种规范,主要包含以下要求: ----类是 public 的,并且有一个无参数的构造函数 ----属性修饰符为:private,并通过 get 和 s ...

  2. SPFA和堆优化的Dijk

    朴素dijkstra时间复杂度$O(n^{2})$,通过使用堆来优化松弛过程可以使时间复杂度降到O((m+n)logn):dijkstra不能用于有负权边的情况,此时应使用SPFA,两者写法相似. 朴 ...

  3. CCF 201703-4 地铁修建(最小生成树)

    题意:A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号到n号枢纽间修建一条地铁.地铁由很多段隧道组成,每段隧道连接两个交通枢纽.经过勘探,有m段隧道作为候选,两个交通枢纽之 ...

  4. C#遍历DataSet

    ] foreach (DataRow dr in dt.Rows) ///遍历所有的行 foreach (DataColumn dc in dt.Columns) //遍历所有的列 Console.W ...

  5. Excel的查询函数vlookup和index使用

    需求 有一些省市的区县,有600多条数据,只有名称,没有编码.现在要根据名称去3000多条数据里面查询. 如图,拿出一部分数据来演示 vlookup 使用vlookup,由于vlookup只能查询数据 ...

  6. 0108 spring的申明式事务

    背景 互联网的金融和电商行业,最关注数据库事务. 业务核心 说明 金融行业-金融产品金额 不允许发生错误 电商行业-商品交易金额,商品库存 不允许发生错误 面临的难点: 高并发下保证: 数据一致性,高 ...

  7. 关于可持久化Trie

    我认为 可持久化Trie 主要指 可持久化01Trie 如洛谷P4735 将每个数的异或前缀和转化为二进制,添加前缀0至相同位数,然后从最高位开始插入,类似主席树,每一层都对需要更新的点加入一个新的点 ...

  8. [强网杯 2019]Upload

    0x00 知识点 代码审计,PHP 反序列化. 0x01 解题 先注册一个账号,再登陆 上传 简单测试一下: 只能上传能被正常查看的 png. F12看到文件上传路径 扫扫敏感文件 存在:/www.t ...

  9. Linux添加虚拟内存 && 修改Linux系统语言

    Linux添加虚拟内存 首先执行free -h查看内存状况: total used free shared buff/cache available Mem: 1.8G 570M 76M 8.4M 1 ...

  10. OpenMandriva或将放弃32位的支持

    导读 除了Ubuntu计划在其19.10发行版中删除32位包之外,OpenMandriva开发团队也是另一个备受关注的Linux发行版起草计划,以取消对32位包的支持. OpenMandriva计划在 ...