Перехват изменений атрибутов в классах внутри класса - Python - PullRequest
3 голосов
/ 24 марта 2009

Я возился с pygame и python и хочу иметь возможность вызывать функцию, когда атрибут моего класса изменился. Мое текущее решение:

class ExampleClass(parentClass):
   def __init__(self):
      self.rect = pygame.rect.Rect(0,0,100,100)
   def __setattr__(self, name, value):
      parentClass.__setattr__(self,name,value)
      dofancystuff()
Firstclass = ExampleClass()

Это работает нормально, и вы можете вызвать вещи для галантереи, когда я изменяю значение прямоугольника с помощью Firsclass.rect = pygame.rect.Rect(0,0,100,100). Однако, если я скажу Firstclass.rect.bottom = 3. __setattr__ а там для галантерейных изделий не называется.

Итак, мой вопрос: как мне перехватить любое изменение атрибута подкласса?

edit: Также, если я поступаю неправильно, пожалуйста, скажите, что я не очень осведомлен, когда дело доходит до Python.

Ответы [ 4 ]

4 голосов
/ 24 марта 2009

Ну, простой ответ - ты не можешь. В случае Firstclass.rect = <...> ваш __setattr__ вызывается. Но в случае Firstclass.rect.bottom = 3 вызывается метод __setattr__ экземпляра Rect. Единственное решение, которое я вижу, - это создать производный класс pygame.rect.Rect, в котором вы перезаписываете метод __setattr__. Вы также можете обезьянить патч класса Rect, но это не рекомендуется по веским причинам.

1 голос
/ 07 апреля 2013

Это не ответ на вопрос, но это актуально:

self.__dict__[name] = value

, вероятно, лучше, чем

parentClass.__setattr__(self, name, value)

Это рекомендуется в документации Python (setattr "> http://docs.python.org/2/reference/datamodel.html?highlight=setattr#object.setattr) и в любом случае имеет больше смысла в общем случае, поскольку не предполагает ничего о поведении parentClass setattr .

Дай за незапрошенный совет на четыре года позже!

1 голос
/ 24 марта 2009

Вы можете попробовать __getattr__, который должен быть вызван на Firstclass.rect.

Но сделайте это вместо этого: создайте отдельный класс (подкласс pygame.rect?) Для ExampleClass.rect. Реализуйте __setattr__ в этом классе. Теперь вам сообщат обо всем, что установлено в вашем rect члене для ExampleClass. Вы все еще можете реализовать __setattr__ в ExampleClassдолжен ), только теперь убедитесь, что вы создали экземпляр своей собственной rect класса ...

Кстати: не называйте ваши объекты Firstclass, так как тогда это выглядит как класс, а не объект ...

0 голосов
/ 11 июля 2009

Я думаю, что причина, по которой вы испытываете эту трудность, заслуживает немного больше информации, чем предоставлено другими ответами.

Проблема в том, когда вы делаете:

myObject.attribute.thing = value

Вы не назначаете значение атрибуту. Код эквивалентен этому:

anAttribute = myObject.attribute
anAttribute.thing = value

Как видно из myObject, все, что вы делаете, получает атрибут; Вы не устанавливаете атрибут.

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

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

Необходимо соблюдать осторожность при выборе __ getattribute __ и __ getattr __ . См. Документацию, связанную в предыдущем предложении, для получения информации, но в основном, если используется __getattr__, фактические атрибуты будут как-то инкапсулированы / обфусцированы так, что __getattr__ обрабатывает запросы для них, а если используется __getattribute__, ему придется получать атрибуты через звонки в базовый класс.

Если все, что вы пытаетесь сделать, это определить, были ли обновлены некоторые из них, тогда это излишне.

...