class ClassName(object):
"""
"""
def __init__(self, foo, bar):
"""
"""
self.foo = foo # read-write property
self.bar = bar # simple attribute
def _set_foo(self, value):
self._foo = value
def _get_foo(self):
return self._foo
foo = property(_get_foo, _set_foo)
a = ClassName(1,2)
#a._set_foo(3)
print a._get_foo()
When I print a._get_foo() the function _get_foo prints the variable self._foo .
But where does it come from?
self._foo and self.foo are different, aren't they?
EDIT: The problem is that I still not understand what property does. Give me some time.
Docs for property explain how it's supposed to be used. There is no difference between these lines:
self.foo = foo # read-write property
and
a.foo = 3
You're also not supposed to call setters and getters manually.
eta: if you don't understand what property does after looking at the examples provided in the docs and reading our answers, you perhaps should just abstain from using it. It really is not the most essential of Python's features. You might want to start with a simpler example, which is easy to understand:
>>> class ClassName(object):
def __init__(self, foo):
self.foo = foo
>>> a = ClassName(1, 2)
>>> a.foo
1
>>> a.foo = 42
>>> a.foo
42
I really recommend this site:
http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
A good explanation of the property-function.
You define foo to be a property with getters and setters.
Those getters and setters use the variable self._foo, since you coded it that way:
def _set_foo(self, value):
self._foo = value
In your case you would get a problem if you had a slightly different implementation:
class ClassName(object):
"""
"""
def __init__(self,):
"""
"""
pass
def _set_foo(self, value):
self._foo = value
def _get_foo(self):
return self._foo
foo = property(_get_foo, _set_foo)
a = ClassName()
print a.foo
-> AttributeError
b = ClassName()
b.foo = 1 # implicitely sets self._foo !
print b.foo
>> OK, this is 1
As it happens you indeed should set self.foo in the __init__ since the setter creates self._foo. (Or initialize self._foo in the __init__ directly of course).
So, where do self.foo and self._foo come from? It's explicit in the code. self.foo is a property, and self._foo is the variable in which you decided to keep the value of that property.
self._foo and self.foo would be different except that you have assigned the property you created to the name foo: foo = property(_get_foo, _set_foo).
So now you have two names defined foo which is property that is defined in terms of the methods _set_foo and _get_foo. You also have a name _foo defined but this is the same attribute used in _set_foo and _get_foo and therefore in property foo.
So you two names but only one object.
foo
/\
/ \
_set_foo _get_foo
\ /
\ /
_foo --> object
Note: For the example you have Python this is overkill, there is no need to use getter and setter methods unless they are going to have business logic in them. Just use an attribute named foo, you can always wrap that in a property in future without affecting client code if it turns out that you need some smarts around the access of the attribute.
Change your code to:
class ClassName(object):
def __init__(self, foo, bar):
self.foo = foo # read-write property
self.bar = bar # simple attribute
Both foo and bar are read write, if you need finer control you can then consider using a property.
According to your code, it "comes from" _set_foo. In your init, when you do self.foo = foo, that calls _set_foo(1), which performs self._foo = 1.
You can see this more clearly if you add a print statement inside _set_foo().
Related
Let's say I have a class defined as follow :
class Foo():
baz = None
def __init__(self, bar):
self.bar = bar
Now, in that example Foo.baz is None. Now let's say that this class attribute needs to be an instance of Foo like below:
class Foo():
baz = Foo("baz")
def __init__(self, bar):
self.bar = bar
How would I proceed?
Similarly, is there any way to create a "class property". I know I can assign a lambda function returning a new instance of the class to a class attribute, but I'd rather not have to write the parenthesis.
If you want to use the line baz = Foo("baz") inside a class even before defining Foo earlier; it's not possible ie Python will throw a NameError: name 'Foo' is not defined at you, but here's a workaround to achieve what you intend:
class Foo:
def __init__(self, bar):
self.bar = bar
Foo.baz=Foo('foo')
Now Foo.baz is an instance of the Foo class and also baz is a class attribute of the Foo class and hence will be inherited by all instances of the class as well:
myFoo = Foo('myFoo')
You can verify that myFoo.baz.bar is infact 'foo' and not 'myFoo'
print(myFoo.bar)
# myFoo
print(myFoo.baz.bar)
# foo
Also note that this will cause Foo.baz, Foo.baz.baz, Foo.baz.baz.baz etc. all to be a Foo object because Foo.baz has value Foo('foo') ie an object of Foo class and baz is also a class attribute of Foo.
A friend yesterday showed me the technique below for giving instance variables a default value in Python.
The class Foo has its own bar property, which is retrieved by default when looking up an attribute on an instance that does not exist. For instance, the following code snippet prints 4✱.
class Foo:
bar = 4
def __init__(self):
pass
def get_bar(self):
return self.bar
def set_bar(self, bar):
self.bar = bar
print(Foo().get_bar())
Initially, I was surprised that this worked. I thought the machinery for "falling back to a definition on the class" that converts/evaluates/defines foo_instance.get_bar to a bound method on class Foo and makes foo_instance.get_bar() meaningful was specific to functions and would fail in some way for a non-function.
That is not the case. The above code prints for as if bar had been set via self.bar = 4 in the __init__ method.
Is this construction idiomatic? The only arguments I can think of against it are that it breaks structural equality, potentially hides attributes of an objects that are "logically there" when debugging, and could mutate global state unintentionally if the default value is stateful.
✱ The getter and setter are only being used to demonstrate that Foo.bar is really intended to be a default value for foo_instance.bar and should not be interpreted as supporting the use of getters and setters in idiomatic Python.
We can let python do the hard work for us:
class Foo:
_bar = 4
#property
def bar(self):
print('getting _bar')
return self._bar
#bar.setter
def bar(self, value):
print('setting _bar')
self._bar = value
foo = Foo()
print(foo.bar) # 4
foo.bar = 6
print(foo.bar) # 6
I have one class (Bar) embedded inside another class (Foo).
class Foo():
class Bar():
def __init__(self):
self.a = 1
self.b = 2
...
self.z = 26
def __init__(self):
self.bar = Bar()
To access the attributes of class Bar, the user would need to the following:
>>> f = Foo()
>>> f.bar.a
1
How can I setup a short dot notation so that users can use BOTH:
>>> f.bar.a
1
and
>>> f.a
1
In my example, I'm trying to demonstrate that Bar class has a lot of variables. So I don't want to write a getter/setter for each one manually. So I was thinking to use the property() in a for loop like this:
def __init__(self):
self.bar = Bar()
# Allow shorter dot notation
for parm in self.bar.__dict__:
setattr(self, i, getattr(bar, i))
self.i = property(...)
But I'm unsure how to use property in this context without manually writing several setter functions.
Any suggestions on how to allow access to both shorter and longer notations?
That's what the __getattr__hook is ideally suited for:
class Foo:
# ...
def __getattr__(self, name):
return getattr(self.bar, name)
__getattr__ is only called for attributes that are missing; so only attributes that are not already present on instances of Foo() are passed to Foo().__getattr__(). The getattr() function then lets you use the same attribute name on self.bar; if the attribute doesn't exist there either, an AttributeError is thrown, as would be expected.
Is it at all possible to monkey patch the value of a #property of an instance of a class that I do not control?
class Foo:
#property
def bar(self):
return here().be['dragons']
f = Foo()
print(f.bar) # baz
f.bar = 42 # MAGIC!
print(f.bar) # 42
Obviously the above would produce an error when trying to assign to f.bar. Is # MAGIC! possible in any way? The implementation details of the #property are a black box and not indirectly monkey-patchable. The entire method call needs to be replaced. It needs to affect a single instance only (class-level patching is okay if inevitable, but the changed behaviour must only selectively affect a given instance, not all instances of that class).
Subclass the base class (Foo) and change single instance's class to match the new subclass using __class__ attribute:
>>> class Foo:
... #property
... def bar(self):
... return 'Foo.bar'
...
>>> f = Foo()
>>> f.bar
'Foo.bar'
>>> class _SubFoo(Foo):
... bar = 0
...
>>> f.__class__ = _SubFoo
>>> f.bar
0
>>> f.bar = 42
>>> f.bar
42
from module import ClassToPatch
def get_foo(self):
return 'foo'
setattr(ClassToPatch, 'foo', property(get_foo))
To monkey patch a property, there is an even simpler way:
from module import ClassToPatch
def get_foo(self):
return 'foo'
ClassToPatch.foo = property(get_foo)
Idea: replace property descriptor to allow setting on certain objects. Unless a value is explicitly set this way, original property getter is called.
The problem is how to store the explicitly set values. We cannot use a dict keyed by patched objects, since 1) they are not necessarily comparable by identity; 2) this prevents patched objects from being garbage-collected. For 1) we could write a Handle that wraps objects and overrides comparison semantics by identity and for 2) we could use weakref.WeakKeyDictionary. However, I couldn't make these two work together.
Therefore we use a different approach of storing the explicitly set values on the object itself, using a "very unlikely attribute name". It is of course still possible that this name would collide with something, but that's pretty much inherent to languages such as Python.
This won't work on objects that lack a __dict__ slot. Similar problem would arise for weakrefs though.
class Foo:
#property
def bar (self):
return 'original'
class Handle:
def __init__(self, obj):
self._obj = obj
def __eq__(self, other):
return self._obj is other._obj
def __hash__(self):
return id (self._obj)
_monkey_patch_index = 0
_not_set = object ()
def monkey_patch (prop):
global _monkey_patch_index, _not_set
special_attr = '$_prop_monkey_patch_{}'.format (_monkey_patch_index)
_monkey_patch_index += 1
def getter (self):
value = getattr (self, special_attr, _not_set)
return prop.fget (self) if value is _not_set else value
def setter (self, value):
setattr (self, special_attr, value)
return property (getter, setter)
Foo.bar = monkey_patch (Foo.bar)
f = Foo()
print (Foo.bar.fset)
print(f.bar) # baz
f.bar = 42 # MAGIC!
print(f.bar) # 42
It looks like you need to move on from properties to the realms of data descriptors and non-data descriptors. Properties are just a specialised version of data descriptors. Functions are an example of non-data descriptors -- when you retrieve them from an instance they return a method rather than the function itself.
A non-data descriptor is just an instance of a class that has a __get__ method. The only difference with a data descriptor is that it has a __set__ method as well. Properties initially have a __set__ method that throws an error unless you provide a setter function.
You can achieve what you want really easily just by writing your own trivial non-data descriptor.
class nondatadescriptor:
"""generic nondata descriptor decorator to replace #property with"""
def __init__(self, func):
self.func = func
def __get__(self, obj, objclass):
if obj is not None:
# instance based access
return self.func(obj)
else:
# class based access
return self
class Foo:
#nondatadescriptor
def bar(self):
return "baz"
foo = Foo()
another_foo = Foo()
assert foo.bar == "baz"
foo.bar = 42
assert foo.bar == 42
assert another_foo.bar == "baz"
del foo.bar
assert foo.bar == "baz"
print(Foo.bar)
What makes all this work is that logic under the hood __getattribute__. I can't find the appropriate documentation at the moment, but order of retrieval is:
Data descriptors defined on the class are given the highest priority (objects with both __get__ and __set__), and their __get__ method is invoked.
Any attribute of the object itself.
Non-data descriptors defined on the class (objects with only a __get__ method).
All other attributes defined on the class.
Finally the __getattr__ method of the object is invoked as a last resort (if defined).
You can also patch property setters. Using #fralau 's answer:
from module import ClassToPatch
def foo(self, new_foo):
self._foo = new_foo
ClassToPatch.foo = ClassToPatch.foo.setter(foo)
reference
In case someone needs to patch a property while being able to call the original implementation, here is an example:
#property
def _cursor_args(self, __orig=mongoengine.queryset.base.BaseQuerySet._cursor_args):
# TODO: remove this hack when we upgrade MongoEngine
# https://github.com/MongoEngine/mongoengine/pull/2160
cursor_args = __orig.__get__(self)
if self._timeout:
cursor_args.pop("no_cursor_timeout", None)
return cursor_args
mongoengine.queryset.base.BaseQuerySet._cursor_args = _cursor_args
This may be a stupid / trivial question, but I'm confused in this matter.
What is the encouraged (pythonic) way of declaring instance fields - in the constructor, or in the class body itself?
class Foo:
""" Foo class """
# While we are at it, how to properly document the fields?
bar = None
def __init__(self, baz):
""" Make a Foo """
self.bar = baz
OR:
class Foo:
""" Foo class """
def __init__(self, baz):
""" Make a Foo """
self.bar = baz
It's a matter of expectations. People reading your code will expect that the attributes defined at the top level of the class will be class attributes. The fact that you then always replace them in __init__ will only create confusion.
For that reason you should go with option 2, defining instance attributes inside __init__.
In terms of documenting the attributes, pick a docstring style and stick to it; I like Google's, other options include numpy's.
class Foo:
"""A class for foo-ing bazs.
Args:
baz: the baz to foo
Attributes:
bar: we keep the baz around
"""
def __init__(self, baz):
self.bar = baz
To keep it simple, let us define class Foo with a class variable bar:
In [34]: class Foo: bar = 1
Now, observe:
In [35]: a = Foo()
In [36]: a.bar
Out[36]: 1
In [37]: Foo.bar = 2
In [38]: a.bar
Out[38]: 2
A change to Foo.bar affects existing instances of the class.
For this reason, one generally avoids class variables, as opposed to instance variables unless one wants these side-effects.