The following code doesn't work properly. setlen isn't called from this line a.length=10
class A():
def __init__(self,length=0):
self._length=length
self._area=length**2
#property
def area(self):
return self._area
def getlen(self):
return self._length
def setlen(self,x):
self._length=x
self.area=x**2
length=property(getlen, setlen)
a=A()
a.length=10
print a.area
You're on Python 2.x. Classes need to inherit from object, directly or through the inheritance chain, for most of the newer features of the class system to work properly.
Not sure why you're using the decorator form one time and not the other. Better to use it both times:
class A(object):
def __init__(self,length=0):
self._length=length
self._area=length**2
#property
def area(self):
return self._area
#property
def length(self):
return self._length
#length.setter
def setlen(self,x):
self._length=x
self.area=x**2
Although as user2357112 says, the root of the problem is that you are not inheriting from object.
Related
Basically, I have a generic class with a lot of methods. Before accessing those methods, I have to check its 'type' field, for example:
Note: generic_class_t is from a 3rd-party library I cannot control or re-design. I can only wrap but I want to be performant.
Here's the problem:
class generic_class_t:
def __init__(self):
self.type = ...
def method1(self):
pass
def method2(self):
pass
attr1 = property(lambda self: ...)
attr1 = property(lambda self: ...)
User code working with the generic class, would always have to use something like this:
if cls.type == 1:
cls.method1()
cls.attr1
elif cls.type == 2:
cls.method2()
cls.attr2
...
What I want to do, is wrap that class in specialized classes:
class cls1:
"""Wrapper for type=1"""
def __init__(self, cls):
self.obj = cls
def method1():
self.obj.method1()
attr = property(lambda self: cls.attr1)
# There are no method2, etc.
class cls2:
"""Wrapper for type=1"""
def __init__(self, cls):
self.obj = cls
def method2():
self.obj.method2()
attr = property(lambda self: cls.attr2)
# There are no method2, etc.
Now of course, I would have to have a factory method:
o1 = wrap(cls)
or:
o2 = wrap(cls)
def wrap(cls):
if cls.type == 1:
return cls1(cls)
elif cls.type == 2:
return cls2(cls)
The problem with that is memory and performance of the factory.
For each generic class instance, another specialized object would have to be constructed.
My question is:
Is there is a way to directly / quickly patch the existing generic class instance and super-impose the specialized cls1 and cls2, etc.?
I prefer not to create a new object at all.
I know a proxy object method can come in handy, but again, we have the proxy object itself.
Can I patch the __dict__ / swap the __dict__ , etc. and do something fast to de-generalize the generic class and have specialized classes hijack its method?
I hope this is clear.
I appreciate any advise.
Thanks!
I think you're underestimating the power of dictionaries. For example, let's say your generic interface has a method do and a propery attr. Your factory does not need a giant if statement to choose which implementation it needs:
class Wrapper:
def __init__(self, obj):
self.obj = obj
class Type1(Wrapper):
def do(self):
return self.obj.method1()
#property
def attr(self):
return self.obj.attr1
class Type2(Wrapper):
def do(self):
return self.obj.method2()
#property
def attr(self):
return self.obj.attr2
type_map = {
1: Type1,
2: Type2
}
def type_factory(obj):
return type_map(obj.type)(obj)
This way allows you to perform arbitrary operations on the underlying object. For example, with a couple of tweaks, you can have a version that does something like this:
class TypeCombined(Wrapper):
def do(self):
return self.obj.method1() + self.obj.method2()
#property
def attr(self):
return self.obj.attr1 + self.obj.attr2
def type_factory(obj, type=None):
return type_map[obj.type if type is None else type](obj)
If you need something simpler because each type simply corresponds to a selection of methods and attributes, you can generate the classes with something like a metaclass, or more simply, use a configurable base class:
type_map = {
1: ('method1', 'attr1'),
2: ('method2', 'attr2')
}
class Wrapper:
def __init__(self, obj):
self.obj = obj
self.method_name, self.attr_name = type_map[obj.type]
def do(self):
return getattr(self.obj, self.method_name)()
#property
def attr(self):
return getattr(self.obj, self.attr_name)
This question already has answers here:
Python: Bind an Unbound Method?
(5 answers)
Closed 2 years ago.
Problem Description
I want to use a decorator to define a class method, but this requires me to manually give the 'self' object when I shouldn't have to provide that.
def func_wrapper(func):
def call_func(self):
print(self.a)
func()
return call_func
def func():
print('hello')
class test:
def __init__(self, func):
self.a = 0
self.call_func = func_wrapper(func)
mytest = test(func)
#mytest.call_func() #why does this not work?
mytest.call_func(mytest) #this works
I want to be able to mytest.call_func() but this doesn't work, presumably because call_func is bound to the func_wrapper and not mytest. If I manually pass in the object, e.g. mytest.call_func(mytest) this will work, but I don't want to have to manually pass in the object - this creates inconsistent call signatures if one inherited the test class and wrote their own call_func method, because then the method would be properly bound to the class.
Solution Attempts
def func_wrapper2(func, obj):
def call_func():
print(obj.a)
func()
return call_func
class test:
def __init__(self, func):
self.a = 0
self.call_func = func_wrapper2(func, self)
Here is a solution which lets me test.call_func() as desired, but here func_wrapper is not a true decorator as it requires to be passed in the object as well.
Looking on the web I found this blog https://medium.com/#vadimpushtaev/decorator-inside-python-class-1e74d23107f6 which talks about this issue and recommends to define the decorator either in a nested class, or a helper class. However their solution doesn't seem to work and I am getting type errors from passing the wrong number of inputs.
class test2:
class test2helper:
#classmethod
def func_wrapper(func):
print(self.a)
func()
def __init__(self):
self.a = 0
#test2helper.func_wrapper
def call_func(self):
print('hello')
So what is the proper way to use decorators with class methods? Every way to do it seems to cause different issues with how the self is being handled. I am going to use the func_wrapper2 design unless there is a better way to do this.
You are missing one level:
class test2:
class test2helper:
#classmethod
def decorator(cls, func): # this must return a function!
def func_wrapper(self): # ... namely this one, the "wrapper"
print(self.a) # ... where you have access to the instance
func(self) # ... upon which the method is called
return func_wrapper
def __init__(self):
self.a = 0
#test2helper.decorator
def call_func(self):
print('hello')
>>> t = test2()
>>> t.call_func()
0
hello
Or, if you want to go with the earlier attempt without nested class:
def decorator(func): # you are decorating an unbound function!
def func_wrapper(obj):
print(obj.a)
func(obj) # which has to be passed all the arguments
return func_wrapper
class test:
def __init__(self):
self.a = 0
#decorator
def call_func(self):
print('hello')
You can define a class decorator to do what you want:
def class_decorator(cls):
def call_func(self):
print(self.a)
return func()
setattr(cls, 'call_func', call_func)
return cls
def func():
print('hello')
#class_decorator
class Test:
def __init__(self, func):
self.a = 0
mytest = Test(func)
mytest.call_func() # This now works.
Output:
0
hello
In python, is there a way to make a decorator on an abstract method carry through to the derived implementation(s)?
For example, in
import abc
class Foo(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
#some_decorator
def my_method(self, x):
pass
class SubFoo(Foo):
def my_method(self, x):
print x
SubFoo's my_method won't get decorated with some_decorator as far as I can tell. Is there some way I can make this happen without having to individually decorate each derived class of Foo?
I would code it as two different methods just like in standard method factory pattern description.
https://www.oodesign.com/factory-method-pattern.html
class Foo(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
#some_decorator
def my_method(self, x):
self.child_method()
class SubFoo(Foo):
def child_method(self, x):
print x
This is, of course, possible. There is very little that can't be done in Python haha! I'll leave whether it's a good idea up to you...
class MyClass:
def myfunc():
raise NotImplemented()
def __getattribute__(self, name):
if name == "myfunc":
func = getattr(type(self), "myfunc")
return mydecorator(func)
return object.__getattribute__(self, name)
(Not tested for syntax yet, but should give you the idea)
As far as I know, this is not possible and not a good strategy in Python. Here's more explanation.
According to the abc documentation:
When abstractmethod() is applied in combination with other method descriptors, it should be applied as the innermost decorator, as shown in the following usage examples: ...
In other words, we could write your class like this (Python 3 style):
from abc import ABCMeta, abstractmethod
class AbstractClass(metclass=ABCMeta):
#property
#abstactmethod
def info(self):
pass
But then what? If you derive from AbstractClass and try to override the info property without specifying the #property decorator, that would create a great deal of confusion. Remember that properties (and it's only an example) usually use the same name for their class method, for concision's sake:
class Concrete(AbstractMethod):
#property
def info(self):
return
#info.setter
def info(self, new_info):
new_info
In this context, if you didn't repeat the #property and #info.setter decorators, that would create confusion. In Python terms, that won't work either, properties being placed on the class itself, not on the instance. In other words, I guess it could be done, but in the end, it would create confusing code that's not nearly as easy to read as repeating a few decorator lines, in my opinion.
My solution would be extending the superclass' method without overriding it.
import abc
class Foo(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
#some_decorator
def my_method(self, x):
pass
class SubFoo(Foo):
def my_method(self, x):
super().my_method(x) #delegating the call to the superclass
print x
Jinksy's answer did not work for me, but with a small modification it did (I use different names but the idea should be clear):
def my_decorator(func):
def wrapped(self, x, y):
print('start')
result = func(self, x, y)
print('end')
return result
return wrapped
class A(ABC):
#abstractmethod
def f(self, x, y):
pass
#my_decorator
def f_decorated(self, x, y):
return self.f(x, y)
class B(A):
def f(self, x, y):
return x + y
B().f_decorated(1, 3)
[Out:]
start
end
4
Notice that the important difference between this and what Jinksy wrote is that the abstract method is f, and when calling B().f_decorated it is the inherited, non-abstract method that gets called.
As I understand it, f_decorated can be properly defined because the abstractmethod decorator is not interfering with the decorator my_decorator.
I have a python class with "emulated" static properties via a metaclass:
class MyMeta(type):
#property
def x(self): return 'abc'
#property
def y(self): return 'xyz'
class My: __metaclass__ = MyMeta
Now some of my functions receives the property name as a string, which should be retrieved from My.
def property_value(name):
return My.???how to call property specified in name???
The point here is that I don't want an instance of My to be created.
Many thanks,
Ovanes
You could use
getattr(My,name)
I was looking at this recently. I wanted to be able to write Test.Fu where Fu is a computed property.
The following works using a descriptor object:
class DeclareStaticProperty(object):
def __init__(self, method):
self.method = method
def __get__(self, instance, owner):
return self.method(owner())
class Test(object):
def GetFu(self):
return 42
Fu = DeclareStaticProperty(GetFu)
print Test.Fu # outputs 42
Note that there is an instance of Test allocated behind the scenes.
I’m currently using the #property decorator to achieve “getters and setters” in a couple of my classes. I wish to be able to inherit these #property methods in a child class.
I have some Python code (specifically, I’m working in py3k) which looks vaguely like so:
class A:
#property
def attr(self):
try:
return self._attr
except AttributeError:
return ''
class B(A):
#property
def attr(self):
return A.attr # The bit that doesn't work.
#attr.setter
def attr(self, value):
self._attr = value
if __name__ == '__main__':
b = B()
print('Before set:', repr(b.attr))
b.attr = 'abc'
print(' After set:', repr(b.attr))
I have marked the part that doesn’t work with a comment. I want the base class’ attr getter to be returned. A.attr returns a property object (which is probably very close to what I need!).
Edit:
After receiving the answer below from Ned I thought up what I think is a more elegant solution to this problem.
class A:
#property
def attr(self):
try:
return self._attr
except AttributeError:
return ''
class B(A):
#A.attr.setter
def attr(self, value):
self._attr = value
if __name__ == '__main__':
b = B()
print('Before set:', repr(b.attr))
b.attr = 'abc'
print(' After set:', repr(b.attr))
The .setter decorator expects a property object which we can get using #A.attr. This means we do not have to declare the property again in the child class.
(This is the difference between working on a problem at the end of the day vs working on it at the beginning of the day!)
To override a setter in python 2 I did this:
class A(object):
def __init__(self):
self._attr = None
#property
def attr(self):
return self._attr
#attr.setter
def attr(self, value):
self._attr = value
class B(A):
#A.attr.setter
def attr(self, value):
# Do some crazy stuff with `value`
value = value[0:3]
A.attr.fset(self, value)
To understand where A.attr.fset came from see the documentation on the property class:
https://docs.python.org/2/library/functions.html#property
I think you want:
class B(A):
#property
def attr(self):
return super(B, self).attr
You mention wanting to return the parent class's getter, but you need to invoke the getter, not return it.