【问题标题】:Python setattr() can't find attribute that obviously existsPython setattr() 找不到明显存在的属性
【发布时间】:2017-05-22 22:00:55
【问题描述】:

我已经束手无策了。 找不到任何其他对此有帮助的东西。

dta = {'type': "", 'content': ""}
print dta

>>>{'content': '', 'type': ''}

setattr(dta, 'type', "Steve")

>>>AttributeError: 'dict' object has no attribute 'type'

【问题讨论】:

  • 如果你不能做dta.type,那么你应该不能用setattr设置它。
  • 存储在字典中的键与属性不同。
  • 字典的键不是属性。但是创建一个属性可以通过索引语法和属性语法访问的对象很容易。

标签: python setattribute setattr


【解决方案1】:

Python 的字典不是 JS 对象。当你创建一个字典时,你并不是在创建一个动态对象,你可以像在 JS 中那样在运行时更改其属性。相反,字典知道如何存储键和值对,并通过覆盖运算符 [] (def __getitem__(self, key)) 来实现。

在更高的实现级别上 - 调用 getattr / setattr 实际上是 data.__getattr__("foo") 的简写,并且由于 dict 使用 __getitem__ 而不是 __getattr__,因此函数调用失败。

因此,无法使用通用属性函数设置(或获取)dict 的项目。

然而,您可以创建支持该操作的自定义 dict 类(尽管我不推荐它):

class AttrDict(dict):
    def __init__(self):
        dict.__init__(self)

    # Override getattr and setattr so that they return the values of getitem / setitem
    def __setattr__(self, name, value):
        self[name] = value

    def __getattr__(self, name):
        return self[name]

data = AttrDict()
data["foo"] = "bar"
print(getattr(data, "foo"))

【讨论】:

  • 我完全不理解你。我正在 python 控制台中执行此操作。 setattr() 是一个标准的 Python 库函数,专门用于更改字典属性的值。
  • 不,不是。 setattr 是一个内置函数,专门用于更改对象属性的值,而不是字典值。
  • 知道了。 OBJECT 不是 DICT。而且我可能会将我的 JS 工作(语法)与我总是同时编写的 Python 代码混淆
  • @Steve 没错!请参阅我的编辑以获取更多解释。
【解决方案2】:

setattr 不适用于字典,因为它没有__dict__

我可以创建一个简单的类和实例:

In [88]: class Obj(object):
    ...:     pass
    ...: 
In [89]: ob = Obj()
In [90]: ob.__dict__
Out[90]: {}
In [91]: setattr(ob,'test',34)
In [92]: ob.__dict__
Out[92]: {'test': 34}
In [95]: ob.test
Out[95]: 34

setattrobj__dict__ 中设置一个项目,结果属性可以通过.test 语法访问。

但是dict 对象没有__dict__

In [96]: dd={1:2, 3:4}
In [97]: dd.__dict__
AttributeError: 'dict' object has no attribute '__dict__'

In [98]: setattr(dd, 'test', 34)
AttributeError: 'dict' object has no attribute 'test'

我使用字典索引符号将项目添加到字典:

In [99]: dd['test'] = 34
In [100]: dd
Out[100]: {1: 2, 3: 4, 'test': 34}

字典类继承自object,但不会给每个实例一个__dict__。因此setattr 没有什么可操作的。

如果由于某种原因[]= 语法很尴尬,您可以将operator.setitem 用作函数:

In [108]: operator.setitem?
Docstring: setitem(a, b, c) -- Same as a[b] = c.
Type:      builtin_function_or_method
In [109]: operator.setitem(dd, 'test', 23)
In [110]: dd
Out[110]: {1: 2, 3: 4, 'test': 23}

或者使用__setitem__方法

In [111]: dd.__setitem__('test', 1)
In [112]: dd
Out[112]: {1: 2, 3: 4, 'test': 1}

实际上,字典确实有属性。例如,它的.get 方法可以用getattr 获取。 setattr 在此示例中返回不同的错误。

In [119]: getattr(dd,'get')
Out[119]: <function dict.get>
In [120]: setattr(dd,'get',dict.get)
...
AttributeError: 'dict' object attribute 'get' is read-only

没有__dict__,我们无法向字典添加属性。许多(如果不是全部)现有属性是只读的。不知道字典有没有可以改变的属性。

其实字典就是object:

In [121]: isinstance(dd,dict)
Out[121]: True
In [122]: isinstance(dd,object)
Out[122]: True

我刚刚导入了defaultdict。它也缺少__dict__。但我可以使用setattr(ddd,'default_factory', int)。我认为no attribute是当属性不存在时正确的错误信息,它不能添加新的。

==============

我必须仔细检查这方面的文档,但我认为 setattr(dd,...) 代表 dd.__setattr__(...)

In [168]: dd.__setattr__('test',1)
...
AttributeError: 'dict' object has no attribute 'test'

In [169]: dd.__setattr__('get',None)
...
AttributeError: 'dict' object attribute 'get' is read-only

所以错误信息是由dict类确定的,而不是setattr

如果setattr 使用错误,即使具有__dict_- 的实例也可能引发错误。例如,数字不是有效的属性名称:

In [171]: setattr(ob, 123, 'a')
....
TypeError: attribute name must be string, not 'int'

但是setattr可以设置不能用.语法访问的属性:

In [172]: setattr(ob, 'a#re',1)
In [174]: ob.a#re
...
AttributeError: 'Obj' object has no attribute 'a'
In [175]: getattr(ob, 'a#re')
Out[175]: 1

vars() 是访问实例的__dict__ 的另一种方式:

In [179]: vars(dd)
 ...
TypeError: vars() argument must have __dict__ attribute

【讨论】:

  • 如果setattr(obj, attr, val) 先做一个测试if (type obj == 'dict') throw error "'obj ' is not an object" 就好了。那会有多方便?
  • 如果你 s = { "qwe": "asd" }print type s 你得到 &gt; &gt; &gt; type dict 所以如果你无意中将一个 dict(即 s)传递给 setattr() 但它需要一个对象然后 setattr() 应该测试this 并抛出一个关于缺少对象参数值的错误。相反,它所做的是抛出一个错误,即在您请求的字典中找不到属性。
  • 实际上是字典__setattr__方法产生了你的错误。
  • 我不明白为什么我不能做 setattr(object(), "test", 1),但我可以用 setattr(Obj(), "test", 1")你的 Obj 类。Obj() 类是空的,为什么我可以扩展它而不是 object()?
  • @Samuel 你试过object().__dict__ 吗? Obj 类没有添加任何方法,但它仍然是带有__dict__ 的用户定义类。
【解决方案3】:

可以直接给dict赋值,不需要setattr()。

dta = {'type': "", 'content': ""}
dta["type"] = "Steve"

【讨论】:

  • 是的。我知道。但我在其他地方成功使用了 setattr() 。一致性很重要。关于我的 setattr() 的任何想法都失败了? .... .... 在重新输入时,我意识到“类型”是保留字。会这样吗?
  • 快速测试。错误不是由于“类型”是保留字
  • Setattr,无法为字典键赋值。查看文档类型/类/setattr ...
  • docs.python.org/2/library/functions.html#setattr 这是 getattr() 的对应物。参数是一个对象、一个字符串和一个任意值。该字符串可以命名现有属性或新属性。如果对象允许,该函数将值分配给属性。例如,setattr(x, 'foobar', 123) 等价于 x.foobar = 123。
  • 知道了。 OBJECT 不是 DICT
【解决方案4】:

'setattr()' 指的是别的东西。当你写setattr(dta, 'type', "Steve")时,你试图访问字段dta.type,dict类没有type属性,所以会报错。

dict_object['key'] 是完全不同的东西,它应该是访问 dict 成员的方式。

更多关于 settatr() Here

【讨论】:

    【解决方案5】:

    字典是subscriptable,键:值对是项目而不是属性。

    使用下标符号访问项目:

    >>> d = {'a':1, 'b':2}
    >>> d['a']
    1
    

    Attributes are accessed using dot notation

    >>> d.a
    Traceback (most recent call last):
      File "<pyshell#3>", line 1, in <module>
        d.a
    AttributeError: 'dict' object has no attribute 'a'
    

    operator.itemgetter 类似于 getattr:

    >>> import operator
    >>> bee = operator.itemgetter('b')
    >>> bee(d)
    2
    >>>  
    

    >>> hasattr(d, '__getitem__')
    True
    >>> hasattr(d, '__getattr__')
    False
    >>> 
    

    【讨论】:

      【解决方案6】:

      docs.python.org/2/library/functions.html#setattr

      这是 getattr() 的对应物。参数是一个对象, 一个字符串和一个任意值。该字符串可以命名一个现有的 属性或新属性。该函数将值分配给 属性,前提是 object 允许

      OBJECT 不是字典。而且我可能会将我的 JS 工作(语法)与我总是同时编写的 Python 代码混淆

      所以错误信息很混乱:

      AttributeError: 'dict' 对象没有属性 'type'

      应该更像:

      'setattr() 用于对象而不是字典'

      .

      谢谢大家。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-23
        • 2019-10-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多