class A():
def __init__(self):
self.__var = 5
def get_var(self):
return self.__var
def set_var(self, value):
self.__var = value
var = property(get_var, set_var)
a = A()
a.var = 10
print a.var == a._A__var
Can anyone explain why result is False?
The property decorator only works on new-style classes. In Python 2.x, you have to extend the object class:
class A(object):
def __init__(self):
self.__var = 5
def get_var(self):
return self.__var
def set_var(self, value):
self.__var = value
var = property(get_var, set_var)
Without the behavior of the new-style class, the assignment a.var = 10 just binds a new value (10) to a new member attribute a.var.
Related
The following piece of code:
class A:
def __init__(self):
self.__var = 123
def getV(self):
return self.__var
a = A()
a.__var = 10
print a.getVar(), a.__var
prints 123 10. Why does this behavior occur? I would expect a.getVar() to print out 10. Does the class internally interpret self.__var as self._A__var?
The double underscore attributes in Python has a special effect, it does "name mangling" that is it converts the attribute __var to _A__var i.e. _<classname>__<attributename> at runtime.
In your example when you assign 10 to the attribute __var of a object, it is essentially creating a new attribute __var and not modifying the self.__var. This is because the self.__var is now _A__var due to name mangling.
This can be seen if you print the __dict__ of the a object:
class A:
def __init__(self):
self.__var = 123
def getV(self):
return self.__var
a = A()
print (a.__dict__)
>> {'_A__var': 123}
If you don't assign any value to __var and try to print it directly, it will result in an AttributeError:
class A:
def __init__(self):
self.__var = 123
def getV(self):
return self.__var
a = A()
print (a.__var)
>> AttributeError: 'A' object has no attribute '__var'
Now if you try to assign to the new mangled attribute name, you would get the right result (but this process is meant to prevent accidental usage of such variables):
class A:
def __init__(self):
self.__var = 123
def getV(self):
return self.__var
a = A()
a._A__var = 10
print (a.getV())
>> 10
I have a class like this
class Test:
def __init__(self, var):
self.var = var
def test(self):
x = self.var + 2
return x
And then I make a class like this
class Test:
def __init__(self, var):
self.var = var
def test(self):
self.x = self.var + 2
return self.x
I understand that I can use self to separate attribute values across various instances of this class. My question is, if I create many utility variables (like x) inside a method, should I always create them using self?
Can anyone explain how the above two classes behave differently (if they do)?
Let's see the difference between the two classes :
class Test:
def __init__(self, var):
self.var = var
def test(self):
x = self.var + 2
return x
Let's create a Test object:
t = Test(1)
And see what we can do
t.var # 1
t.x # Raises AttributeError : no such attribute in the class
t.test() #3
t.x # Still erroring
And with your second class
class Test:
def __init__(self, var):
self.var = var
def test(self):
self.x = self.var + 2
return self.x
Let's create a Test object:
t = Test(1)
And see what we can do
t.var # 1
t.x # Raises AttributeError : no such attribute in the class
t.test() #3
t.x # 3
So what ? Well we can see that any variables defined with self.VARNAME persist in the instance, while simple local variables, without self., dosen't.
However, if x needs to be accessible with t.x, i'd probably go for a property, like so
class Test:
def __init__(self, var):
self.var = var
#property
def x(self):
x = self.var + 2
return x
t = Test()
t.x # 3
class A(object):
__A = None
def get_a(self):
return self.__A
def set_a(self, value):
self.__A = value
class B(A):
def method_b(self, value):
self.set_a(value)
class C(A):
def method_c(self)
self.get_a()
Someone can to explain me how can i to catch installed value in method_b inside my 'C' class method?
P.S. In this variant i just getting nothing.
Python isn't Java; you don't need setters & getters here: just access the attributes directly.
There are three problems with your code.
C.method_c() has no return statement, so it returns None.
You are using __ name mangling when that's exactly what you don't want.
In A.set_a() you want to set a class attribute, but your assignment instead creates an instance attribute which shadows the class attribute.
Here's a repaired version.
class A(object):
_A = 'nothing'
def get_a(self):
return self._A
def set_a(self, value):
A._A = value
class B(A):
def method_b(self, value):
self.set_a(value)
class C(A):
def method_c(self):
return self.get_a()
b = B()
c = C()
print(c.method_c())
b.method_b(13)
print(c.method_c())
output
nothing
13
Here's a slightly more Pythonic version:
class A(object):
_A = 'nothing'
class B(A):
def method_b(self, value):
A._A = value
class C(A):
pass
b = B()
c = C()
print(c._A)
b.method_b(13)
print(c._A)
I have a class where I want to validate the data whenever it's property is changed. I wish to store the valid options as a class variable that the setter can refer to, but I seem to have found that within the #var.setter option I'm unable to reference any class variables at all.
Why is that?
Code example:
class Standard():
def __init__(self):
self.variable1 = 1
self.variable2 = 2
#property
def variable1(self):
# This works
print(self.variable2)
return self.__variable1
#variable1.setter
def variable1(self, var):
# This doesn't work
print(self.variable2)
self.__variable1 = var
x = Standard()
print(x.variable1)
x.variable1 = 4
print(x.variable1)
This outputs:
AttributeError: 'Standard' object has no attribute 'variable2'
When it clearly does.
You are first setting variable1 in __init__:
def __init__(self):
self.variable1 = 1
self.variable2 = 2
Since self.variable1 is handled by #variable1.setter, variable2 can't yet exist at that time. You could swap the two lines:
def __init__(self):
self.variable2 = 2
self.variable1 = 1
Now variable2 is properly set before variable1.setter runs.
Alternatively, give variable2 a class attribute to act as a default:
class Standard():
# ...
variable2 = 'class default'
#variable1.setter
def variable1(self, var):
print(self.variable2)
self.__variable1 = var
or use getattr() on self:
#variable1.setter
def variable1(self, var):
print(getattr(self, 'variable2', 'not available yet'))
self.__variable1 = var
or set __variable1 directly, bypassing the setter:
class Standard():
def __init__(self):
self.__variable1 = 1 # don't use the setter
self.variable2 = 2
For example:
class Example:
def __init__(self):
self.v = 0
#property
def value(self):
return self.v
#value.setter
def value(self, v):
self.v = v
class SubExample(Example):
pass
Would it be possible to rewrite just the getter to value in SubExample?
You can do so like this
class DoubleExample(Example):
#Example.value.getter
def value(self):
return self.v * 2
o = Example()
o.value = 1
print o.value # prints "1"
p = DoubleExample()
p.value = 1
print p.value # prints "2"
However, this only works if Example is a new-style class (class Example(object):) rather than an old style class (class Example:), as it is in your example code.
Warning: Thomas pointed out in the comments that this method may not behave as expected if you're using multiple inheritance (class Foo(Bar, Baz)).
It isn't possible to override a property's getter in a subclass, no. The property is an object that lives in the class and that holds references to the functions you give it -- if you later redefine the names of those functions, it won't affect the property at all.
What you can do is have the functions your property calls perform indirect calls, like so:
class Example(object):
def __init__(self):
self.v = 0
#property
def v(self):
return self._v_getter()
#v.setter
def v(self, value):
return self._v_setter(value)
def _v_setter(self, value):
self._v = value
class SubExample(Example):
def _v_getter(self):
return 5
>>> se = SubExample()
>>> se.v
5
>>> se._v
0
>>> se.v = 10
>>> se.v
5
>>> se._v
10
Alternatively, you can redefine the entire property in the subclass, by simply defining a new property. You won't have convenient access to the functions or property defined in the parentclass, however, and doing the right thing in the face of multiple inheritance is difficult.
Your question has been answered before:
http://code.activestate.com/recipes/408713-late-binding-properties-allowing-subclasses-to-ove/
http://stackoverflow.com/questions/3393534/python-property-and-method-override-issue-why-subclass-property-still-calls-the
Essentially, instead of using property directly, you have to defer calling the getter so that it will access the one defined in the subclass rather than the one defined in the superclass when you first defined the property. This can be achieved via a lambda:
class Test(object):
def __init__(self):
self.v = 0
def _value(self):
return self.v
def _value_setter(self, v):
self.v = v
value = property(lambda self: self._value(), lambda self, v: self._value_setter(v))
class Test2(Test):
def _value(self):
return self.v + 1
a = Test()
a.value = 2
print a.value # 2
b = Test2()
b.value = 2
print b.value # 4