Python 什么是getattr()以及如何使用它?

Python 什么是getattr()以及如何使用它?,python,getattr,Python,Getattr,我最近一直在工作。问题是我仍然不能理解它的用法。关于getattr()我唯一了解的是getattr(li,“pop”)与调用li.pop相同 我不明白书中提到如何在运行时才知道函数名的情况下使用它来获取对函数的引用。一般来说,这可能是我在编程方面的一个新手。有人能解释一下这个问题吗?什么时候以及如何准确地使用它?下面是一个简单的例子,说明了一个类如何根据使用getattr()在哪个操作系统上执行而触发不同版本的save方法 现在让我们在一个示例中使用这个类: logger = Log() #

我最近一直在工作。问题是我仍然不能理解它的用法。关于
getattr()
我唯一了解的是
getattr(li,“pop”)
与调用
li.pop
相同


我不明白书中提到如何在运行时才知道函数名的情况下使用它来获取对函数的引用。一般来说,这可能是我在编程方面的一个新手。有人能解释一下这个问题吗?什么时候以及如何准确地使用它?

下面是一个简单的例子,说明了一个类如何根据使用
getattr()
在哪个操作系统上执行而触发不同版本的save方法

现在让我们在一个示例中使用这个类:

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

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

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

http://www.example.com/customers/list
分为“客户”和“名单”。然后搜索名为
CustomerController
的控制器类。假设找到了该类,它将创建该类的一个实例,然后使用
getattr
获取其
list
方法。然后调用该方法,将请求作为参数传递给它


一旦你掌握了这个想法,扩展web应用程序的功能就变得非常容易:只需向控制器类添加新方法,然后在你的页面中创建链接,为这些方法使用合适的URL。所有这些都是通过Python中的对象可以具有属性(数据属性和与这些(方法)一起工作的函数)实现的。实际上,每个对象都有内置属性

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
例如,您有一个对象
person
,该对象有几个属性:
name
gender
,等等

您访问这些属性(无论是方法还是数据对象)时通常会写入:
person.name
person.gender
person.the_method()
,等等

但是如果在编写程序时不知道属性的名称呢?例如,属性名存储在名为
attr\u name
的变量中

如果

然后,不是写,

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
如果对象中不存在具有给定名称的属性,则将引发
AttributeError

>>> getattr(person, 'age')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'age'
您可以使用
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

对我来说,
getattr
是最简单的解释方式:

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

例如,您不能执行以下操作:

obj = MyObject()
for x in ['foo', 'bar']:
    obj.x()
因为x不是
builtin
类型,而是
str
。但是,您可以这样做:

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

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

我有时使用
getattr(..)
在代码中使用次要属性之前,惰性地初始化它们

# 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')
比较以下各项:

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\u calls\u to\u plot
仅出现在代码中使用它的地方。这有利于可读性,因为(1)在阅读如何使用它时,您可以立即看到它以什么值开始,(2)它不会给
\uuuuuu init\uuuu(…)
方法带来干扰,理想情况下,该方法应该是关于类的概念状态,而不是出于技术原因(如优化)仅由函数方法之一使用的某些实用计数器,与对象的含义无关。

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

class Pet:
    def __init__(self):
        self.hair = None
        self.color = None
如果使用
hasattr
执行此操作,即使属性值的类型为
None
,它也会返回
True
,这将导致我的ElementTree
set
命令失败

hasattr(temp, 'hair')
>>True
如果属性值的类型为
None
getattr
也将返回它,这将导致我的ElementTree
set
命令失败

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
这是我在Python中实现switch语句时使用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
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]))

除了这里所有令人惊讶的答案之外,还有一种方法可以使用
getattr
保存大量代码行并使其保持舒适。这种想法源于代码的可怕表现,有时可能是必要的

场景

假设您的目录结构如下所示:

- superheroes.py
- properties.py
此外,您还可以在
超级英雄.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'],
}
现在,假设您希望在
superheros.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']
你大大减少了
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']
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']
def get_superhero_weapon(hero):
    superhero = 'properties_of_{}'.format(hero)
    all_properties = getattr(properties, superhero)
    return all_properties['weapon']
class Person:
    age = 23
    name = "Adam"

person = Person()
print('The age is:', getattr(person, "age"))
print('The age is:', person.age)
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'))
Employee = type("Employee", (object,), dict())

employee = Employee()

# Set salary to 1000
setattr(employee,"salary", 1000 )

# Get the Salary
value = getattr(employee, "salary")

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