2015-11-19 2 views
2

Я написал класс, как показано ниже. Я хочу добавить атрибут 'parent' в мой базовый класс Node. Мне было интересно, может ли кто-нибудь показать мне, как правильно это сделать. Мне дали указания о том, как это сделать, но я не совсем уверен, как написать синтаксис. Вот предлагаемый способ сделать это ...python parent child relationship class

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

class Node(object): 
    def __init__(self, name, attributes, children): 
     self.name = name 
     self.attributes = attributes if attributes is not None else {} 
     self.children = children if children is not None else [] 


class Camera(Node): 
    def __init__(self, name="", attributes=None, children=None, enabled=True): 
     super(Camera, self).__init__(name=name, attributes=attributes, children=children) 
     self.enabled = enabled 

обновленный

import weakref 

class Node(object): 
    _parent = None 

    def __init__(self, name, attributes, children, parent): 
     self.name = name 
     self.attributes = attributes if attributes is not None else {} 
     self.children = children if children is not None else [] 
     self.parent = parent 

     for child in children: 
      child.parent = self 

    @property 
    def parent(self): 
     return self._parent() if self._parent is not None else None 

    @parent.setter 
    def parent(self, newparent): 
     oldparent = self.parent 

     if newparent is oldparent: 
      return 
     if oldparent is not None: 
      oldparent.children.remove(self) 
     if self not in newparent.children: 
      newparent.children.append(self) 
     self._parent = weakref.ref(newparent) if newparent is not None else None 


class Camera(Node): 
    def __init__(self, name="", attributes=None, children=None, enabled=True, parent=None): 
     super(Camera, self).__init__(name=name, attributes=attributes, children=children, parent=parent) 
     self.enabled = enabled 




Camera() 
+0

Замечание: Вероятно, лучше использовать 'weakref.ref' или' weakref.proxy' для хранения атрибута '_parent' (мы предполагаем, что' parent' является 'свойством', поэтому соглашение в этом случае обычно для обозначения «реального» атрибута с префиксом подчеркивания). В противном случае ваши деревья гарантируют создание эталонных циклов, поэтому они не будут очищены детерминистически (и память просочится, если какая-либо гайка отключает циклический gc, или любой объект цикла имеет 'class' с финализатором' __del__', [на Python 3.3 и ранее, циклический gc не может справиться с этим] (https://docs.python.org/3/whatsnew/3.4.html#whatsnew-pep-442)). – ShadowRanger

+0

Что я надеялся сделать родителем камеры на другую камеру – JokerMartini

ответ

1

Пример кода, включающий weakref, чтобы избежать опорных циклов, которые могут задержать очистку (или предотвратить его полностью в некоторых случаях, particularly on Python 3.3 and earlier):

import weakref 

class Node: 
# If this is Python 2, you need to explicitly inherit from object to 
# be a new-style class with descriptor support (which allows properties), so 
# the class line would be: 
# class Node(object): 
# On Py3, it's implicit and can be omitted 

    # Ensure attribute readable so getter/setter don't need to use has/getattr 
    # Will be allocated per-instance when self.parent is assigned in __init__ 
    # So on Py3.3+, it will still get the compact key-sharing dicts for attributes 
    _parent = None 

    # Adding defaults for all values matching Camera for simplicity 
    def __init__(self, name='', attributes=None, children=None, parent=None): 
     self.name = name 
     self.attributes = attributes if attributes is not None else {} 
     self.children = children if children is not None else [] 
     self.parent = parent 
     for child in children: 
      child.parent = self 

    @property 
    def parent(self): 
     return self._parent() if self._parent is not None else None 

    @parent.setter 
    def parent(self, newparent): 
     oldparent = self.parent 
     # If setting to existing parent, then no-op 
     # Remove this check and early-out if you want to be able to move 
     # a node to the end of its parent's children by reassigning the same parent 
     if newparent is oldparent: 
      return 
     if oldparent is not None: 
      oldparent.children.remove(self) 
     if self not in newparent.children: 
      newparent.children.append(self) 
     self._parent = weakref.ref(newparent) if newparent is not None else None 

Как правило, чтобы избежать проблем с изменением родительского класса прототипов, я поставил дополнительный параметры для дочернего класса __init__ методы сначала, а не последние. Потому что я дал __init__ дефолтов по Camera, это делает Camera очень просто:

class Camera(Node): 
    def __init__(self, enabled=True, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     # On Py2, super isn't magic, so you need to be explicit unlike Py3: 
     # super(Camera, self).__init__(*args, **kwargs) 
     self.enabled = enabled 

Как вы можете видеть, перемещая Camera уникальный __init__ параметров на фронт, Camera может перестать обращать внимание на изменения в Node__init__; новый Camera работает с оригиналом Node или новым Node (который принимает parent и присваивает self.parent) просто отлично, потому что он менее плотно связан с точным упорядочением параметров. Обратите внимание, что это означает, что если enabled не передается позиционно, все аргументы должны передаваться по ключевому слову.

Прошу прокомментировать, если я допустил какие-либо ошибки, но это должно быть близко к правилу. В общем, у меня был класс Node, использующий аксессуар parent, чтобы упростить код, удалив трудность с правильной обработкой None (None не является слабым ссылоспособен).

+0

Я пошел вперед и обновил свой код выше, я вставил старый код. Я использую новый «супер» материал, как вы упомянули. извините за путаницу. Дайте мне знать, если это что-то изменит в вашем примере кода – JokerMartini

+0

, показывает ли ваш пример все, что упоминалось в начальном вопросе, который я выделил желтым? – JokerMartini

+0

@JokerMartini: Я изначально забыл о добавлении его в 'children' нового' parent', но сейчас он находится. Большая часть магии находится в методе '@ parent.setter'; всякий раз, когда вы назначаете 'n.parent = x', он вызывает этот метод с 'x' в качестве нового родителя, который будет использовать для вас маска' weakref', удаляет 'n' из своих предыдущих' parent' (если есть) 'children' и добавьте его в новый 'parent' (если не' None') 'children'. Я также добавил оптимизацию/правильность на раннем этапе для 'setter', так что переопределение одного и того же« родителя »снова и снова не делает ненужной работы. – ShadowRanger