什么是 & 如何在 Python 中使用 getattr()?

What is & How to use getattr() in Python?

提问人:Terence Ponce 提问时间:11/2/2010 最后编辑:Super Kai - Kazuya ItoTerence Ponce 更新时间:9/21/2023 访问量:363205

问:

我读了一篇关于该函数的文章,但我仍然不明白它的用途。getattr

我唯一了解的是,这与呼叫相同。getattr()getattr(li, "pop")li.pop

我何时以及如何使用它?这本书说了一些关于使用它来引用一个函数,该函数的名称直到运行时才知道,但是我何时以及为什么要使用它?

Python 函数 内置 getattr 类属性

评论

0赞 Ignacio Vazquez-Abrams 11/2/2010
您在哪个部分遇到问题?属性作为字符串?一流的功能?
2赞 Terence Ponce 11/2/2010
我认为我的问题是理解getattr()的概念。我仍然不明白它的目的。
0赞 Alois Cochard 11/2/2010
@Terence我的回答不是更清楚了吗?
0赞 Terence Ponce 11/2/2010
@Alois,你的回答确实消除了我的一些疑虑,但我仍然不能完全理解 getattr() 的用途。
6赞 Terence Ponce 11/2/2010
@S.Lott,我做到了。文档只有定义,所以我对它的用法有点困惑。不过,在阅读了更多有关它的信息后,我现在理解了 getattr。

答:

16赞 Josh 11/2/2010 #1

这是一个快速而肮脏的例子,说明一个类如何根据它所使用的操作系统来触发不同版本的 save 方法。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()
45赞 Robert Rossney 11/2/2010 #2

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

例如,在像 Django 或 Pylons 这样的 Web 框架中,可以直接将 Web 请求的 URL 映射到将要处理它的函数。例如,如果你查看 Pylons 路由的底层,你会看到(至少在默认情况下)它会切碎请求的 URL,例如:getattr

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

进入“客户”和“列表”。然后,它搜索名为 的控制器类。假设它找到该类,它会创建该类的实例,然后用于获取其方法。然后,它调用该方法,将请求作为参数传递给它。CustomerControllergetattrlist

一旦你掌握了这个想法,扩展 Web 应用程序的功能就变得非常容易了:只需向控制器类添加新方法,然后在页面中创建使用这些方法的适当 URL 的链接。所有这一切都是通过 实现的。getattr

352赞 warvariuc 11/2/2010 #3

Python 中的对象可以具有属性——数据属性和函数来处理这些属性(方法)。实际上,每个对象都有内置属性(在 Python 控制台中尝试 , , , )。dir(None)dir(True)dir(...)dir(dir)

例如,您有一个对象 ,它有几个属性:、 等。personnamegender

您可以访问这些属性(无论是方法还是数据对象),通常以:、、等形式进行访问。person.nameperson.genderperson.the_method()

但是,如果您在编写程序时不知道属性的名称,该怎么办?例如,您将属性的名称存储在名为 的变量中。attr_name

如果

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

您可以与 dir 一起使用来遍历所有属性名称并获取其值:getattr

>>> 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'
>>>

评论

14赞 wpcarro 10/25/2016
所以在我看来,应该在 2 种情况下使用:1.当属性名称是变量(例如)内部的值时,以及 2.当我们需要为默认值使用第三个位置参数时(例如)。如果我看到一个场景,在我看来,它是相同的,这让我认为这更像是 Pythonic。这是对的吗?getattr(..)getattr(person, some_attr)getattr(person, 'age', 24)getattr(person, 'age')person.ageperson.age
1赞 qneill 7/19/2020
@wpcarro两者都是 Python 的惯用语,所以很难证明一个比另一个更 Pythonic。person.agegetattr(person, "age")
4赞 warvariuc 6/10/2021
“可读性很重要”。当然比.当您在变量中有属性名称时,使用我是有意义的。person.agegetattr(person, "age")getattr
124赞 NuclearPeon 8/31/2013 #4

对我来说,最容易这样解释:getattr

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

例如,您不能这样做:

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

因为 x 不是 的类型,而是 。但是,您可以这样做:builtinstr

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

它允许您根据输入动态连接对象。我发现它在处理自定义对象和模块时很有用。

评论

4赞 user6037143 1/2/2019
这是一个非常直接和精确的答案。
0赞 develarist 9/16/2020
什么object.x
1赞 NuclearPeon 9/16/2020
@develarist 提问者没有示例供我回答,因此 、 和 (分别为 Class def、类实例和属性)只是示例/模型数据,您应该在其中填写您自己要访问的类和属性。,,并且通常用作 Linux/UNIX/FOSS 文档中的占位符。MyObjectobjxfoobarbaz
0赞 Rub 12/1/2021
operator.methodcaller( ) 旨在执行与本示例中相同的操作,调用用字符串定义的方法。我更喜欢示例中的实现。
4赞 Kduyehj 3/26/2015 #5
# 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')

评论

2赞 abarisone 3/26/2015
您能否详细说明您的答案,并添加有关您提供的解决方案的更多描述?
4赞 Evgeni Sergeev 6/11/2015 #6

我有时会在代码中使用次要属性之前延迟初始化它们。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)

第二种方式的优点是只出现在代码中使用它的位置周围。这有利于可读性,因为 (1) 在阅读它的使用方式时,您可以立即看到它以什么值开头,(2) 它不会在方法中引入干扰,理想情况下,方法应该是关于类的概念状态,而不是出于技术原因仅由函数方法之一使用的一些实用程序计数器, 例如优化,与对象的含义无关。n_calls_to_plot__init__(..)

3赞 btathalon 3/12/2016 #7

当我从存储在类中的数据创建XML文件时,如果该属性不存在或类型为。在这种情况下,我的问题不是不知道属性名称是什么,正如您的问题中所述,而是数据是否曾经存储在该属性中。None

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

如果我曾经这样做,即使属性值的类型为类型,它也会返回,这将导致我的 ElementTree 命令失败。hasattrTrueNoneset

hasattr(temp, 'hair')
>>True

如果属性值的类型为 ,也会返回它,这将导致我的 ElementTree 命令失败。Nonegetattrset

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

3赞 Jules Damji 1/29/2018 #8

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]))

评论

0赞 may 1/12/2020
我喜欢这个答案,但请纠正小错别字
8赞 unixia 5/9/2018 #9

除了这里所有惊人的答案之外,还有一种方法可以用来保存大量代码行并使其保持舒适。这个想法是在代码的可怕表示之后产生的,有时可能是必要的。getattr

场景

假设您的目录结构如下:

- superheroes.py
- properties.py

并且,您具有用于获取有关 、 的函数。你非常聪明地把它们所有的属性写在一个契约中,然后访问它们。ThorIron ManDoctor Strangesuperheroes.pyproperties.pydict

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

1赞 Barny 1/9/2019 #10

这也从 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”对象没有属性“”

235赞 blue_note 4/10/2019 #11

getattr(object, 'x') 完全等同于 .object.x

只有两种情况是有用的。getattr

  • 你不能写,因为你事先不知道你想要哪个属性(它来自一个字符串)。对于元编程非常有用。object.x
  • 您希望提供默认值。 如果没有,将提出一个.但会回来.object.yAttributeErrorygetattr(object, 'y', 5)5

评论

1赞 skoh 7/3/2020
我认为第二个要点与答案的开场白不一致,这是错误的吗?
4赞 blue_note 7/3/2020
@skoh:嗯,实际上,开场白提到了两个参数(这是等效的),第二个项目符号提到了带有 3 个参数的 getattr。即使它不连贯,我也可能会离开它,强调更重要。getattr
2赞 blue_note 8/22/2020
@UlfGjerdingen:想想 JavaScript。 等同于 。但是第二个表达式可以与任何可以在运行时决定的表达式一起使用(例如,从用户输入或对象检查),而在第一个表达式中,是固定的。o.xo['x']o[some_string]x
7赞 Michael 10/26/2020
为了恢复死灵,另一个用例是当标识符包含非法字符时,例如 or(正如我现在正在处理的那样)。 将在 obj.some.val 无法工作的地方工作。.-getattr(obj, 'some.val')
1赞 blue_note 9/6/2021
@JürgenK.:当然,它的行为就像任何其他对象一样,唯一的区别是它是自动传递的self
3赞 kuldeep Mishra 12/5/2019 #12

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)
0赞 siva balan 2/24/2020 #13

我已经在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
2赞 Dersu Giritlioğlu 4/16/2020 #14

我认为这个例子是不言自明的。它运行第一个参数的方法,其名称在第二个参数中给出。

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()
0赞 Super Kai - Kazuya Ito 9/21/2023 #15

getattr() 可以使用类和对象访问属性。

例如,下面有类:Test

class Test:
    class_variable = "Class variable"
    
    def __init__(self):
        self.instance_variable = "Instance variable"
    
    def instance_method(self, var):
        print(var)
        
    @classmethod
    def class_method(cls, var):
        print(var)
        
    @staticmethod
    def static_method(var):
        print(var)

然后,使用类和结果访问属性,如下所示:Testgetattr()

print(getattr(Test, "class_variable"))                  # Class variable
print(getattr(Test, "instance_variable"))               # Error

getattr(Test, "instance_method")("Instance method")     # Error
getattr(Test, "instance_method")("", "Instance method") # Instance method
getattr(Test, "class_method")("Class method")           # Class method
getattr(Test, "static_method")("Static method")         # Static method

print(getattr(Test, "my_variable"))                     # Error
print(getattr(Test, "my_variable", "Doesn't exist"))    # Doesn't exist

print(getattr(Test, "my_method")())                     # Error
print(getattr(Test, "my_method", "Doesn't exist")())    # Error
print(getattr(Test, "my_method", "Doesn't exist"))      # Doesn't exist

然后,使用对象和结果访问类属性,如下所示:Testgetattr()

obj = Test()
print(getattr(obj, "class_variable"))                  # Class variable
print(getattr(obj, "instance_variable"))               # Instance variable

getattr(obj, "instance_method")("Instance method")     # Instance method
getattr(obj, "instance_method")("", "Instance method") # Error
getattr(obj, "class_method")("Class method")           # Class method
getattr(obj, "static_method")("Static method")         # Static method

print(getattr(obj, "my_variable"))                     # Error
print(getattr(obj, "my_variable", "Doesn't exist"))    # Doesn't exist

print(getattr(obj, "my_method")())                     # Error
print(getattr(obj, "my_method", "Doesn't exist")())    # Error
print(getattr(obj, "my_method", "Doesn't exist"))      # Doesn't exist