我最近读了关于getattr()函数的文章。问题是我仍然不能理解它的用法。我对getattr()的唯一理解是,getattr(li,“pop”)与调用li.pop相同。
我不理解书中提到如何使用它来获取函数的引用,而直到运行时才知道它的名称。也许这就是我在编程方面的新手。谁能解释一下这个问题?我何时以及如何使用它?
我最近读了关于getattr()函数的文章。问题是我仍然不能理解它的用法。我对getattr()的唯一理解是,getattr(li,“pop”)与调用li.pop相同。
我不理解书中提到如何使用它来获取函数的引用,而直到运行时才知道它的名称。也许这就是我在编程方面的新手。谁能解释一下这个问题?我何时以及如何使用它?
当前回答
下面是一个快速而简单的示例,演示了一个类如何根据使用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()
其他回答
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'
>>>
我在Python2.7.17中尝试过
有些人已经回答了。不过我已经试过打电话了 getattr(obj, 'set_value'),这没有执行set_value方法,所以我改为getattr(obj, 'set_value')()——>这有助于调用相同的。
示例代码:
示例1:
class GETATT_VERIFY():
name = "siva"
def __init__(self):
print "Ok"
def set_value(self):
self.value = "myself"
print "oooh"
obj = GETATT_VERIFY()
print getattr(GETATT_VERIFY, 'name')
getattr(obj, 'set_value')()
print obj.value
我有时使用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)
The advantage of the second way is that n_calls_to_plot only appears around the place in the code where it is used. This is good for readability, because (1) you can immediately see what value it starts with when reading how it's used, (2) it doesn't introduce a distraction into the __init__(..) method, which ideally should be about the conceptual state of the class, rather than some utility counter that is only used by one of the function's methods for technical reasons, such as optimisation, and has nothing to do with the meaning of the object.
除了这里所有令人惊叹的答案之外,还有一种方法可以使用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来编写更清晰的代码。
setattr ()
我们使用setattr向类实例添加一个属性。我们传递类实例、属性名和值。
getattr ()
使用getattr可以检索这些值
例如
Employee = type("Employee", (object,), dict())
employee = Employee()
# Set salary to 1000
setattr(employee,"salary", 1000 )
# Get the Salary
value = getattr(employee, "salary")
print(value)