Mimic a descriptor with a function - python

I am trying to mimic a descriptor with a decorator function, but have failed. Here's what I have tried.
def my_property(self):
def wrapper(func):
return func(self)
return wrapper
class C:
def __init__(self):
self._x = 0
#my_property(C()) # this will print 0 for me, but it's not from the obj `c`
def p(self):
return self._x
c = C()
print(c.p)
Overriding __get__ directly in the decorator didn't help me either. I also tried to inherit the function class and override its __get__ method, but was told function is final and not subclassable (probably I should try forbiddenfruit https://github.com/clarete/forbiddenfruit).
Can anyone help?
Edit: To clarify, I was wondering if it is possible without having to use the keyword class?

Your intuition is right to override __get__. In fact, that's exactly how properties in Python actually work.
Consider
class MyProperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return self.func(instance)
MyProperty is a class whose instances contain a func. When we __get__ an instance of MyProperty off a class, it'll call the inner function automatically.
Now we'll make a neat wrapper function for it. Pretty trivial, but still nice to be consistent with Python's nomenclature for functions vs. types
def my_property(func):
return MyProperty(func)
Finally, using the decorator.
class C:
def __init__(self):
self._x = 0
#my_property
def p(self):
return self._x
c = C()
print(c.p) # Prints 0

Related

How to decorate all methods in a class? Can I just decorate the class? [duplicate]

This question already has answers here:
Attaching a decorator to all functions within a class
(11 answers)
Closed 5 years ago.
I have several classes and they have same implements name but difference realization. I want to decorate all methods in some classes but others not. I have thought about inheritance, but some classes have some methods do not need to be decorated. The problem is that I don't want to decorate methods one by one, some classes they need to be decorated by a same decorator, Is there any solution to fix it?
Your can start all method that required to be decorated with some prefix and then use something like this:
class Xobject(object):
def __init__(self, decorator):
for method_name in dir(self):
if method_name.startswith("dec_"):
attr = getattr(self, method_name)
wrapped = decorator(attr)
setattr(self, method_name, wrapped)
def dec_me_1(self):
print("In dec_me1")
return 0
def dec_me_2(self):
print("In dec_me2")
return 1
def decorator(func):
def wrapped(*args):
print("TEST")
return func(*args)
return wrapped
x = Xobject(decorator)
x.dec_me_1()
x.dec_me_2()
UPDATE:
You can decorate class by mean of function below. When using Python you should know that class in Python is also object so you could change it and pass it to the other function.
def decorator(func):
def wrapped(*args):
print("TEST")
return func(*args)
return wrapped
def decorate_object(p_object, decorator):
for method_name in dir(p_object):
if method_name.startswith("dec_"):
attr = getattr(p_object, method_name)
wrapped = decorator(attr)
setattr(p_object, method_name, wrapped)
decorate_object(Xobject, decorator)
x = Xobject()
x.dec_me_1()
x.dec_me_2()
Also your can decorate already instantiated object same way:
x = Xobject()
x.dec_me_1()
x.dec_me_2()
decorate_object(x, decorator)
x.dec_me_1()
x.dec_me_2()
I'm sure there are a few approaches to this, but the main leading options are:
Create a custom metaclass, where the __new__ method iterates across the attribute dictionary, identifies methods, and decorates them. See http://eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example/ for an example of Python metaclass programming. Disadvantages: that may be more complex than we'd want to get into here.
Do the same in a regular class's __init__ method. Disadvantages: that only decorates instance methods and not class or static methods, and it's slower because it runs every time you create a new instance.
Do it outside the class:
class Foo(object):
def bar(self):
print 'bar'
for name, ref in vars(Foo):
if callable(ref): ...
Disadvantages: You only get one chance to do it right: at import time. Subclasses don't get modified.
Do it in a class-level decorator. Same disadvantages as doing it outside the class (I think).
At some point you have to be explicit about what gets wrapped and what doesn't.
If I've understood you correctly, I think you could do something like this:
def wrapper(func):
def inner(*args, **kwargs):
print "%s was called" func.__name__
return func(*args, **kwargs)
return inner
class A(object):
def foo(self):
print "foo called"
def bar(self):
print "BAR CALLED"
class B(A):
#wrapper
def foo(self):
super(B, self).foo()
class C(A):
#wrapper
def bar(self):
super(C, self).bar()
Stick = A()
Dave = B()
Jupiter = C()
Jupiter.foo() #prints "foo called"
Jupiter.bar() #prints "bar wrapped" and "BAR CALLED"

Can I refactor this simple callback pattern that uses the property decorator?

I'm just getting to grips with decorators in Python and using them to add callbacks to some instance variables using the following simple pattern:
class A(object):
def __init__(self):
self._var = 0
self.var_callbacks = []
#property
def var(self):
return self._var
#var.setter
def var(self, x):
self._var = x
for f in self.var_callbacks:
f(x)
The property decorator is a neat way of allowing me to introduce callbacks where necessary without changing the class interface. However, after the third or fourth variable it's making the code a bit repetitive.
Is there a way to refactor this pattern into something along the following:
class A(object):
def __init__(self):
self.var = 0
enable_callback(self, 'var', 'var_callbacks')
You'll need to set the property on the class (since it is a descriptor), so using a enable_callback call in the initializer is not going to work.
You could use a class decorator to set the properties from a pattern:
def callback_properties(callbacks_attribute, *names):
def create_callback_property(name):
def getter(self):
return getattr(self, '_' + name)
def setter(self, value):
setattr(self, '_' + name, value)
for f in getattr(self, callbacks_attribute):
f(value)
return property(getter, setter)
def add_callback_properties(cls):
for name in names:
setattr(cls, name, create_callback_property(name)
return cls
return add_callback_properties
Then use that as:
#add_callback_properties('var_callbacks', 'var1', 'var2')
class A(object):
# everything else
Have a look at the Python descriptor protocol. In essence, you can define a class that handles the getting, setting and deleting of a property. So you could define a descriptor that runs your callbacks on setting the attribute.
Descriptors are regular classes, and can be parameterized. So you could implement a descriptor that takes the destination variable its constructor. Something like the following:
class A(object):
var = CallbackDescriptor('var')
foo = CallbackDescriptor('foo')

python: is this a good way to use the same function name for both classmethod and method?

class A(object):
#classmethod
def print(cls):
print 'A'
def __print(self):
print 'B'
def __init__(self):
self.print = self.__print
a = A()
a.print()
A.print()
I think it's too ugly, is there any other method to implement the same features? do not say combinemethod, because it creates an object every time.
The simplest solution is to create a descriptor decorator like classmethod but that also passes the instance to the method:
from functools import partial
class descriptormethod(object):
def __init__(self, fn):
self.fn = fn
def __get__(self, instance, owner):
return partial(self.fn, instance, owner)
class A(object):
#descriptormethod
def print_(self, cls):
print 'A' if self is None else 'B'
Don't worry about the overhead of the descriptor or partial objects; it's no different from what happens when you call an instance or class method normally.

Basic Python method definitions

I some questions about some code I've been looking at. What does the #staticmethod and #property mean when it is written above a method definition in Python like the following?
#staticmethod
def methodName(parameter):
Class_Name.CONSTANT_VARIABLE = parameter
#property
def methodName(parameter):
Class_Name.CONSTANT_VARIABLE = parameter
The decorator syntax is shorthand for this pattern.
def methodName(parameter):
Class_Name.CONSTANT_VARIABLE = parameter
methodName = some_decorator(methodName)
can be rearranged like this
#some_decorator
def methodName(parameter):
Class_Name.CONSTANT_VARIABLE = parameter
One advantage is that it sits at the top of the function, so it is clear that it is a decorated function
Are you also asking what staticmethods and properties are?
There is a sample code
class Class1(object):
def __init__(self):
self.__x = None
# you can call this method without instance of a class like Class1.method1()
#staticmethod
def method1():
return "Static method"
def method2(self):
return "Class method"
#property
def x(self):
print "In getter"
return self.__x
#x.setter
def x(self, value):
print "In Setter"
self.__x = value
A staticmethod is just a function that has been included in a class definition. Unlike regular methods, it will not have a self argument.
A property is a method that gets run upon attribute lookup. The principal purpose of a property to is support attribute lookup but actually run code as if a method call had been made.

Python decorator as a staticmethod

I'm trying to write a python class which uses a decorator function that needs information of the instance state. This is working as intended, but if I explicitly make the decorator a staticmetod, I get the following error:
Traceback (most recent call last):
File "tford.py", line 1, in <module>
class TFord(object):
File "tford.py", line 14, in TFord
#ensure_black
TypeError: 'staticmethod' object is not callable
Why?
Here is the code:
class TFord(object):
def __init__(self, color):
self.color = color
#staticmethod
def ensure_black(func):
def _aux(self, *args, **kwargs):
if self.color == 'black':
return func(*args, **kwargs)
else:
return None
return _aux
#ensure_black
def get():
return 'Here is your shiny new T-Ford'
if __name__ == '__main__':
ford_red = TFord('red')
ford_black = TFord('black')
print ford_red.get()
print ford_black.get()
And if I just remove the line #staticmethod, everything works, but I do not understand why. Shouldn't it need self as a first argument?
This is not how staticmethod is supposed to be used. staticmethod objects are descriptors that return the wrapped object, so they only work when accessed as classname.staticmethodname. Example
class A(object):
#staticmethod
def f():
pass
print A.f
print A.__dict__["f"]
prints
<function f at 0x8af45dc>
<staticmethod object at 0x8aa6a94>
Inside the scope of A, you would always get the latter object, which is not callable.
I'd strongly recommend to move the decorator to the module scope -- it does not seem to belong inside the class. If you want to keep it inside the class, don't make it a staticmethod, but rather simply del it at the end of the class body -- it's not meant to be used from outside the class in this case.
Python classes are created at runtime, after evaluating the contents of the class declaration. The class is evaluated by assigned all declared variables and functions to a special dictionary and using that dictionary to call type.__new__ (see customizing class creation).
So,
class A(B):
c = 1
is equivalent to:
A = type.__new__("A", (B,), {"c": 1})
When you annotate a method with #staticmethod, there is some special magic that happens AFTER the class is created with type.__new__. Inside class declaration scope, the #staticmethod function is just an instance of a staticmethod object, which you can't call. The decorator probably should just be declared above the class definition in the same module OR in a separate "decorate" module (depends on how many decorators you have). In general decorators should be declared outside of a class. One notable exception is the property class (see properties). In your case having the decorator inside a class declaration might make sense if you had something like a color class:
class Color(object):
def ___init__(self, color):
self.color = color
def ensure_same_color(f):
...
black = Color("black")
class TFord(object):
def __init__(self, color):
self.color = color
#black.ensure_same_color
def get():
return 'Here is your shiny new T-Ford'
Solution does exist!
Problem is that Static method that is trying to be used as decorator is in fact staticmethod object and is not callable.
Solution: staticmethod object has method __get__ which takes any argument and returns real method: python documentation Python 3.5 and up:
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
Min solution I came with is:
class A():
def __init__(self):
self.n = 2
#staticmethod
def _returnBaseAndResult(func):
from functools import wraps
#wraps(func)
def wrapper(*args, **kwargs):
self = args[0]
response = func(*args, **kwargs)
return self.n, response
return wrapper
#_returnBaseAndResult.__get__('this can be anything')
def square(self):
return self.n**2
if __name__ == '__main__':
a = A()
print(a.square())
Will print (2, 4)
ensure_black is returning a _aux method that isn't decorated by #staticmethod
You can return a non-static method to a static_method
http://docs.python.org/library/functions.html#staticmethod

Categories