removing a property in python - python

I am using a code snippet from here along with my own modifications in ironpython which works extremly well:
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])
Now I must admit that I not fully understand all of the code. Mainly the use of the Notify_property class is an enigma to me. To get a better understanding of the code I tried to remove a property. Calling from my MainViewModel which subclasses the above class I can define a property via:
add_notifiable_property('TestProperty')
or
add_handled_property((TestProperty,[handler1,handler2])
I can also delete handlers (not yet implemeted) but how to I remove a property again?
del self.TestProperty
excepts with
undeletable attribute
and
delattr(self,'TestProperty')
excepts with
delattr takes exactly 2 arguments 2 given
hmm very strange.
I also tried to add a function to my base class:
def remove_notifiable_property(self,propertyname):
''' removes a notifiable property
'''
self._property_handlers.pop(propertyname,None)
exec "del self.{0}".format(propertyname)
but get the same error about an undeletable attribute.
How can I remove a set property again?
EDIT: I found out I was missing the deleter function. Adding this code to the above dnp string now leads to a new error:
#{0}.deleter
def {0}(self):
del self._{0}
with new error:
Derived calss has no attribute _TestProperty
with TestProperty being the name I added. Still stuck.
EDIT2:
I tracked it down to the following:
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)
shows the same behavior. The error no _ came from missing initializing the attribute. Adding an:
exec """self._{0} = None""".format(symbol)
to the last line of the add_handled_property fixes it.
But still the attribute itself is shown with dir, also it is not in the class anymore. Is this a bug in python?

You should be able to do
delattr(self.__class__, 'TestProperty')
because the properties are in the class's __dict__. See the last line:
setattr(self.__class__, symbol, d[symbol])
Example of how properties work in Python using the class A, instance a and property p in the class A:
>>> 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>)
you can replace them in the class
>>> A.p = 2
>>> a.p
2
or delete them from the class
>>> A.p = A.Property()
>>> del A.p

Related

Can a python class method have as arguments the same class variable updated in init(self)?

I have two python classes
class A:
"""
This is a class retaining some constants
"""
C=1
class B:
VAR = None
def __init__(self):
b.VAR = A
def f(self, v=VAR ):
print(v.C)
clb = B()
clb .f()
AttributeError: 'NoneType' object has no attribute 'C'
So what I am trying to do is populate the B::VAR class variable in the B::init() with the reference of class A, and after that in the B::f() to have access to A::C by using default argument v (that retains VAR).
I intend to use v as a default value for the code inside B::f() and if needed to change it when calling the function.
Is my scenario possible?
Thank you,
Yes, this is possible:
class A:
"""
This is a class retaining some constants
"""
C = 1
class B:
VAR = None
def __init__(self):
self.VAR = A
def f(self, v=None):
if v is None:
v = self.VAR
print(v.C)
clb = B()
clb.f()
You issue is that the default arguments v=VAR is an old reference to the B.VAR which is None, not the updated value of the object clb.VAR.
This diagram show that the old version of f() have a default value for v that point to None, because this is computed at the definition of the method, when the class B is defined, before any creation of clb: B object, where VAR is a class attribute.
My suggestion is to set v at runtime using the VAR of the object throught self, which is changed in the __init__ to A.
class A:
C = 1
class B:
VAR = None
def __init__(self):
B.VAR = A
#classmethod
def f(cls):
print(cls.VAR.C)
clb = B()
clb.f()
This is another way to do it. However, I'm wondering what it is you're actually trying to do, because this seems really strange

Call specific variable in function

Somebody can help me how to access specific variable from other function in Python?
class A:
me = None
def __init__(self):
self.me = self.me
def something(self, other):
other = other
self.me = "its me to change"
return other #this function just return 'other' only.
def call_me(self):
something = A().something
print something.__get__(self.me) #get variable 'self.me' only from function of 'something'
A().call_me()
We need only show self.me in my function of call_me(self):
So, if we call A().call_me(), the output is its me to change.
Edit:
class A:
def something(self, other):
other = other
me = "its me to change"
return other
def call_me(self):
something = A().something
#get variable 'me' only from function of something
A().call_me()
Looks like you did not fully understand how Python objects work.
class A:
me = None
Here, you declare a attribute of class A, what would be called a static attribute in other OO languages => it is shared between all objects of the class
class A:
...
def __init__(self):
self.me = self.me
Almost a no-op: you override the static attribute A.me with an object attribute with same name and same value. The only effect if that when you create an object of class A it has a private copy:
>>> a = A()
>>> id(a.me) = id(A.me) # same value ?
True
>>> id(a.me) is id(A.me) # same object
False
Let's continue
class A:
...
def something(self, other):
other = other
self.me = "its me to change"
return other #this function just return 'other' only.
other = other is really a no-op
self.me = ... sets the value of the object attribute me - you can now access this new value in any other method as self.me or from the outside as a.me (if a is an object of class A) - if would be the same even if you had not done self.me = self.me in __init__
Last but not least:
class A:
...
def call_me(self):
something = A().something
print something.__get__(self.me) # ???
something = A().something: declares a new object of class A and make the local variable something point to the something method of that object - as the variable is local to the method, that new object will be destroyed on method exit
print something.__get__(self.me): does nothing, as you never call the something method, so just display, so you get:
>>> a = A() # create an object a of class A
>>> a.call_me() # call call_me method on that object
<bound method A.something of <__main__.A instance at ...>>
>>> A().call_me() # directly call `call_me` on a temporary object
...
TypeError: __get__(None, None) is invalid
because in first case you just print the local variable something as self is a valid object (a), while in second case it is just a temporary
I assume that want you wanted is simply:
class A:
def something(self, other):
self.me = "its me to change" # sets the attribute 'me'
return other #this function just return 'other' only.
def call_me(self):
self.something(None) # call something on self => sets self.me
print self.me #get variable 'self.me' after setting it in 'something'
You get now as expected:
>>> A().call_me()
its me to change

How to override a method of a member object?

In python 3.4 I have a member object through composition.
I would like to override one of it's member functions.
def class Foo:
def __init__(self, value):
self.value = value
def member_obj.baz(baz_self, arg):
print("my new actions on {}".format(arg))
Foo.member_obj.baz(arg) #the original function
foo_inst = Foo(2)
bar = Bar(*bar_parameters) #from a third party module
setattr(foo_inst, "member_obj", bar) #it did not "stick" when I did foo_inst.member_obj = bar
foo_inst.member_obj.baz("some argument")
It does not make sense to inherit from the Bar class.
I also only want this different behaviour to occur if the object is inside Foo. I use Bar in many other places and would like to retain the same way of calling the method. I.e. I would like to avoid wrapping it in Foo.baz.
Is it even possible to do something like the def member_obj.baz and is it a good idea?
It would be similar to this: https://softwareengineering.stackexchange.com/questions/150973/what-are-the-alternatives-to-overriding-a-method-when-using-composition-instea
Are you trying to do something like this?
class B():
def __init__(self):
self.x = None
def fun(self):
print("Assigning value to attribute of object of class B.\n")
self.x = "Value of B object's attribute"
class A():
def __init__(self):
self.value = B()
def fun(self):
print("Screw this, I'll do something else this time!\n")
self.value.x = 13
def override(self):
# Edit: you can assign any identifier (that is not reserved) to
# any type of object or method AND the "fun" ("really self.fun")
# above is visible from here, since we passed "self" as an
# argument
self.value.fun = self.fun
myObj = B()
myOtherObj = A()
myOtherObj.override()
myObj.fun()
myOtherObj.value.fun()

Python class #property: use setter but evade getter?

In python classes, the #property is a nice decorator that avoids using explicit setter and getter functions. However, it comes at a cost of an overhead 2-5 times that of a "classical" class function. In my case, this is quite OK in the case of setting a property, where the overhead is insignificant compared to the processing that needs to be done when setting.
However, I need no processing when getting the property. It is always just "return self.property". Is there an elegant way to use the setter but not using the getter, without needing to use a different internal variable?
Just to illustrate, the class below has the property "var" which refers to the internal variable "_var". It takes longer to call "var" than "_var" but it would be nice if developers and users alike could just use "var" without having to keep track of "_var" too.
class MyClass(object):
def __init__(self):
self._var = None
# the property "var". First the getter, then the setter
#property
def var(self):
return self._var
#var.setter
def var(self, newValue):
self._var = newValue
#... and a lot of other stuff here
# Use "var" a lot! How to avoid the overhead of the getter and not to call self._var!
def useAttribute(self):
for i in xrange(100000):
self.var == 'something'
For those interested, on my pc calling "var" takes 204 ns on average while calling "_var" takes 44 ns on average.
Don't use a property in this case. A property object is a data descriptor, which means that any access to instance.var will invoke that descriptor and Python will never look for an attribute on the instance itself.
You have two options: use the .__setattr__() hook or build a descriptor that only implements .__set__.
Using the .__setattr__() hook
class MyClass(object):
var = 'foo'
def __setattr__(self, name, value):
if name == 'var':
print "Setting var!"
# do something with `value` here, like you would in a
# setter.
value = 'Set to ' + value
super(MyClass, self).__setattr__(name, value)
Now normal attribute lookups are used when reading .var but when assigning to .var the __setattr__ method is invoked instead, letting you intercept value and adjust it as needed.
Demo:
>>> mc = MyClass()
>>> mc.var
'foo'
>>> mc.var = 'bar'
Setting var!
>>> mc.var
'Set to bar'
A setter descriptor
A setter descriptor would only intercept variable assignment:
class SetterProperty(object):
def __init__(self, func, doc=None):
self.func = func
self.__doc__ = doc if doc is not None else func.__doc__
def __set__(self, obj, value):
return self.func(obj, value)
class Foo(object):
#SetterProperty
def var(self, value):
print 'Setting var!'
self.__dict__['var'] = value
Note how we need to assign to the instance .__dict__ attribute to prevent invoking the setter again.
Demo:
>>> f = Foo()
>>> f.var = 'spam'
Setting var!
>>> f.var = 'ham'
Setting var!
>>> f.var
'ham'
>>> f.var = 'biggles'
Setting var!
>>> f.var
'biggles'
property python docs: https://docs.python.org/2/howto/descriptor.html#properties
class MyClass(object):
def __init__(self):
self._var = None
# only setter
def var(self, newValue):
self._var = newValue
var = property(None, var)
c = MyClass()
c.var = 3
print ('ok')
print (c.var)
output:
ok
Traceback (most recent call last):
File "Untitled.py", line 15, in <module>
print c.var
AttributeError: unreadable attribute
The #WeizhongTu answer
class MyClass(object):
def __init__(self):
self._var = None
# only setter
def var(self, newValue):
self._var = newValue
var = property(None, var)
c = MyClass()
c.var = 3
print ('ok')
print (c.var)
Is fine, except from the fact that is making the variable ungettable...
A similar solution but preserving getter is with
var = property(lambda self: self._var, var)
instead of
var = property(None, var)
The accepted answer's setter descriptor would be probably more convenient if it set the property by itself:
A setter descriptor (alt.)
class setter:
def __init__(self, func, doc=None):
self.func = func
self.__doc__ = doc or func.__doc__
def __set__(self, obj, value):
obj.__dict__[self.func.__name__] = self.func(obj, value)
class Foo:
#setter
def var(self, value):
print('Setting var!')
# validations and/or operations on received value
if not isinstance(value, str):
raise ValueError('`var` must be a string')
value = value.capitalize()
# returns property value
return value
Demo:
>>> f = Foo()
>>> f.var = 'spam'
Setting var!
>>> f.var = 'ham'
Setting var!
>>> f.var
'Ham'
>>> f.var = 'biggles'
Setting var!
>>> f.var
'Biggles'
>>> f.var = 3
ValueError: `var` must be a string

Access parents variables in Python

I have something like this:
class SomeObject:
#code to access parents MyVar
class MyClass:
MyVar = 3
MyObject = SomeObject()
I need to access MyVar from inside MyObject. Is there any way I can do that?
Thank you!
You can store a reference to the MyClass object in the SomeObject. You can initialise the reference when you make an constructor with a MyClass Object as parameter.
class SomeObject:
def __init__(self, reference):
self.reference_=reference
#code to access parents MyVar
self.reference_.MyVar=5
class MyClass:
MyVar = 3
MyObject = SomeObject(self)
As unutbu stated my code was not running, therefore a more detailed example.
class SomeObject:
def __init__(self):
self.reference_=None
def connect(self, reference):
self.reference_=reference
#code to access parents MyVar
def call(self):
self.reference_.MyVar=5
class MyClass:
MyVar = 3
MyObject = SomeObject()
def connect(self):
self.MyObject.connect(self)
if __name__ == '__main__':
myclass = MyClass()
myclass.connect()
myclass.MyObject.call()
print(myclass.MyVar)
You have to store a reference to your parent, but you can make that magic happen automatically:
from weakref import ref
class MyClass(object):
def __setattr__(self, key, value):
self.__dict__[key] = value
try:
value._parent = ref(self)
except AttributeError:
raise TypeError('MyClass cannot have children of type ' +
type(value).__name__)
def __delattr__(self, key):
v = self.__dict__[key]
del self.__dict__[key]
try:
v._parent = None
except AttributeError:
raise TypeError('Child of MyClass is mysteriously '
'missing its parent')
class SomeObject(object):
_parent = None
#property
def parent(self):
if self._parent is not None:
return self._parent()
return None
>>> a = MyClass()
>>> a.b = SomeObject()
>>> print a.b.parent
<__main__.MyClass at 0x8ce60f0>
>>> b = a.b
>>> del a.b
>>> print b.parent
None
By overriding the __setattr__ and __delattr__ operators you can control the child's view of its parent and make sure that the connection is always correct. Furthermore, this avoids using clumsy add/remove methods; methods you may accidentally forget to use. This restricts your objects to having exactly one parent, but for these types of models, that is generally desirable.
Lastly, I recommend that rather than holding a reference to the parent object directly, you hold a weak reference. This avoids cyclic references that may confuse the garbage collector (a holds a reference to b, which holds a reference to a. Their reference count never goes to 0, so they aren't garbage collected).

Categories

Resources