Установка атрибута класса с заданным именем в python при определении класса

Я пытаюсь сделать что-то вроде этого:

property = 'name'
value = Thing()
class A:
  setattr(A, property, value)
  other_thing = 'normal attribute'

  def __init__(self, etc)
    #etc..........

Но я не могу найти ссылку на класс, чтобы заставить setattr работать так же, как простое назначение переменной в определении класса. Как я могу это сделать?


person prismofeverything    schedule 25.03.2010    source источник
comment
Кстати, всегда наследуйте от object, а не от ничего (class A(object):), чтобы использовать классы нового стиля.   -  person Mike Graham    schedule 26.03.2010
comment
Это кажется намеренно запутанным. Почему атрибут не может иметь стабильное, понятное имя? В качестве альтернативы, почему этот атрибут не может быть просто ключом в словаре? Почему магия?   -  person S.Lott    schedule 26.03.2010
comment
Я использую appengine, и их свойства определены как переменные класса. Однако я генерирую администратора автоматически, поэтому у меня есть список имен свойств, которые будут использоваться в другом месте, которые я также хочу использовать для создания свойств, чтобы каждое свойство нужно было указывать только один раз. В основном я пытаюсь избежать добавления записи в список свойств, а затем добавления переменной в класс, когда на самом деле они имеют одно и то же имя и могут рассинхронизироваться.   -  person prismofeverything    schedule 26.03.2010


Ответы (4)


Для этого вам нужно использовать метакласс:

property = 'foo'
value = 'bar'

class MC(type):
  def __init__(cls, name, bases, dict):
    setattr(cls, property, value)
    super(MC, cls).__init__(name, bases, dict)

class C(object):
  __metaclass__ = MC

print C.foo
person Ignacio Vazquez-Abrams    schedule 25.03.2010
comment
Как передать параметр в такой файл a = MC(params) ( mc.py - это конкретный файл), __metaclass__ = MC(params) не работает? - person TomSawyer; 07.10.2017
comment
Если MC не является вызываемым, который возвращает метакласс, вы этого не сделаете. И метакласс будет установлен только при первом определении класса, поэтому это не способ установки динамического метакласса. - person Ignacio Vazquez-Abrams; 07.10.2017
comment
@TomSawyer: я знаю как минимум пару способов передать аргументы в метакласс. Предлагаем поискать здесь вопросы и ответы по теме. - person martineau; 18.06.2018
comment
используйте class C(object, metaclass=MC): pass в python3 - person zhy; 30.03.2021

Можно еще проще:

class A():
    vars()['key'] = 'value'

В отличие от предыдущего ответа, это решение хорошо работает с внешними метаклассами (например, моделями Django).

person Vitalik Verhovodov    schedule 16.12.2013
comment
Еще одно преимущество заключается в том, что он позволяет избежать проблем, вызванных изменением синтаксиса для определения метаклассов между Python 2 и 3, так что это более независимый от версии подход. Если вы думаете об этом, это фактически дает аргумент self (или cls) коду в определении класса. - person martineau; 18.06.2018
comment
Это отлично! Я часто хотел использовать setattr() для строящегося класса, например, при построении на основе таблицы множества похожих свойств. Раньше мне приходилось либо использовать метакласс, либо определять метод класса, который я вызываю сразу после закрытия самого определения класса. Я не знал о vars(). - person Eric Smith; 07.08.2019

Это может быть связано с тем, что класс A не полностью инициализируется, когда вы делаете там setattr(A, p, v).

Первое, что нужно попробовать, это просто переместить settattr вниз после закрытия блока class и посмотреть, работает ли это, например.

class A(object):
    pass

setattr(A, property, value)

В противном случае то, что Игнасио только что сказал о метаклассах.

person keturn    schedule 25.03.2010
comment
Это решение работает очень хорошо. Нет необходимости делать это в метаклассе, когда вы можете сделать это напрямую. - person Mike Graham; 26.03.2010
comment
Хотя это может показаться (очень немного) более сложным, как показывает @Vitalik Verhovodov в своем ответе, вы можете использовать vars() внутри самого тела класса, чтобы получить доступ к определяемому классу __dict__. Если у вас есть это, вы можете легко изменить его содержимое. - person martineau; 06.07.2018

Итак, я знаю, что это действительно старо и, вероятно, бьет дохлую лошадь, и, возможно, это было невозможно в то время, но я наткнулся на это, пытаясь решить свою собственную проблему.

Я понял, что это можно сделать без метаклассирования.

setattr принимает объект, имя доступа и значение. Ну, объект - это не имя класса, а конкретный экземпляр класса, который можно выполнить с помощью self.

class A(object):
    def __init__(self):
        self.a = 'i am a accessor'
        setattr(self, 'key', 'value')

a = A()
print a.a
print a.key
person StoneyD    schedule 19.04.2016
comment
Ваш код устанавливает атрибут экземпляра, что не то же самое, что определение атрибута класса, поскольку self является экземпляром класса A, а не самим классом. Другими словами, это не отвечает на заданный вопрос. - person martineau; 17.06.2018