getattr()究竟是什么,我该如何使用它?

我正在阅读有关getattr()函数 。 问题是我还是不能把握它的用法。 我对getattr()理解是, getattr(li, "pop")和调用li.pop是一样的。

我不明白什么时候这本书提到你如何使用它来获得一个函数的引用,直到运行时才知道它的名字。 总的来说,也许这就是我在编程方面的一个小菜鸟。 任何人都可以谈一谈这个问题? 何时以及如何使用这个?

你可以在这里查看一个完整的例子:

内省可以用于不同的目的,“深入到Python”中提供的内容只是一种在应用程序中dynamic添加function(插件)的方法。

dynamic地,我的意思是在核心应用程序中不做修改来添加新的function。

以“深入Python”为例 – 一个简单的应用程序,从不同文件的文件中提取属性 – 你可以添加一个新的文件格式的处理,而不用修改原来的应用程序。

我build议你整理这本书,一切都变得越来越清晰。

Python中的对象可以有属性(实际上,每个对象都有内置的属性 – 数据属性和方法(函数是值,也就是对象)来处理这些属性。

例如,你有一个对象,有几个属性: namegender

您可以访问这些属性(通常是方法或数据对象): person.nameperson.genderperson.name person.the_method()

但是如果你在编写程序的时候不知道属性的名字呢? 例如,您将属性名称存储在名为attr_name的variables中。

如果

 attr_name = 'gender' 

那么,而不是写作

 gender = person.gender 

你可以写

 gender = getattr(person, attr_name) 

一些做法:

 Python 3.4.0 (default, Apr 11 2014, 13:05:11) >>> class Person(): ... name = 'Victor' ... def say(self, what): ... print(self.name, what) ... >>> getattr(Person, 'name') 'Victor' >>> attr_name = 'name' >>> person = Person() >>> getattr(person, attr_name) 'Victor' >>> getattr(person, 'say')('Hello') Victor Hello 

如果给定名称的属性不存在于对象中, getattr将引发AttributeError

 >>> getattr(person, 'age') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Person' object has no attribute 'age' 

但是你可以传递一个默认值作为第三个参数,如果这个属性不存在,将返回这个值:

 >>> getattr(person, 'age', 0) 0 

您可以使用getattrdir来遍历所有属性名称并获取它们的值:

 >>> dir(1000) ['__abs__', '__add__', ..., '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes'] >>> obj = 1000 >>> for attr_name in dir(obj): ... attr_value = getattr(obj, attr_name) ... print(attr_name, attr_value, callable(attr_value)) ... __abs__ <method-wrapper '__abs__' of int object at 0x7f4e927c2f90> True ... bit_length <built-in method bit_length of int object at 0x7f4e927c2f90> True ... >>> getattr(1000, 'bit_length')() 10 

一个实际的用法是find所有名称以test开始的方法并调用它们 。

getattr类似, setattr允许你设置一个名字为对象的属性:

 >>> setattr(person, 'name', 'Andrew') >>> person.name # accessing instance attribute 'Andrew' >>> Person.name # accessing class attribute 'Victor' >>> 

对我而言,getattr最容易解释:

它允许您根据string的内容调用方法,而不是键入方法名称。

例如,你不能这样做:

 obj = MyObject() for x in ['foo', 'bar']: obj.x() 

因为x不是“内build”types,而是“str”。 但是,您可以这样做:

 obj = MyObject() for x in ['foo', 'bar']: getattr(obj, x)() 

它允许您根据您的inputdynamic连接对象。 处理自定义对象和模块时,我发现它很有用。

getattr一个非常常见的用例是将数据映射到函数。

例如,在像Django或Pylons这样的Web框架中, getattr可以直接将Web请求的URL映射到要处理它的函数。 例如,如果你仔细看看Pylons的路由,你会发现(至less在缺省情况下)会截断一个请求的URL,例如:

 http://www.example.com/customers/list 

成“客户”和“名单”。 然后它search名为CustomerController的控制器类。 假设它find类,它创build类的一个实例,然后使用getattr来获取它的list方法。 然后调用该方法,将请求作为parameter passing给它。

一旦掌握了这个想法,扩展一个Web应用程序的function就变得非常简单了:只需在控制器类中添加新的方法,然后在页面中创build链接,以便为这些方法使用适当的URL。 所有这一切都可以通过getattr

下面是一个快速和肮脏的例子,说明一个类如何根据使用getattr()执行的操作系统来激发不同版本的保存方法。

 import os class Log(object): def __init__(self): self.os = os.name def __getattr__(self, name): """ look for a 'save' attribute, or just return whatever attribute was specified """ if name == 'save': try: # try to dynamically return a save # method appropriate for the user's system return getattr(self, self.os) except: # bail and try to return # a default save method return getattr(self, '_save') else: return getattr(self, name) # each of these methods could have save logic specific to # the system on which the script is executed def posix(self): print 'saving on a posix machine' def nt(self): print 'saving on an nt machine' def os2(self): print 'saving on an os2 machine' def ce(self): print 'saving on a ce machine' def java(self): print 'saving on a java machine' def riscos(self): print 'saving on a riscos machine' def _save(self): print 'saving on an unknown operating system' def which_os(self): print os.name 

现在让我们用一个例子来说明这个类:

 logger = Log() # Now you can do one of two things: save_func = logger.save # and execute it, or pass it along # somewhere else as 1st class: save_func() # or you can just call it directly: logger.save() # other attributes will hit the else # statement and still work as expected logger.which_os() 

我有时使用getattr(..)在代码中使用之前就懒惰地初始化次要属性。

比较以下内容:

 class Graph(object): def __init__(self): self.n_calls_to_plot = 0 #... #A lot of code here #... def plot(self): self.n_calls_to_plot += 1 

对此:

 class Graph(object): def plot(self): self.n_calls_to_plot = 1 + getattr(self, "n_calls_to_plot", 0) 

第二种方法的优点是n_calls_to_plot只出现在代码的使用地点周围。 这对于可读性是有好处的,因为(1)在阅读它的使用方式时,你可以马上看到它开始的价值,(2)它不会将注意力引入__init__(..)方法,理想的情况应该是概念状态,而不是一些实用计数器,由于技术上的原因,比如优化,只能被函数的某个方法使用,而与对象的含义无关。

当我从存储在类中的数据创buildXML文件时,经常会遇到错误,如果该属性不存在或者是Nonetypes的。 在这种情况下,我的问题并不知道属性名称是什么,正如你的问题所述,而是存储在该属性中的数据。

 class Pet: def __init__(self): self.hair = None self.color = None 

如果我使用hasattr来做到这一点,即使属性值是Nonetypes,它也会返回True ,这会导致我的ElementTree set命令失败。

 hasattr(temp, 'hair') >>True 

如果属性值的types为None ,那么getattr也会返回它,这会导致我的ElementTree set命令失败。

 c = getattr(temp, 'hair') type(c) >> NoneType 

现在我使用下面的方法来处理这些情况:

 def getRealAttr(class_obj, class_attr, default = ''): temp = getattr(class_obj, class_attr, default) if temp is None: temp = default elif type(temp) != str: temp = str(temp) return temp 

这是何时以及如何使用getattr

 # getattr class hithere(): def french(self): print 'bonjour' def english(self): print 'hello' def german(self): print 'hallo' def czech(self): print 'ahoj' def noidea(self): print 'unknown language' def dispatch(language): try: getattr(hithere(),language)() except: getattr(hithere(),'noidea')() # note, do better error handling than this dispatch('french') dispatch('english') dispatch('german') dispatch('czech') dispatch('spanish')