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') |
因为属性在类的
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 |