I've been successfully using Python properties, but I don't see how they could work. If I dereference a property outside of a class, I just get an object of type property:
#property
def hello(): return "Hello, world!"
hello # <property object at 0x9870a8>
But if I put a property in a class, the behavior is very different:
class Foo(object):
#property
def hello(self): return "Hello, world!"
Foo().hello # 'Hello, world!'
I've noticed that unbound Foo.hello is still the property object, so class instantiation must be doing the magic, but what magic is that?
As others have noted, they use a language feature called descriptors.
The reason that the actual property object is returned when you access it via a class Foo.hello lies in how the property implements the __get__(self, instance, owner) special method:
If a descriptor is accessed on an instance, then that instance is passed as the appropriate argument, and owner is the class of that instance.
When it is accessed through the class, then instance is None and only owner is passed. The property object recognizes this and returns self.
Besides the Descriptors howto, see also the documentation on Implementing Descriptors and Invoking Descriptors in the Language Guide.
In order for #properties to work properly the class needs to be a subclass of object.
when the class is not a subclass of object then the first time you try access the setter it actually makes a new attribute with the shorter name instead of accessing through the setter.
The following does not work correctly.
class C(): # <-- Notice that object is missing
def __init__(self):
self._x = None
#property
def x(self):
print 'getting value of x'
return self._x
#x.setter
def x(self, x):
print 'setting value of x'
self._x = x
>>> c = C()
>>> c.x = 1
>>> print c.x, c._x
1 0
The following will work correctly
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
print 'getting value of x'
return self._x
#x.setter
def x(self, x):
print 'setting value of x'
self._x = x
>>> c = C()
>>> c.x = 1
setting value of x
>>> print c.x, c._x
getting value of x
1 1
Properties are descriptors, and descriptors behave specially when member of a class instance. In short, if a is an instance of type A, and A.foo is a descriptor, then a.foo is equivalent to A.foo.__get__(a).
The property object just implements the descriptor protocol: http://docs.python.org/howto/descriptor.html
Related
Consider the following code taken from the official documentation
class test:
_x = 10
def getx(self): return self._x
def setx(self, value): self._x = value
x = property(getx, setx)
as already explained in many other questions, this is 100% equivalent to
class test:
_x = 10
#property
def x(self):
return self._x
#x.setter
def x(self, val):
self._x = val
I would like to access the property x (and not the int in _x) in order to change the value of x.setter.
However doing type(test().x) returns int rather than property indicating that what test().x returns is _x and not the property x. Indeed, trying to do access test().x.setter returns a AttributeError: 'int' object has no attribute 'setter'.
I understand that 99.9% of the time, when someone does test().x he wants to access the value associated with the property x. This is exactly what properties are meant for.
However, how can I do in that 0.01% of the times when I want to access the property object rather than the value returned by the getter?
x is a class attribute, whose __get__ method receives a reference to the object when invoked on an instance of the class. You need to get a reference to the class first, then you can get the actual property object without invoking the getter.
>>> t = test()
>>> t.x
10
>>> type(t).x
<property object at ....>
I'm curious about the #property annotation in Python 3.
I know I can manipulate state between calls to a property like this ...
class Obj:
_x = 0
#property
def x(self):
self._x += 1
return self._x
obj = Obj()
print(obj.x)
print(obj.x)
... which prints:
1
2
However, is it possible keep this mechanism after it has been passed to a function?
Take the following function:
def f(x):
print(x)
print(x)
Say we cannot change it, meaning we can't simply pass the object to the function and use the properties directly. Is it possible to pass it only the property, or something to that effect, such that each time x is "used" in the function x increments? Is there maybe a way to do this by manipulating and passing the class or object itself? Something similar to __call__(self, ...), or adding #property to the class itself or the __init__(self, ...) of the class?
I've tried the following naive approaches ...
obj = Obj()
f(obj.x)
... and ...
obj = Obj()
f(getattr(obj, 'x'))
Both print ...
1
1
... which makes sense seeing as it is evaluated before it is passed to f. I also tried to extend Obj:
class Obj:
_x = 0
#property
def x(self):
self._x += 1
return self._x
def y(self):
return x
... and then go ...
obj = Obj()
f(obj.y)
... but it produces ...
<bound method Obj.y of <__main__.Obj object at 0x000002379E015748>>
<bound method Obj.y of <__main__.Obj object at 0x000002379E015748>>
This also makes sense seeing as we're simply getting the method itself and passing it to the f function.
Just a note: This isn't a real world problem/example. I'm simply trying to understand the principles and limits of python itself.
The property() wrapper is a descriptor, meaning that it is only invoked by dotted access, like a.x, and not by plain variable access.
To trigger a method invocation or function call with just a variable reference, I think it would be necessary to exec() code in a custom locals namespace:
>>> def add_ten(x):
return x + 10
>>> class NS(dict):
def __getitem__(self, key):
value = dict.__getitem__(self, key)
if key == 'x':
return add_ten(value)
return value
>>> exec('print(x + 2)', globals(), NS(x=5))
17
In the above example, just a reference to the variable x is enough to trigger a call to add_ten().
This is likely more trouble than its worth, but as you say, you just wanted to see what is possible :-)
I have two methods, one for the individual Instance, and one for every Instance in that class:
class MasterMatches(models.Model):
#classmethod
def update_url_if_any_matches_has_one(cls):
# apply to all instances, call instance method.
def update_url_if_any_matches_has_one(self):
# do something
Should I name these the same? Or, what is a good naming convention here?
The question of using the same names can be clarified by understanding how decorators work.
#dec
def foo(x):
print(x)
translates to
def foo(x):
print(x)
foo = dec(foo)
In your example the decorator syntax can be expanded to
class MasterMatches(models.Model):
def update_url_if_any_matches_has_one(cls):
# apply to all instances, call instance method.
update_url_if_any_matches_has_one = classmethod(update_url_if_any_matches_has_one)
def update_url_if_any_matches_has_one(self):
# do something
The former implementation of update_url_if_any_matches_has_one will be overwritten by the latter.
Usually use self declaration style. #classmethod use only if method not works with class instance fields.
Function decorated as #classmethod takes the first argument is the class type, while normal method takes instance of object.
class A:
#classmethod
def a(cls):
print(cls)
def b(self):
print(self)
a = A()
a.a()
a.b()
# Output:
# <class '__main__.A'>
# <__main__.A object at 0x03FC5DF0>
It can be useful if you have a static class fields. The to access therm you don't need explicitly specify the class name. But you don't get access to instance fields. Example:
class A:
field = 1
#classmethod
def a(cls):
print(cls.field)
def b(self):
self.field = 2
print(self.field, A.field)
a = A()
a.a()
a.b()
# Outputs:
# 1
# 2 1
Context:
Using the following:
class test:
def __init__(self):
self._x = 2
def __str__(self):
return str(self._x)
def __call__(self):
return self._x
Then creating an instance with t = test()
I see how to use __str__ for print:
>>> print t
2
I can see how to make the object callable using __call__
>>> t()
2
Question
But how do you get the object to return an internal attribute such that when you enter:
>>> t
2
instead of:
<__main__.test instance at 0x000000000ABC6108>
in a similar way that Pandas prints out DataFrame objects.
__repr__ is intended to be the literal representation of the object.
Note that if you define __repr__, you don't have to define __str__, if you want them both to return the same thing. __repr__ is __str__'s fallback.
class test:
def __init__(self):
self._x = 2
def __repr__(self):
return str(self._x)
def __call__(self):
return self._x
t = test()
>>> print t
2
>>> t
2
Define __repr__.
def __repr__(self):
return str(self._x)
The Python interpreter prints the repr of the object by default.
Use dir. Especially from the cli, dir(t) would reveal as much as you need to know about your object t.
I am looking at this Python Doc page:
http://docs.python.org/2/library/functions.html#property
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
Right below it says:
If then c is an instance of C, c.x will invoke the getter, c.x = value will invoke the setter and del c.x the deleter.
To me, c.x = value looks like assignment of a value to a function, since c.x is a function, unless the "=" operator is overloaded. Is it what is happening here?
Same thing with del c.x
Thanks.
property is a descriptor, which changes the way Python handles attribute access. The Python docs have an article introducing descriptors.
When Python accesses an attribute that points to an object with a __get__ method, it will return what that method returns instead of the object itself. Similarly, = will delegate to __set__ and del to __delete__. The special methods are described in the docs.