在Python中使用setattr()函数

88

我正在寻求有人解释如何使用以及不使用 setattr() 的基础知识。

我的问题是在尝试使用一个类方法/函数返回数据后,将其放入另一个方法/函数中。也许在这种情况下更简单的方法会更好,但我正在尝试了解类的工作原理/用法。这个问题似乎取决于 setattr(),而这是我尝试对其进行相当简单的使用。

虽然问题不完全相同,但我正在遵循Python The Hard Way, ex42 -第18-41行的while循环。

我尝试编写一个 \__init__() 并改用 getattr(),认为或许需要在类的命名空间中放置某些内容,但这似乎没有帮助。

#! /bin/python2.6

class HolyGrail(object):

    def __init__(self):
        self.start = 'start_at_init'

    # function definition in question:
    # TypeError: 'str' object is not callable

    def run_it(self):
        start = setattr(self, 'name', 'get_thing')
        start = self.name

        # Something wrong here?
        value_returned = start() #I believe this == self.get_thing()
        use_it(value_returned)

    """
    # alternate function definitions
    # NameError: global name 'start' is not defined

    def __init__(self):
        self.start = 'get_thing'

    def run_it(self):
        go_do_it = getattr(self, start)
        first_output = go_do_it()
        use_it(first_output)
    """

    def get_thing(self):
        return "The Knights Who Say ... Ni!"

    def use_it(self, x):
        print x
        print "We want a shrubbery!"

my_instance = HolyGrail()
my_instance.run_it()

感谢@Karl Knechtel,@Amber,@Chris Morgan的帮助。

我现在可以解释我的答案了!这需要我更好地掌握自我作为对象的理解。它是一个实例名称,附带一些属性。

该类可以是Town,然后getattr使用其名称查找房屋,以便您随时调用它,并在找不到房屋时提供不同的位置。 -- 使用getattr会有一个“名称”,您会去寻找它。使从一个函数到另一个函数的步骤变得动态。 作为奖励,您可能会拥有一个默认值,有助于获取备用的默认方法——例如连接失败或其他原因。

setattr建立一个房子并给它一个名字,以便稍后可以调用。 如果无法找到它,您可以重新建造这座房子或前往特定位置。 -- setattr创建属性名称,并给出或更改其值,以便稍后调用。 也许用户将声音关闭,则未来的方法将不会输出任何音频。

我可以用多种方式编写我的函数,但没有必要更改任何属性:

def run_it(self):
    yo = getattr(self, 'get_thing')
    answer = yo()
    setattr(self, 'deal_accepted', self.use_it) #really ott
    no = getattr(self, 'deal_accepted')
    no(answer)

正确修正的代码:

def run_it(self):
    value_returned = self.get_thing()
    self.use_it(value_returned)

9
setattr用于那些无法直接完成的情况。对于初学者来说,这些情况应该是不存在的。setattr(self, 'name', 'get_thing')的意思与self.name = 'get_thing'完全相同。 - Karl Knechtel
5
@monkut说的是三引号字符串(triple-quoted string),而不是文档字符串(docstring);"docstring" 只是指模块、类或函数定义中第一条语句(或对象的__doc__属性)中的字符串。 - Chris Morgan
2
你是对的。无论如何,不要使用字符串作为注释。 - monkut
1
@monkut,为什么不应该使用字符串作为注释? - Haleemur Ali
5
一般来说,注释的目的是为了澄清代码的操作,并不是作为程序输出的结果。被注释的行不会被解释器分析,因此不会影响运行时行为。创建字符串会消耗内存和处理时间。 - monkut
显示剩余2条评论
6个回答

108

Python 文档已经详细介绍了这个函数,就我所知。

setattr(object, name, value)

该函数是 getattr() 的对应函数。参数分别为一个对象、一个字符串和一个任意值。字符串可以是现有属性或新属性的名称。如果对象允许,则会将值分配给属性。例如,setattr(x, 'foobar', 123) 相当于 x.foobar = 123


14
如果点表示法如此简洁,那么为什么还要使用setattr呢? - Nostalg.io
38
name 不是字符串字面量时,这个技巧就很有用了。当你设置的属性是动态确定的时(例如在某些元编程形式中),它也非常实用。 - Chris Morgan
7
一个例子:for key in data: value = request.DATA.get(key) setattr(obj, key, value) < -- 遍历所有提供的POST数据,使用键作为字段,并将其赋值给obj。 - e.thompsy
3
@Chris Morgan,一些对象如何禁止使用 setattr ?例如,x = numpy.ones(3); setattr( x, "name", "xname" ) --> 引发 AttributeError 错误?(如果您愿意,我可以提一个新问题) - denis
3
setattr并不一定可以在一个对象上设置任何名称的属性。如果该类型使用了__dict__,那么可以,但是一个由固定属性集合组成的C语言创建的类型可能没有这个功能,或者从Python代码中定义了__slots__的类型也可能没有。在这种情况下,您可以使用setattr来设置可接受的属性,但其他属性将会产生AttributeError异常。 - Chris Morgan
显示剩余3条评论

85

你正在将self.name设置为字符串"get_thing",而不是函数get_thing

如果你想要self.name成为一个函数,那么你应该将它设置为一个函数:

setattr(self, 'name', self.get_thing)

然而,对于您的其他代码来说,这是完全不必要的,因为您可以直接调用它:

value_returned = self.get_thing()

我明白了!懂了!你只需要告诉Python函数在哪里,self!(所以getattr的_value_也是self.function)。谢谢你,Amber! - bounce
有没有一种方法可以在get_thing()函数内访问属性名称'name' - zml
据我所知,除非您再次在容器函数上使用 setattr,否则不会发生这种情况。 - bjd2385

14

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

7

除了其他答案,我发现setattr()的常见用例是在使用配置时。通常会从文件(.ini文件或其他文件)中解析配置到字典中。所以你最终会得到如下内容:

configs = {'memory': 2.5, 'colour': 'red', 'charge': 0, ... }

如果您想将这些配置分配给一个类进行存储和传递,可以通过简单的赋值来实现:
MyClass.memory = configs['memory']
MyClass.colour = configs['colour']
MyClass.charge = configs['charge']
...

然而,更简便且不那么冗长的方法是循环遍历配置,使用 setattr() 函数,示例如下:

for name, val in configs.items():
    setattr(MyClass, name, val)

只要你的字典键有正确的名称,这个方法将非常有效并且整洁。需要注意的是,字典键必须是字符串作为类对象的名称。

5

假设您想给之前未在代码中编写的实例分配属性。 setattr()正是这样做的。它需要类self的实例、要设置的键和值。

class Example:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

1
你的代码让我印象最深的是你将开始值设置为setattr的值。
start = setattr(self, 'name', 'get_thing')
start = self.name

# Something wrong here?
value_returned = start() #I believe this == self.get_thing()
use_it(value_returned)
setattr 的返回值是 None。它是一个执行任务但不返回值的操作。类似于调用 exit() 这样的函数,该操作只是运行而已。 从 shell 中输入 python 就可以看到。
a = exit() #exits your program

将a设置为print('x')的效果类似于exit和您的setattr,但调用a不会调用我们的方法。

a = print('15') #returns 15
a #returns None

如果你想要在类内调用setattr,你可以定义一个方法。

def setAtrrClassInstance(self,name,value):  #This returns None
    setattr(self,name,value)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接