2014-10-20 6 views
3

У меня есть два класса, один из которых наследует от другого:Как скопировать все атрибуты одного объекта Python в другой?

class DaParent(object): 
    name = '' 
    number = 0 

class DaChild(DaParent): 
    additional = '' 

я теперь создать родительский и изменить атрибуты:

parent = DaParent() 
parent.name = 'papa' 
parent.number = 123 

И с этой точки, я хочу, чтобы создать Ребенок, в котором я хочу скопировать все атрибуты из родителя. Я могу, конечно, сделать это так:

child = DaChild() 
child.name = parent.name 
child.number = parent.number 

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

Есть ли способ автоматически перенести атрибуты родительского объекта в новый дочерний объект? Все советы приветствуются!

[EDIT] Просто, чтобы объяснить ПОЧЕМУ, я хочу это сделать. Я использую Peewee ORM для взаимодействия с моей БД. Теперь я хочу пересмотреть таблицу (это означает, что если запись будет обновлена, я хочу сохранить все предыдущие версии). Способ, которым я намереваюсь это сделать, - это создать класс Person и класс PersonRevision, который наследует класс Person. Затем я переопределяю peewee save() method, чтобы не только сохранить объект Person, но и скопировать все атрибуты в объект PersonRevision и сохранить его. Поскольку я никогда не буду напрямую взаимодействовать с классом PersonRevision, мне не нужны тени или какие-либо причудливые вещи. Я просто хочу скопировать атрибуты и вызвать объект его метод save().

+3

ли вы действовать хотите ли вы, чтобы они были атрибутами * class *, а не * instance *? – jonrsharpe

+0

@jonrsharpe - Насколько я понимаю, они должны быть атрибутами экземпляра, поэтому атрибуты объекта, а не самого класса. – kramer65

+0

Это не ** то, что у вас есть сейчас - атрибуты, определенные внутри 'class', но вне метода экземпляра' def' - это атрибуты класса *. – jonrsharpe

ответ

7

Очевидное решение состоит в использовании композиции/делегирования вместо наследования:

class Parent(object): 
    def __init__(self, name, number): 
     self.name = name 
     self.number = number 


class Child(object): 
    def __init__(self, parent, other): 
     self.parent = parent 
     self.other = other 

    def __getattr__(self, name): 
     try: 
      return getattr(self.parent, name) 
     except AttributeError, e: 
      raise AttributeError("Child' object has no attribute '%s'" % name) 

p = Parent("Foo", 42) 
c = Child(p, "parrot") 
print c.name, c.number, c.other 
p.name = "Bar" 
print c.name, c.number, c.other 

Это, конечно, при условии, что вы действительно не хотите «копии», но «ссылки». Если вы действительно хотите получить копию, это также возможно, но это может получить сложно с изменяемыми типами:

import copy 

class Parent(object): 
    def __init__(self, name, number): 
     self.name = name 
     self.number = number 


class Child(object): 
    def __init__(self, parent, other): 
     # only copy instance attributes from parents 
     # and make a deepcopy to avoid unwanted side-effects 
     for k, v in parent.__dict__.items(): 
      self.__dict__[k] = copy.deepcopy(v) 
     self.other = other 

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

[прав.] Упорядочить по XY-проблеме. Реальный вопрос: «Как скопировать поля peewee.Model в другой peewee.Model. peewee использует дескрипторы (peewee.FieldDescriptor) для управления доступом к полям модели и хранения имен полей и определений в файле _meta.fields dict, поэтому самым простым решением является итерировать на _meta.fields ключей исходной модели и использовать getattr/setattr:

class RevisionMixin(object): 
    @classmethod 
    def copy(cls, source, **kw): 
     instance = cls(**kw) 
     for name in source._meta.fields: 
      value = getattr(source, name) 
      setattr(instance, name, value) 
     return instance 

class Person(peewee.Model): 
    # fields defintions here 


class PersonRevision(Person, RevisionMixin): 
    # additional fields definitions here 


p = Person(name="foo", number=42) 
r = PersonRevision.copy(p, whatelse="parrot") 

NB: непроверенный код, никогда не использовал peewee, есть, возможно, что-то лучше делать ...

0

Если вы собираетесь иметь одиночный родитель с мульти и дети должны быть обновлены, чтобы соответствовать родителям всякий раз, когда родитель изменяет, тогда вместо атрибутов родителя будут атрибуты класса, а «копирование» для детей будет автоматическим.

Если вы собираетесь иметь несколько родителей, и по крайней мере некоторые родители будут иметь ребенок, есть три варианта:

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