0

我正在使用这里的代码片段以及我自己在 Ironpython 中的修改,效果非常好:

    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_property 类的使用对我来说是个谜。为了更好地理解代码,我尝试删除一个属性。从我的 MainViewModel 调用,它是上述类的子类,我可以通过以下方式定义一个属性:

add_notifiable_property('TestProperty')

或者

add_handled_property((TestProperty,[handler1,handler2])

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

del self.TestProperty

除了

undeletable attribute

delattr(self,'TestProperty')

除了

delattr takes exactly 2 arguments 2 given

嗯很奇怪。

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

def remove_notifiable_property(self,propertyname):
    ''' removes a notifiable property
    '''
    self._property_handlers.pop(propertyname,None)
    exec "del self.{0}".format(propertyname)

但是对于不可删除的属性会出现相同的错误。

如何再次删除设置的属性?

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

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

出现新错误:

Derived calss has no attribute _TestProperty

TestProperty 是我添加的名称。还是卡住了。

EDIT2:我将其追踪到以下内容:

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)

显示相同的行为。错误 no _ 来自缺少初始化属性。添加一个:

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

到 add_handled_property 的最后一行修复它。

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

4

1 回答 1

1

你应该能够做到

delattr(self.__class__, 'TestProperty')

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

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

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

>>> 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>)

你可以在课堂上替换它们

>>> A.p = 2 
>>> a.p
2

或从课堂上删除它们

>>> A.p = A.Property()
>>> del A.p
于 2013-05-15T15:37:28.123 回答