Accessing "private" variable behind python property - python

How do you access the "private" variable behind a Python property?
In the following code, I get Hello World instead of the World World that I expect. I would guess that the property has a different scope that results in self being different in the property than the module. If so, is there a way to access the underlying variable? Or is there a different idiom to use for "code outside the class should use a different getter than code in the class"?
class Foo():
def __init__(self):
self._x = 'Hello'
self.x = 'World'
#property
def x(self):
return self._x
#x.setter
def x(self, val):
self._x = val
foo = Foo()
print(foo._x)
print(foo.x)

You forgot to inherit from object, so you created an old-style class. property setters don't work for old-style classes. If you inherit from object, you get World from both prints, like you expected:
>>> class Foo(object):
... def __init__(self):
... self._x = 'Hello'
... self.x = 'World'
... #property
... def x(self):
... return self._x
... #x.setter
... def x(self, val):
... self._x = val
...
>>> foo = Foo()
>>> print foo._x
World
>>> print foo.x
World

You are accessing the private variable _x via foo._x.
What is typical in this situation is to not define the x attribute at all, i.e. remove the line self.x = 'World'. That way you are using the property x to access the attribute _x (and because privates aren't really private you can of course also access the attribute directly using _x).
Edit: the first part of my answer was misleading, see user2357112's answer for why you are not getting the expected output.

Related

How to use property setter as a callback

I'm working with a legacy system for which a Python interface has been added recently.
In my code, I get messages containing ASCII strings for attributes to be set in some wrapper classes.
I would like to use a dictionary to map "data labels" to property setter methods. Each property setter would be used as a "callback" when the corresponding data label is encountered in a message.
Using explicit setters/getters, the essential logic looks like this:
class A():
def __init__(self):
self._x = 1.2
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
myA = A()
myTable = {
'X' : myA.set_x,
}
label, value = get_message()
print(myA.get_x())
# label is 'X', value a float
myTable[label](value)
print(myA.get_x())
This works, but is a bit ugly. I would like to use the #property decorator, but then I don't know how to reference the setter method in the dictionary.
I.e. the following doesn't work.
class B():
def __init__(self):
self._x = 1.2
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
myB = B()
myTable = {
'X' : myB.x
}
label, value = get_message()
print(myB.x)
# doesn't work as expected
myTable[label] = value
# no change
print(myB.x)
Of course, the reference to property myB.x in the dictionary definition calls the getter, so a float value is associated to the 'X' key. The myTable[label] = value assignment just replaces this value, it doesn't call the setter.
So, is there a way to get a reference to the property setter to insert in the dictionary and to later invoke as a "callback"?
I dug in reference information and this answer, but can't figure out a solution by myself.
Or, am I getting it wrong and I should follow a different path? (Suggestions welcome).
To access the actual function, you have to access the property directly on the class, so:
In [1]: class B:
...: def __init__(self):
...: self._x = 1.2
...:
...: #property
...: def x(self):
...: return self._x
...:
...: #x.setter
...: def x(self, value):
...: self._x = value
...:
In [2]: B.x.fset
Out[2]: <function __main__.B.x(self, value)>
Since functions are descriptors, you can use their __get__ method to bind them and change them into a method:
In [4]: B.x.fset.__get__(b)(42)
In [5]: b.x
Out[5]: 42
So, something like:
In [6]: my_table = {'X':B.x.fset.__get__(b)}
In [7]: my_table['X']('foo')
In [8]: b.x
Out[8]: 'foo'
I'm coming to this several years late, but I have a similar situation, and building off of juanpa.arrivillaga's answer I came up with this to answer your follow-up question, which is maybe what you were really hoping for originally.
Basically, an instance of TestDevice can use its own class method and getattr to find and call the appropriate setter:
class TestDevice(object):
#classmethod
def set_property(cls, instance, property, value):
getattr(cls, property).fset(instance, value)
def __init__(self, x):
self.x = x
def apply_state(self, state):
for k, v in state.items():
self.set_property(self, k, v)
#property
def x(self):
return self._x
#x.setter
def x(self, v):
self._x = v
Which seems to do the trick:
>>> thing = TestDevice(5)
>>> thing.x
5
>>> new_state = {'x': 7}
>>> thing.apply_state(new_state)
>>> thing.x
7

What's the best way to inspect an attribute before setting it?

I have a need to inspect attributes before they are set†. A naive implementation would be something like:
class C(object):
x = 5
def __setattr__(self, name, value):
if hasattr(self, name):
x = getattr(self, name)
if x == 5:
print 'do something'
object.__setattr__(self, name , value)
However, this would trigger the class' __getattribute__ method, which must be avoid here. From what i can tell, searching in the class' __dict__ directly might do the trick; but as this is a class that's meant to be subclassed by the user, i imagine that __slots__ and the MRO could add complications down the road.
Given these considerations, what's the best way to inspect an attribute before setting it?
† In the interest of full disclosure, this class is actually going to be written as a C extension; however, i don't imagine the strategy deviating too much from the python implementation for that to matter.
How about using the property decorator?
class C(object):
def __init__(self):
self._x = 5 # Default, for all
# Future updates should be done with self.x = ...
# To go through the approval below
#property
def x(self):
return self._x
#x.setter
def x(self, value):
if value == 5:
print 'do something'
else:
self._x = value

Getting the name of the #property being accessed, set or deleted in Python

Is it possible in Python to get the name of property currently being accessed, modified for deleted inside the function? For example, I've got this code with some pseudo-code inside:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'x'
return self._x
#x.setter
def x(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'x'
return self._x
#property
def y(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'y'
return self._x
So the pseudo-code here is the get_current_property(), which should work inside of the getter, setter and deleter methods for each property. Any way to do this?
So, there is no way to make it easy and sexy. Only dirty-inspecty magic, my friend.
import inspect
class A(object):
#property
def b(self):
print inspect.stack()[0][3]
A().b
will give you result you want, but you should do it only if there is no way you can deal with your things.
Btw, you can try to make a decorator, which will take a function, take its __name__ and send it as argument.
Here is implementation of idea:
def named_property(func):
return property(lambda *a, **kwa: func(*a, fname=func.__name__, **kwa))
class A(object):
#named_property
def b(self, fname):
print fname
A().b # will print 'b'
As #Martijn Pieters said, there is no straightforward way for the method to get a reference to itself.
I'm trying to understand why the property definition (written by you) wouldn't already know its own name. I'm guessing that you want to do this so that you can create a bunch of properties programmatically without a separate explicit defitinition for each one.
Try something like this to build a new class dynamically while creating some of its properties from a list:
def make_getter_setter(name):
# this function uses an implicit closure to "freeze" the local value of name
# within the scope of the getter/setter functions
def getter(self):
return name
def setter(self):
pass # your original code doesn't make clear that the setter should actually do anything
return getter, setter
class C(object):
def __init__(self):
# dictionary to store the values of the properties
# this doesn't do anything now, but I presume you'll want to allow
# setting the properties later, and you'll need somewhere to store
# their values
self._properties = {}
for name in ('spam', 'eggs', 'ham'):
getter, setter = make_getter_setter(name)
setattr(C, name, property(getter, setter, doc="I'm the '%s' property" % name))
foo = C()
print foo.eggs, foo.ham # shows their values
help(foo) # shows their doc strings

Setting a variable python class - function [duplicate]

This question already has answers here:
Understanding __get__ and __set__ and Python descriptors
(8 answers)
Closed 8 years ago.
Is there a function such that i can write but as a function?
class foo:
def __init__(self,x):
self.x = x;
asd = foo(2);
asd.x = 5;
print(asd.x);
But like:
class foo:
def __init__(self,x):
self.x = x;
def someFunction(self,string,value):
if(string == 'x'):
self.x = value;
print("worked");
asd = foo(2);
asd.x = 3; #and "worked" will be printed?
I tried __ set __ and __ setattr __ but i had no luck ;\
Is there a way to call a function when setting a class variable?
asd.x = 3; calls a function?
Use a property. The method decorated by #property will be used whenever you try to access the attribute x; the method subsequently decorated by #x.setter will be called whenever you try to set the value of x. The underlying "private" attribute _x is used to store the value for x used by both the getter and setter.
class foo:
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
print("worked")
def __init__(self, x):
self._x = x
The decorator syntax can be skipped if you want more explicit names for the getter and setter methods:
class foo(object):
def __init__(self, x):
self._x = x
def _get_x(self):
return self._x
def _set_x(self, value):
self._x = value
print("worked")
x = property(_get_x, _set_x)
For an object to handle setting of attributes on itself, use the __setattr__ method. It's rather tricky to debug, so don't do this unless you know what you're doing. Good explanation
source
class Beer(object):
def __init__(self, adj):
self.adj = adj
def __setattr__(self, key, value):
print '\tSET',key,value
object.__setattr__(self, key, value) # new style (don't use __dict__)
b = Beer('tasty')
print 'BEFORE',b.adj
b.adj = 'warm'
print 'AFTER',b.adj
print b.__dict__
output
SET adj tasty
BEFORE tasty
SET adj warm
AFTER warm
{'adj': 'warm'}

How do I do get/set method in Python (specifically Trac)

In C-ish languages, I'd mask data storage details with getter/setter methods/functions like:
int getFoo();
void setFoo(int value);
I have some Python that does:
class MyClass:
def Foo(self):
...magic to access foo...
return value
What's the right way to write/name a setter for Foo? I'm sure it's more idiom than language feature but I'm not sure what's common. Maybe I need to rename Foo() to getFoo() and match it with setFoo(). I guess that's OK if that's what is usually done.
You can use a property. This is pulled directly from the docs:
class C(object):
def __init__(self):
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
Now you can do...
c = C()
c.x = "a"
print c.x
>>> "a"
del c.x
Keep in mind that in Python versions prior to Python 3 (e.g., Python 2.7) you need to make sure that your object is a new-style class (it must derive from object) for it to support properties like this. Granted, you probably should be using new-style classes for all your classes anyway...
Use the builtin property function:
class MyClass:
def __init__(self):
self._value = 'Initialize self._value with some value or None'
def get_foo(self):
...magic to access foo...
return self._value
def set_foo(self, value):
... magic processing for value ...
self._value = value
foo = property(get_foo, set_foo)
Now you can use access it like this:
inst = MyClass()
inst.foo = 'Some value'
print inst.foo
It will print:
'Some value'
Generally you don't need to use getters and setters in Python.
If however, you want to expose the result of a procedure as a property, you can use the #property decorator:
class MyClass:
#property
def foo(self):
# operation
return value
#foo.setter
def foo(self, value):
# operation storing value
It is more common to just store the value of foo in an attribute. This can be calculated in the __init__ instance initializer:
class MyClass:
def __init__(self):
self.foo = someCalculationDeterminingFoo()

Categories