Я в своем уме. Не могу найти ничего другого, что поможет с этим.

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

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

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

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

3
Steve 8 Янв 2017 в 18:48

6 ответов

Лучший ответ

Словари Python не являются объектами JS. Когда вы создаете dict, вы не создаете динамический объект, свойства которого вы можете изменить во время выполнения, как в 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"))
5
Nikola Dimitroff 8 Янв 2017 в 16:04

Вы можете назначать значения dict напрямую, setattr () не требуется.

dta = {'type': "", 'content': ""}
dta["type"] = "Steve"
1
Maurice Meyer 8 Янв 2017 в 15:50

Словари подписаны, пары ключ-значение: предметы вместо атрибутов.

Доступ к элементам осуществляется с помощью индексной записи:

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

Атрибуты доступны с использованием точечной нотации

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

ФИЛЬМЫ ПОХОЖИЕ НА getattr:

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

>>> hasattr(d, '__getitem__')
True
>>> hasattr(d, '__getattr__')
False
>>> 
1
wwii 8 Янв 2017 в 16:19

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

Это аналог getattr (). Аргументы - это объект , строка и произвольное значение. Строка может назвать существующую атрибут или новый атрибут. Функция присваивает значение атрибут, если объект позволяет

ОБЪЕКТ НЕ СЛОВАРЬ. И я, вероятно, путаю свою работу JS (синтаксис) с кодом Python, который я всегда пишу одновременно

Так что сообщение об ошибке сбивает с толку:

AttributeError: у объекта 'dict' нет атрибута 'type'

Это должно быть больше похоже на:

'setattr () для объектов, а не словарей'

.

Спасибо всем.

0
Steve 8 Янв 2017 в 16:06

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

setattr устанавливает элемент в __dict__ из obj, и к полученному атрибуту можно получить доступ с помощью .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'

Я добавляю элементы в dict с помощью индексации словаря:

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.

Даже экземпляры с __dict_- могут вызвать ошибки, если setattr используется неправильно. Например, число не является допустимым именем атрибута:

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
1
hpaulj 8 Янв 2017 в 19:13

'setattr ()' относится к чему-то другому. Когда вы пишете setattr(dta, 'type', "Steve"), вы пытаетесь получить доступ к полю dta.type, класс dict не имеет атрибута type, поэтому выдает ошибку.

dict_object['key'] - это совсем другое, и именно так нужно обращаться к членам dict.

Подробнее оulfatr () здесь

1
Ginko 8 Янв 2017 в 15:56