关于mvvm:删除python中的属性

removing a property in python

我在这里使用了一个代码片段以及我自己在Ironpython中所做的修改,这些修改非常有效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    from System.ComponentModel import INotifyPropertyChanged, PropertyChangedEventArgs
    from Library.pyevent import make_event

    class Notify_property(property):
        ''' defines a notifiable property
        '''

        def __init__(self, getter):
            def newgetter(slf):
                #return None when the property does not exist yet
                try:
                    return getter(slf)
                except AttributeError:
                    return None
            super(Notify_property, self).__init__(newgetter)

        def setter(self, setter):
            def newsetter(slf, newvalue):
                # do not change value if the new value is the same
                # trigger PropertyChanged event when value changes
                oldvalue = self.fget(slf)
                if oldvalue != newvalue:
                    setter(slf, newvalue)
                    slf.OnPropertyChanged(setter.__name__)
            return property(
                fget=self.fget,
                fset=newsetter,
                fdel=self.fdel,
                doc=self.__doc__)

    class NotifyPropertyChangedBase(INotifyPropertyChanged):
        ''' The base of the MVVM view model
        Here the bound properties are added in addition with its
        handlers.
        '''

        # handlers which get fired on any change register here
        PropertyChanged = None
        ''' handlers that only get fired on their property change register here
        they are organized in a dictionary with the property name as key and
        a list of handlers as value
        '''

        _property_handlers = {}

        def __init__(self):
            ''' we create an event for the property changed event
            '''

            self.PropertyChanged, self._propertyChangedCaller = make_event()

        def add_PropertyChanged(self, value):
            ''' helper function to wrap the += behaviour
            '''

            self.PropertyChanged += value

        def remove_PropertyChanged(self, value):
            ''' helper function to wrap the -= behaviour
            '''

            self.PropertyChanged -= value

        def OnPropertyChanged(self, propertyName):
            ''' gets fired on an property changed event
            '''

            if self.PropertyChanged is not None:
                self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))
            try:
                for property_handler in self._property_handlers[propertyName]:
                    property_handler(propertyName,PropertyChangedEventArgs(propertyName))
            except KeyError:
                pass

        def add_notifiable_property(self, notifiable_property):
            self.add_handled_property((notifiable_property,None))

        def add_notifiable_property_list(self, *symbols):
            for symbol in symbols:
                self.add_notifiable_property(symbol)

        def add_handled_property_list(self, *symbols):
            for symbol in symbols:
                self.add_handled_property(symbol)

        def add_handled_property(self, notifiable_property):
            symbol = notifiable_property[0]
            if notifiable_property[1] is not None:
                self._property_handlers[notifiable_property[0]] = notifiable_property[1]
            dnp ="""
    import sys
    sys.path.append(__file__)

    @Notify_property
    def {0}(self):
        return self._{0}

    @{0}.setter
    def {0}(self, value):
       self._{0} = value
   """
.format(symbol)
            d = globals()
            exec dnp.strip() in d
            setattr(self.__class__, symbol, d[symbol])

现在我必须承认我没有完全理解所有的代码。主要是使用notify_属性类对我来说是个谜。为了更好地理解代码,我试图删除一个属性。从我的MainViewModel调用,它是上述类的子类,我可以通过以下方式定义属性:

1
add_notifiable_property('TestProperty')

1
add_handled_property((TestProperty,[handler1,handler2])

我还可以删除处理程序(尚未实现),但如何再次删除属性?

1
del self.TestProperty

例外

1
undeletable attribute

1
delattr(self,'TestProperty')

例外

1
delattr takes exactly 2 arguments 2 given

嗯,很奇怪。

我还尝试向我的基类添加一个函数:

1
2
3
4
5
def remove_notifiable_property(self,propertyname):
    ''' removes a notifiable property
    '''

    self._property_handlers.pop(propertyname,None)
    exec"del self.{0}".format(propertyname)

但对于不可删除的属性也会有同样的错误。

如何再次删除集合属性?

编辑:我发现我缺少删除函数。将此代码添加到上述dnp字符串现在会导致一个新错误:

1
2
3
@{0}.deleter
def {0}(self):
    del self._{0}

出现新错误:

1
Derived calss has no attribute _TestProperty

其中testproperty是我添加的名称。还是卡住了。

编辑2:我追踪到如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class C(object):
    def __init__(self):
        pass#self._x = None

    @property
    def x(self):
       """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

c = C()
print dir(c)
c.x = 'A'
print c.x
print dir(c)
del c.x
print dir (c)

显示相同的行为。错误"否"是因为缺少初始化属性。添加:

1
exec"""self._{0} = None""".format(symbol)

添加处理的属性的最后一行修复了它。

但是属性本身仍然显示为dir,而且它不再在类中。这是Python中的bug吗?


你应该能做到

1
delattr(self.__class__, 'TestProperty')

因为属性在类的__dict__中。见最后一行:

1
setattr(self.__class__, symbol, d[symbol])

使用类A、实例A和类A中的属性P在Python中如何工作的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> class A(object):
    class Property(object):
        def __get__(*args):
            print 'get:', args
        def __set__(*args):
            print 'set:', args
        def __delete__(*args):
            print 'del:', args
    p = Property()


>>> A.p
get: (<__main__.Property object at 0x7f3e16da4690>, None, <class '__main__.A'>)
>>> a = A()
>>> a.p
get: (<__main__.Property object at 0x7f3e16da4690>, <__main__.A object at 0x7f3e16da4910>, <class '__main__.A'>)
>>> a.p = 3
set: (<__main__.Property object at 0x7f3e16da4690>, <__main__.A object at 0x7f3e16da4910>, 3)
>>> del a.p
del: (<__main__.Property object at 0x7f3e16da4690>, <__main__.A object at 0x7f3e16da4910>)

你可以在课堂上替换它们

1
2
3
>>> A.p = 2
>>> a.p
2

或者从课堂上删除它们

1
2
>>> A.p = A.Property()
>>> del A.p