How Can I Use Descriptors For Non-static Methods?
Solution 1:
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.
classRevealAccess(object):
"""A data descriptor that sets and returns values
normally and prints a message logging their access.
"""def__init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def__get__(self, obj, objtype):
print'Retrieving', self.name
return self.val
def__set__(self, obj, val):
print'Updating', self.name
self.val = val
>>> classMyClass(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
Solution 2:
Considering method(param)
returns a descriptor, you may invoke it manually with a property like so:
classSomeClass(object):def__init__(self):
self._descriptor = method(param)
@propertydefmy_attribute(self):
returnself._descriptor.__get__(self, self.__class__)
@my_attribute.setter
defmy_attribute(self, value):
self._descriptor.__set__(self, value)
This will allow you to create instance-specific descriptors instead of class-level descriptors.
I still do not see the reason for you to do that as descriptors should usuallty be class-level. That's their point. Else they are just regular objects which you can call using properties.
Solution 3:
Properties are "computed attributes". Properties are implemented using descriptors. If an object's attribute is looked up and a descriptor object is found, the descriptor's getter function will compute the value.
This special rule is valid only at the class level.
That's why:
classSomeClass():
property = <a propertyobject here>
defines a property (computed attribute) for all SomeClass
instances, but:
classSomeClass():
def__init__(self):
self.property = <a propertyobject here>
defines an ordinary attribute which happens to be of property object type, but is not treated specially in any way. Its getters and setters are ignored (unless called explicitely by the user code, of course).
There is no other way of using descriptors and properties as setting them in the class and not in an instance.
UPDATE - Example:
Small example: instead of creating several instances each with its own descriptor (approach which does not work), a new subclass is instantiated every time.
classBaseClass:
pass
_class_number = 0defclass_factory(prop):
global _class_number
_class_number += 1returntype('Class' + str(_class_number), (BaseClass,), dict(prop=prop))
c1 = class_factory(property(fget=lambda self: "property1"))()
print(c1.prop)
c2 = class_factory(property(fget=lambda self: "property2"))()
print(c2.prop)
Solution 4:
guys,
Thanks for the help. Out of many great suggestions, I decided to wrap the set and get methods, thus losing the practicality of descriptors, while keeping the practicality of having a module completely programmed for me. I simply extended the class "PageElement" and created two new methods get() and set(), which call their correspondent implementations:
defget(self):
returnself.__get__(self.owner_page, self.owner_page.__class__)
defset(self, value):
self.__set__(self.owner_page, value)
Thanks for the help! I opened up my eyes to a lot of details in the language that I still do not know. And I will keep digging.
Post a Comment for "How Can I Use Descriptors For Non-static Methods?"