2015-05-08 4 views
0

Вот ссылка на мой первый вопрос: Creating class instance from dictionary?
Так что я пытаюсь создать экземпляр класса из словаря, который содержит ключи, которых нет у класса. Например:Есть ли способ получить атрибуты экземпляра класса без создания экземпляра класса?

class MyClass(object): 
    def __init__(self, value1, value2): 
     self.attr1 = value1 
     self.attr2 = value2 

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'} 

Перед созданием экземпляра класса я должен удалить этот redundant_key из Словаре

dict.pop('redundant_key', None) 
new_instance = MyClass(**dict) 

Проблема заключается в том, что у меня есть несколько классов и несколько dicts с большим количеством ключей (у меня есть несколько ответов в формате json, которые представлены как dicts, и я хочу создавать объекты из этих json-ответов). Я уже нашел временное решение из предыдущего вопроса - как удалить избыточные ключи. Я могу создать новый Dict от старого Словаре только с ключами, которые мне нужны:

new_dict = {key: old_dict[key] for key in allowed_keys} 

Так вот код:

class MyClass(object): 
    def __init__(self, value1, value2): 
     self.attr1 = value1 
     self.attr2 = value2 

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'} 
new_instance = MyClass(**{key: dict[key] for key in allowed_keys}) 

Все, что мне нужно сейчас, чтобы получить allowed_keys. Итак, вопрос: есть ли способ получить атрибуты экземпляра класса без создания экземпляра класса?

+0

Во-первых, это невозможно, во-вторых, вы хотите получить аргументы функции, а не атрибуты экземпляра, которые возможны путем проверки. – Daniel

+0

Это технически невозможно, атрибуты могут быть добавлены и удалены динамически для экземпляров, поэтому нет смысла иметь их с фактическим экземпляром. Я не уверен, зачем вам это нужно, где определены 'allowed_keys'? – luk32

+0

@ Daniel Все, что мне нужно, это получить 'attr1' и' attr2' в 'allowed_keys', когда атрибуты attr1,' attr2' являются экземплярами класса – Demyanov

ответ

1

Если вы настаиваете на использовании слишком общего словаря для инициализации своего объекта, просто определите __init__, чтобы принять, но игнорировать дополнительные ключи.

class MyClass(object): 
    def __init__(self, attr1, attr2, **kwargs): 
     self.attr1 = attr1 
     self.attr2 = attr2 

d = {'attr1': 'value1', 'attr2': 'value2', 'extra_key': 'value3'} 
new_instance = MyClass(**d) 

Если вы не можете изменить __init__ (как представляется, в случае, если он наследует от декларативной базы SQLAlchemy), добавить дополнительный конструктор, чтобы принять все именованные аргументы, но выбрать те, которые вам необходимы.

class MyClass(Base): 
    @classmethod 
    def from_dict(cls, **kwargs): 
     # Let any KeyErrors propagate back to the caller. 
     # They're the one who forgot to make sure **kwargs 
     # contained the right keys. 
     value1 = kwargs['attr1'] 
     value2 = kwargs['attr2'] 
     return cls(value1, value2) 

new_instance = MyClass.from_dict(**d) 
+0

Вы нарушили одно из основных правил программирования Python, назвав переменную такой же, как встроенный ... – martineau

+0

Нет, я скопировал исходный код пользователя и не стал его менять. – chepner

1

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Это ответы на то, о чем спрашивал OP (получение атрибутов экземпляра), а не то, что им нужно. Кажется, что это список параметров конструктора.

Вы не можете делать то, что хотите. В атрибутах python динамически добавляются в экземпляр класса. Два экземпляра одного класса могут иметь разные атрибуты. Ну ... если быть точным, есть такие вещи, которые называются экземплярами, и класс атрибутов.

Атрибуты экземпляра - это те, которые связаны с экземпляром класса. Атрибуты класса связаны с его определением т.е. если вы написали (MyClass.foo)

Если вы посмотрите на пример, атрибуты добавляются во время __init__ на self поэтому они атрибуты экземпляра.

Что вы могли бы сделать, это создать правильный экземпляр и осмотрите его (смотрите на рисунке примере), обеспечивают статический список allowed_keys (например, в качестве атрибута класса), или каким-либо образом требуют allowed_keys в качестве параметра конструктора. Все это - обходные пути, так как то, что вам действительно нужно, невозможно. У них есть свои плюсы и минусы.

пример:

class MyClass(object): 
    def __init__(self, value1, value2): 
     self.attr1 = value1 
     self.attr2 = value2 

instance = MyClass(1,2)      # create a valid object 
instance_attributes = instance.__dict__.keys() # inspect it 
print(instance_attributes) 
+0

Мне не нужны атрибуты экземпляра класса. Мне нужны атрибуты, которые создавая в течение метода '__init__'. Есть ли способ получить атрибуты, которые добавляются во время метода' __init__'? – Demyanov

+0

Случай, когда _is_ понятие атрибутов класса - это когда класс имеет '__slots__', а не словарь атрибутов. – alexis

+0

Это решение может иметь побочные эффекты, не будет работать в каждом случае, и вам уже нужно знать параметры '__init__', чтобы инициализировать класс. – Daniel

1

Вот как сделать то, что вы пытаетесь сделать: Инстанцировать классы с соответствующими аргументами. Обратите внимание, что вы не изучаете атрибуты, созданные __init__, но аргументы, которые он принимает. Не имеет значения, что с ними делается - это не ваша забота, когда вы вызываете конструктор.

myparams = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'} 
usable = { k:v for k, v in myparams if k in MyClass.__init__.__code__.co_varnames } 
new_instance = MyClass(**usable) 

Для ясности я использовал отфильтрованное понимание словаря, но вы могли бы сделать это за один шаг, конечно.

PS. Обратите внимание, что у вас возникнет проблема, если один из ваших словарей содержит ключ self. :-) Вы можете захотеть отфильтровать его, если не можете доверять источнику данных.

+0

Это действительно хорошее решение, но проблема в том, что класс, который у меня есть, создается sqlalchemy. Я просто пишу его в соответствии с стилем определения декларативного класса. Итак, MyClass .__ init __.__ code __. Co_varnames возвращает что-то вроде этого '('self', 'kwargs', 'new_state')' и я просто не могу написать метод '__init__', так как хочу – Demyanov

+0

В этом случае ваш вопрос должен быть конкретным к sqalchemy! Вам придется копать вокруг своих внутренних компонентов, чтобы узнать, какие аргументы принимаются в интересующих вас классах. Возможно, что-то вы можете использовать (возможно, его инициализаторы имеют стандартный способ управления допустимыми аргументами ключевого слова), или не. В общем, вы не можете рассчитывать на то, что будет делать функция, без ее запуска или моделирования. – alexis

+0

Я также сильно подозреваю, что созданные атрибуты будут зависеть от аргументов ключевого слова, которые вы предоставляете, что означает, что даже если вы можете создать экземпляр конструктора без аргументов для создания экземпляра объекта-образца, вы не увидите все возможные атрибуты в экземпляре объекта. – alexis

1

Вы должны упомянуть, что вам нужны столбцы SQLAlchemy-Mapper-Class. Это намного проще:

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'} 
columns = YourTable.__table__.columns.keys() 
entry = YourTable(**{k: dict[k] for k in columns}) 
Смежные вопросы