2009-05-19 3 views
1

Я хотел бы сериализовать объекты Python в формате plist (и это можно сделать с помощью plistlib). Моя идея состояла в том, чтобы написать класс PlistObject который оборачивает других объектов:Обтекание объекта Python

def __init__(self, anObject): 
    self.theObject = anObject 

и обеспечивает «писать» метод:

def write(self, pathOrFile): 
    plistlib.writeToPlist(self.theObject.__dict__, pathOrFile) 

Теперь было бы неплохо, если бы PlistObject вела себя просто нравится завернутые сам объект, что все атрибуты и методы каким-то образом «перенаправляются» на обернутый объект. Я понимаю, что методы __getattr__ и __setattr__ могут быть использован для сложных операций атрибутов:

def __getattr__(self, name): 
     return self.theObject.__getattr__(name) 

Но тогда, конечно, я бег в проблему, что конструктор теперь производит бесконечную рекурсию, так и self.theObject = anObject пытается получить доступ к обернутому объекту ,

Как я могу избежать этого? Скажите мне, что вся идея кажется плохим.

+2

Вы считали, что все ваши классы наследуются от PlistObject? –

+0

Да, это была бы альтернатива. Я не уверен, какое решение имеет больше преимуществ. –

ответ

2

Но тогда, конечно, я столкнулся с проблемой, что конструктор теперь создает бесконечную рекурсию, так как self.theObject = anObject пытается получить доступ к обернутому объекту.

Именно поэтому руководство предлагает вам сделать это для всех «реальных» атрибутов доступа.

theobj = object.__getattribute__(self, "theObject") 
3

Если я что-то не хватает, это будет прекрасно работать:

def __getattr__(self, name): 
    return getattr(self.theObject, name) 

Edit: для тех, кто думает, что поиск в self.theObject приведет к бесконечным рекурсивным вызовом __getattr__, позвольте мне показать вам:

>>> class Test: 
...  a = "a" 
...  def __init__(self): 
...   self.b = "b" 
...  def __getattr__(self, name): 
...   return 'Custom: %s' % name 
... 
>>> Test.a 
'a' 
>>> Test().a 
'a' 
>>> Test().b 
'b' 
>>> Test().c 
'Custom: c' 

__getattr__ называется только lastresort. С theObject можно найти в __dict__, никаких проблем не возникает.

+0

Это не так. Внутри __getattr__ необходимо найти self.theObject. поэтому он вызывает __getattr__, что приводит к бесконечному циклу. –

+0

Нет, он не нужен __getattr__, потому что объект объекта находится в __dict__. Я обновил ответ на примере. – Stephan202

1

Я рад видеть, что другие смогли помочь вам с рекурсивным призывом к __getattr__. Поскольку вы просили комментировать общий подход сериализации к plist, я просто хотел перезвонить с несколькими мыслями.

Реализация plist Python обрабатывает только базовые типы и не предоставляет механизма расширения для инструкций по сериализации/десериализации сложных типов. Если вы определяете собственный класс, например, writePlist не сможет помочь, как вы обнаружили, так как вы передаете __dict__ экземпляра для сериализации.

Это имеет несколько последствий:

  1. Вы не сможете использовать это, чтобы сериализовать любые объекты, которые содержат другие объекты неосновного типа без преобразования их в __dict__, и так на рекурсивно для всего сетевого графика.

  2. Если вы перевернете свой собственный сетевой граф-ходок для сериализации всех неосновных объектов, которые могут быть достигнуты, вам придется беспокоиться о кругах на графике, где один объект имеет другое свойство, которое, в свою очередь, содержит ссылка на первую и т. д. и т. д.

Учитывая, что вы можете рассмотреть рассол вместо этого, поскольку он может обрабатывать все это и многое другое. Если вам нужен формат plist по другим причинам, и вы уверены, что можете придерживаться «простых» объектов dicts, тогда вы можете просто использовать простую функцию ... пытаясь, чтобы PlistObject макет каждой возможной функции в содержащемся объект - это лук с потенциально многими слоями, так как вам нужно обрабатывать все возможности обернутого экземпляра.

Что-то же просто, как это может быть более вещим, и сохранить удобство обернутого объекта более простого, не обернув его в первую очередь:

def to_plist(obj, f_handle): 
    writePlist(obj.__dict__, f_handle) 

Я знаю, что, кажется, не очень сексуально, но на мой взгляд, это намного более удобно, чем оболочка, учитывая жесткие пределы формата plist и, конечно, лучше, чем искусственное принуждение всех объектов в вашем приложении к наследованию из общего базового класса, когда в вашем бизнес-домене нет ничего, что фактически указывает на те Разнесенные объекты связаны.

+0

Спасибо за обширный комментарий. Pickle - это не вариант, так как мне нужен формат Plist. Я знаю, что оболочка не является общей и может обрабатывать только простые типы. На данный момент он работает нормально, но если у меня возникнут проблемы, я, вероятно, пойду за простую функцию, как вы предложили. –

Смежные вопросы