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

2024-12-03 08:44:00
admin
原创
154
摘要:问题描述:我读过一篇关于该功能的文章getattr,但我仍然不明白它是做什么用的。我唯一理解的getattr()是,这getattr(li, "pop")与调用是一样的li.pop。我什么时候以及如何使用它?书中提到了使用它来获取对直到运行时才知道名称的函数的引用,但是我什么时候以及为什么...

问题描述:

我读过一篇关于该功能的文章getattr,但我仍然不明白它是做什么用的。

我唯一理解的getattr()是,这getattr(li, "pop")与调用是一样的li.pop

我什么时候以及如何使用它?书中提到了使用它来获取对直到运行时才知道名称的函数的引用,但是我什么时候以及为什么要使用它呢?


解决方案 1:

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

例如,您有一个对象person,它具有几个属性:namegender等等。

您可以通过以下方式访问这些属性(方法或数据对象):person.name,,,等等person.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

您可以使用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

它的一个实际用途是查找所有名称以 开头的方法test并调用它们。

类似于getattr允许setattr您设置具有其名称的对象的属性:

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

解决方案 2:

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

只有两种情况才有getattr用。

  • 您不能写object.x,因为您事先不知道想要哪个属性(它来自字符串)。对于元编程非常有用。

  • 您想提供一个默认值。如果没有,object.y则会引发。但会返回。AttributeError`ygetattr(object, 'y', 5)5`

解决方案 3:

对我来说,getattr最简单的解释是这样的:

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

例如,您不能这样做:

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

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

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

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

解决方案 4:

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

例如,在 Django 或 Pylons 等 Web 框架中,getattr可以直接将 Web 请求的 URL 映射到将要处理该请求的函数。例如,如果您深入了解 Pylons 的路由,您会发现(至少默认情况下)它会将请求的 URL 切碎,例如:

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

分为“customers”和“list”。然后它搜索名为的控制器类CustomerController。假设它找到该类,它会创建该类的一个实例,然后使用它getattr来获取其list方法。然后它调用该方法,将请求作为参数传递给它。

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

解决方案 5:

这是一个简单而粗略的例子,说明一个类如何根据其在哪个操作系统上执行来触发不同版本的保存方法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()

解决方案 6:

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

设想

假设你的目录结构如下:

- superheroes.py
- properties.py

而且,您有函数可以获取ThorIron ManDoctor Strange中的信息superheroes.py。您可以非常聪明地将所有属性properties.py紧凑地记在 中dict,然后访问它们。

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在正确的地方使用以编写更干净的代码的见解。

解决方案 7:

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

解决方案 8:

我有时会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__(..),理想情况下,方法应该是关于类的概念状态,而不是一些实用程序计数器,它仅由函数的一种方法出于技术原因(例如优化)使用,并且与对象的含义无关。

解决方案 9:

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

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

如果我曾经这样做过,即使属性值是类型,hasattr它也会返回,这会导致我的 ElementTree命令失败。True`None`set

hasattr(temp, 'hair')
>>True

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

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

解决方案 10:

getattr() 的另一个用途是在 Python 中实现 switch 语句。它同时使用反射来获取 case 类型。

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

解决方案 11:

设置属性()

我们使用setattr为类实例添加属性。我们传递类实例、属性名称和值。

获取属性()

使用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)

解决方案 12:

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'

解决方案 13:

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

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

解决方案 14:

我已经在 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

解决方案 15:

getattr()可以使用classobject访问类属性。

例如有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)

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

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

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

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
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用