I am aware that I can use descriptors to change static property as if it were a normal property. However, when I try using descriptors for a normal class property, I end up changing the object it references to, instead of the value in the object.
If I have
Normal use, considering that the method(param) returns an object
class SomeClass():property = method(param)
I can then do:
instance = SomeClass()
instance.property = 3
and be able to have that setting handled by the the class of which property is an instance.
Now, if I instead have
class SomeClass():def__init__(self):self.property = method(param)
and I do:
instance = SomeClass()
instance.property = 3
That code does not work, and I overwrite the reference to the object created by method(param) with 3, instead of having that setting handled by the descriptor.
Is there a way I can use descriptors without static methods? In essence, I need to be able to create several instances of the class, each with its own unique properties that can be altered using the convenient descriptor method. Is that possible?
Python version: 2.7
Thanks!
Descriptors provide a simple mechanism for variations on the usual patterns of binding functions into methods.
To recap, functions have a __get__()
method so that they can be converted to a method when accessed as attributes. The non-data descriptor transforms an obj.f(*args)
call into f(obj, *args)
. Calling klass.f(*args)
becomes f(*args)
.
This chart summarizes the binding and its two most useful variants:
Transformation Called from an Object Called from a Class
function f(obj, *args) f(*args)
staticmethod f(*args) f(*args)
classmethod f(type(obj), *args) f(klass, *args)
Static methods return the underlying function without changes. Calling either c.f or C.f is the equivalent of a direct lookup into
object.__getattribute__(c, "f") or object.__getattribute__(C, "f").
As a result, the function becomes identically accessible from either an object or a class.
Good candidates for static methods are methods that do not reference the self variable.
class RevealAccess(object):"""A data descriptor that sets and returns valuesnormally and prints a message logging their access."""def __init__(self, initval=None, name='var'):self.val = initvalself.name = namedef __get__(self, obj, objtype):print 'Retrieving', self.namereturn self.valdef __set__(self, obj, val):print 'Updating', self.nameself.val = val>>> class MyClass(object):
... x = RevealAccess(10, 'var "x"')
... y = 5
...
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20
>>> m.y
5