我试图理解什么时候定义__getattr__或__getattribute__。python文档提到__getattribute__适用于新样式的类。什么是新型类?
当前回答
我发现没有人提到这个区别:
__getattribute__有默认实现,但__getattr__没有。
class A:
pass
a = A()
a.__getattr__ # error
a.__getattribute__ # return a method-wrapper
这有一个明确的含义:因为__getattribute__有默认实现,而__getattr__没有,显然python鼓励用户实现__getattr__。
其他回答
新型类是直接或间接继承“object”的类。除了__init__之外,它们还有一个__new__类方法,并且有一些更合理的低级行为。
通常,你会想要重写__getattr__(如果你重写了其中任何一个),否则你将很难支持“self”。方法中的Foo语法。
额外信息:http://www.devx.com/opensource/Article/31482/0/page/4
这只是一个基于Ned Batchelder解释的例子。
__getattr__例子:
class Foo(object):
def __getattr__(self, attr):
print "looking up", attr
value = 42
self.__dict__[attr] = value
return value
f = Foo()
print f.x
#output >>> looking up x 42
f.x = 3
print f.x
#output >>> 3
print ('__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found')
如果同样的例子使用__getattribute__,你会得到>>> RuntimeError:调用Python对象时超过最大递归深度
让我们看一些__getattr__和__getattribute__神奇方法的简单例子。
__getattr__
每当你请求一个尚未定义的属性时,Python将调用__getattr__方法。在下面的例子中,我的类Count没有__getattr__方法。在main中,当我访问两个obj1时。Mymin和obj1。Mymax属性一切正常。但当我访问obj1时。` Count `对象没有属性` mycurrent `
class Count():
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent) --> AttributeError: 'Count' object has no attribute 'mycurrent'
现在我的类Count有__getattr__方法。当我访问obj1时。mycurrent属性——python返回我在__getattr__方法中实现的任何内容。在我的例子中,每当我试图调用一个不存在的属性时,python都会创建该属性并将其设置为整数值0。
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
def __getattr__(self, item):
self.__dict__[item]=0
return 0
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent1)
__getattribute__
现在让我们看看__getattribute__方法。如果你的类中有__getattribute__方法,python会为每个属性调用这个方法,不管它是否存在。那么为什么我们需要__getattribute__方法呢?一个很好的理由是,您可以阻止对属性的访问,并使它们更加安全,如下面的示例所示。
每当有人试图访问以子字符串“cur”开头的属性时,python会引发AttributeError异常。否则它会返回该属性。
class Count:
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
重要提示:为了避免__getattribute__方法中的无限递归,它的实现应该始终调用具有相同名称的基类方法来访问所需的任何属性。例如:object。__getattribute__(self, name)或super().__getattribute__(item)而不是self.__dict__[item]
重要的
如果你的类同时包含getattr和getattribute魔法方法,那么__getattribute__将首先被调用。但是如果__getattribute__引发 AttributeError异常,则该异常将被忽略,并调用__getattr__方法。示例如下:
class Count(object):
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattr__(self, item):
self.__dict__[item]=0
return 0
def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return object.__getattribute__(self,item)
# or you can use ---return super().__getattribute__(item)
# note this class subclass object
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
__getattr__和__getattribute__之间的一个关键区别是,__getattr__只在没有以通常的方式找到属性时才会被调用。它很适合为缺失的属性实现回退,并且可能是您想要的两种方法之一。
__getattribute__是在查看对象上的实际属性之前调用的,因此正确实现可能很棘手。你可以很容易地得到无限递归。
新类型的类派生于object,旧类型的类是Python 2中的类。没有显式基类的X。但是在__getattr__和__getattribute__之间进行选择时,旧风格和新风格类之间的区别并不是重要的一个。
你几乎肯定想要__getattr__。
在阅读Beazley & Jones PCB时,我偶然发现了__getattr__的一个明确而实际的用例,它有助于回答OP问题的“何时”部分。摘自书中:
"The __getattr__() method is kind of like a catch-all for attribute lookup. It's a method that gets called if code tries to access an attribute that doesn't exist." We know this from the above answers, but in PCB recipe 8.15, this functionality is used to implement the delegation design pattern. If Object A has an attribute Object B that implements many methods that Object A wants to delegate to, rather than redefining all of Object B's methods in Object A just to call Object B's methods, define a __getattr__() method as follows:
def __getattr__(self, name):
return getattr(self._b, name)
其中_b是Object A的属性(Object B)的名称。当Object B上定义的方法在Object A上被调用时,__getattr__方法将在查找链的末尾被调用。这也会使代码更干净,因为您不需要为委托给另一个对象而定义一个方法列表。
推荐文章
- 如何保持Python打印不添加换行符或空格?
- 为什么Python的无穷散列中有π的数字?
- Python 3.7数据类中的类继承
- 如何在PyTorch中初始化权重?
- 计数唯一的值在一列熊猫数据框架像在Qlik?
- 使用Pandas将列转换为行
- 从matplotlib中的颜色映射中获取单个颜色
- 将Pandas或Numpy Nan替换为None以用于MysqlDB
- 使用pandas对同一列进行多个聚合
- 使用Python解析HTML
- django MultiValueDictKeyError错误,我如何处理它
- 如何在for循环期间修改列表条目?
- 我如何在Django中创建一个鼻涕虫?
- 没有名为'django.core.urlresolvers'的模块
- 蟒蛇导出环境文件