我最近读了关于getattr()函数的文章。问题是我仍然不能理解它的用法。我对getattr()的唯一理解是,getattr(li,“pop”)与调用li.pop相同。
我不理解书中提到如何使用它来获取函数的引用,而直到运行时才知道它的名称。也许这就是我在编程方面的新手。谁能解释一下这个问题?我何时以及如何使用它?
我最近读了关于getattr()函数的文章。问题是我仍然不能理解它的用法。我对getattr()的唯一理解是,getattr(li,“pop”)与调用li.pop相同。
我不理解书中提到如何使用它来获取函数的引用,而直到运行时才知道它的名称。也许这就是我在编程方面的新手。谁能解释一下这个问题?我何时以及如何使用它?
当前回答
Getattr (object, 'x')完全等价于object.x。
getattr只在两种情况下有用。
你不能写object。X,因为您事先不知道您想要哪个属性(它来自字符串)。对于元编程非常有用。 您需要提供一个默认值。对象。如果没有y, y将引发AttributeError。但是getattr(object, 'y', 5)将返回5。
其他回答
Python中的对象可以具有属性——数据属性和使用这些属性的函数(方法)。实际上,每个对象都有内置属性(在Python控制台中尝试dir(None), dir(True), dir(…),dir(dir))。
例如,你有一个对象人,它有几个属性:名字,性别等。
访问这些属性(无论是方法还是数据对象)通常需要写:person.name, person。性别、person.the_method()等。
但是,如果在编写程序时不知道属性的名称怎么办?例如,您将属性名存储在名为attr_name的变量中。
if
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
你可以使用getattr和dir来遍历所有属性名并获得它们的值:
>>> 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
这样做的一个实际用途是找到所有名称以test开头的方法并调用它们。
与getattr类似的还有setattr,它允许你设置一个对象的属性。
>>> setattr(person, 'name', 'Andrew')
>>> person.name # accessing instance attribute
'Andrew'
>>> Person.name # accessing class attribute
'Victor'
>>>
对我来说,getattr是最简单的解释方式:
它允许您根据字符串的内容调用方法,而不是键入方法名称。
例如,你不能这样做:
obj = MyObject()
for x in ['foo', 'bar']:
obj.x()
因为x不是内置类型,而是str。然而,你可以这样做:
obj = MyObject()
for x in ['foo', 'bar']:
getattr(obj, x)()
它允许您根据输入动态地连接对象。我发现它在处理自定义对象和模块时很有用。
除了这里所有令人惊叹的答案之外,还有一种方法可以使用getattr来节省大量代码行并保持舒适。这种想法源于代码的可怕表示,有时可能是必要的。
场景
假设你的目录结构如下:
- superheroes.py
- properties.py
你可以在superheroes。py中获得关于雷神,钢铁侠,奇异博士的信息。你很聪明地在一个紧凑字典的properties.py中写下它们的所有属性,然后访问它们。
properties.py
thor = {
'about': 'Asgardian god of thunder',
'weapon': 'Mjolnir',
'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
'weapon': 'Armor',
'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
'about': ' primary protector of Earth against magical and mystical threats',
'weapon': 'Magic',
'powers': ['magic', 'intellect', 'martial arts'],
}
现在,假设您希望在superheroes.py中按需返回它们各自的能力。有这样的函数
from .properties import thor, iron_man, doctor_strange
def get_thor_weapon():
return thor['weapon']
def get_iron_man_bio():
return iron_man['about']
def get_thor_powers():
return thor['powers']
...以及更多基于键和超级英雄返回不同值的函数。
在getattr的帮助下,你可以这样做:
from . import properties
def get_superhero_weapon(hero):
superhero = getattr(properties, hero)
return superhero['weapon']
def get_superhero_powers(hero):
superhero = getattr(properties, hero)
return superhero['powers']
你大大减少了代码行数、函数和重复!
哦,当然,如果你的变量有像properties_of_thor这样的坏名字,它们可以通过简单的操作来创建和访问
def get_superhero_weapon(hero):
superhero = 'properties_of_{}'.format(hero)
all_properties = getattr(properties, superhero)
return all_properties['weapon']
注意:对于这个特殊的问题,可以有更聪明的方法来处理这种情况,但是我们的想法是在正确的地方使用getattr来编写更清晰的代码。
getattr的一个非常常见的用例是将数据映射到函数。
例如,在Django或Pylons这样的web框架中,getattr可以直接将web请求的URL映射到将要处理它的函数。例如,如果你看一下Pylons的路由,你会发现(至少在默认情况下)它分割了一个请求的URL,比如:
http://www.example.com/customers/list
分为“客户”和“列表”。然后它搜索名为CustomerController的控制器类。假设它找到该类,它创建该类的实例,然后使用getattr获取其list方法。然后调用该方法,将请求作为参数传递给它。
一旦你掌握了这个思想,扩展web应用程序的功能就变得非常容易:只需向控制器类添加新的方法,然后在页面中创建链接,为这些方法使用适当的url。所有这些都是由getattr实现的。
getattr()在Python中实现switch语句的另一种用法。它使用两个反射来获取大小写类型。
import sys
class SwitchStatement(object):
""" a class to implement switch statement and a way to show how to use gettattr in Pythion"""
def case_1(self):
return "value for case_1"
def case_2(self):
return "value for case_2"
def case_3(self):
return "value for case_3"
def case_4(self):
return "value for case_4"
def case_value(self, case_type=1):
"""This is the main dispatchmethod, that uses gettattr"""
case_method = 'case_' + str(case_type)
# fetch the relevant method name
# Get the method from 'self'. Default to a lambda.
method = getattr(self, case_method, lambda: "Invalid case type")
# Call the method as we return it
return method()
def main(_):
switch = SwitchStatement()
print swtich.case_value(_)
if __name__ == '__main__':
main(int(sys.argv[1]))