我最近读了关于getattr()函数的文章。问题是我仍然不能理解它的用法。我对getattr()的唯一理解是,getattr(li,“pop”)与调用li.pop相同。
我不理解书中提到如何使用它来获取函数的引用,而直到运行时才知道它的名称。也许这就是我在编程方面的新手。谁能解释一下这个问题?我何时以及如何使用它?
我最近读了关于getattr()函数的文章。问题是我仍然不能理解它的用法。我对getattr()的唯一理解是,getattr(li,“pop”)与调用li.pop相同。
我不理解书中提到如何使用它来获取函数的引用,而直到运行时才知道它的名称。也许这就是我在编程方面的新手。谁能解释一下这个问题?我何时以及如何使用它?
当前回答
除了这里所有令人惊叹的答案之外,还有一种方法可以使用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实现的。
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
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')
它也从https://www.programiz.com/python-programming/methods/built-in/getattr澄清
class Person:
age = 23
name = "Adam"
person = Person()
print('The age is:', getattr(person, "age"))
print('The age is:', person.age)
年龄:23岁
年龄:23岁
class Person:
age = 23
name = "Adam"
person = Person()
# when default value is provided
print('The sex is:', getattr(person, 'sex', 'Male'))
# when no default value is provided
print('The sex is:', getattr(person, 'sex'))
性别:男性
AttributeError: 'Person'对象没有属性'sex'
下面是一个快速而简单的示例,演示了一个类如何根据使用getattr()执行的操作系统来触发save方法的不同版本。
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()