Help a guy out. Can't seem to get a decorator to work with inheritance. Broke it down to the simplest little example in my scratch workspace. Still can't seem to get it working.
class bar(object):
def __init__(self):
self.val = 4
def setVal(self,x):
self.val = x
def decor(self, func):
def increment(self, x):
return func( self, x ) + self.val
return increment
class foo(bar):
def __init__(self):
bar.__init__(self)
#decor
def add(self, x):
return x
Oops, name "decor" is not defined.
Okay, how about #bar.decor? TypeError: unbound method "decor" must be called with a bar instance as first argument (got function instance instead)
Ok, how about #self.decor? Name "self" is not defined.
Ok, how about #foo.decor?! Name "foo" is not defined.
AaaaAAaAaaaarrrrgggg... What am I doing wrong?
Define decor as a static method and use the form #bar.decor:
class bar(object):
def __init__(self):
self.val = 4
def setVal(self,x):
self.val = x
#staticmethod
def decor(func):
def increment(self, x):
return func(self, x) + self.val
return increment
class foo(bar):
def __init__(self):
bar.__init__(self)
#bar.decor
def add(self, x):
return x
I know the question has been asked 11 years ago ...
I had the same problem, here is my solution to use an inherited private decorator :
class foo:
def __bar(func):
def wrapper(self):
print('beginning')
func(self)
print('end')
return wrapper
class baz(foo):
def __init__(self):
self.quux = 'middle'
#foo._foo__bar
def qux(self):
print(self.quux)
a = baz()
a.qux()
The output is :
beginning
middle
end
Related
This could be a so called XY problem, so let me start with what I want:
ed = Edit.add(1).add(2).add(3)
print(ed.op) # [1,2,3]
Following is what I tried and basically I got working code, but I'm not sure if I did it right
or if there are other options.
The first add(1) is a class method call and the following add(2) and add(3) are instance method calls. I started here:
class Edit:
def __init__(self):
self.op = []
#classmethod
def add(cls, x):
self = cls()
return self.add_im(x)
def add_im(self, x): # im = instance method
self.op.append(x)
return self
ed = Edit.add(1).add_im(2).add_im(3)
print(ed.op)
but I wanted the same name everywhere, so I added some attribute name rewriting:
class Edit:
def __init__(self):
self.op = []
def __getattribute__(self, name):
if name == "add":
name = "add_im"
return super().__getattribute__(name)
#classmethod
def add(cls, x):
self = cls()
return self.add(x)
# im = instance method
def add_im(self, x):
self.op.append(x)
return self
ed = Edit.add(1).add(2).add(3)
print(ed.op)
UPDATE:
as #lllrnr101 noted in the comments, one part of my question has been answered here: Same name for classmethod and instancemethod
My question is broader, I think it does not have to be closed as a duplicate.
UPDATE2:
After studying the mentioned thread I have now new version I am satisfied with:
class dualmethod(classmethod):
def __get__(self, instance, typ):
if instance is None:
instance = typ() # create an instance "on the fly"
return self.__func__.__get__(instance, typ)
class Edit:
def __init__(self):
self.op = []
#dualmethod
def add(self, x):
self.op.append(x)
return self
ed = Edit.add(1).add(2).add(3)
print(ed.op) # [1,2,3]
I have a class A object method which uses another class B object's method, which the argument is class A object.
class A():
def calculate(self):
B = B.calculator(A)
class B():
def calculator(self, A):
...do something with A.attributes
It is possible to just pass attributes into the object, but I would see this possibility as the last priority. I am definitely a bit oversimplify my case, but I am wondering if there is a way to pass the entire class
Edit:
Sorry for the confusion. At the end I am trying to call class A object and A.calculate(), which will call class B obj and calculator function.
class A():
def __init__(self, value):
self.value = value
def calculate(self):
Bobj = B()
Bobj.calculator(A)
class B():
def calculator(self, A):
...do something with A.value
def main():
Aobj = A(value)
Aobj.calculate()
Your scenario does not currently indicate that you want to use any information from B when calculating A. There are a few ways of getting the functionality that you want.
Scenario: B stores no information and performs calculation. B should be a function
def B(value):
```do something with value```
return
class A():
def __init__(self, value):
self.value = value
def calculate(self):
return B(self.value)
def main():
Aobj = A(value)
Aobj.calculate()
Scenario: B stores some other information, but internal B information is not needed for the calculation. B should have a static method
class B():
#staticmethod
def calculate(value):
```do something with value```
return
class A():
def __init__(self, value):
self.value = value
def calculate(self):
return B.calculate(self.value)
def main():
Aobj = A(value)
Aobj.calculate()
Is it ok to have multiple staticmethods that calls from each other.
something like:
class Myclass():
def __init__(self, a):
self.var = self.static1(a)
#staticmethod
def static1(i):
i += 1
return self.static2(i)
#staticmethod
def static2(i):
return i * 3
c = Myclass(1)
I got :
NameError: name 'self' is not defined
use the #classmethod decorator
function will denote it does not change anything in the instance while you can access the class via first parameter cls
class Myclass():
def __init__(self, a):
self.var = self.static1(a)
#classmethod
def static1(cls,i):
i += 1
return cls.static2(i)
#staticmethod
def static2(i):
return i * 3
No need to prepend with 'self.'. Just call MyClass.static2(i)
This question was already asked here but doesn't contain any answers.
I'm creating a custom class that inherits from the native Python dict and want to implement some special behavior when an instance of my class is passed to a function with a signature like def foo(*args,**kwargs).
According to the docs, the relevant methods that have to be overloaded for this are __iter__, __getitem__ and __len__, so I setup a basic example to verify what's happening behind the scenes:
class A(dict):
def __init__(self):
super(A, self).__init__()
def __getattribute__(self, item):
print("__getattribute__ called")
return super(A, self).__getattribute__(item)
def __iter__(self):
print("__iter__ called")
return super(A, self).__iter__()
def __getitem__(self, item):
print("__getitem__ called")
return super(A, self).__getitem__(item)
def __len__(self):
print("__len__ called")
return super(A, self).__len__()
def foo(*args, **kwargs):
print("args: ", args)
print("kwargs: ", kwargs)
a = A()
a['a'] = 1
print("Calling foo() with A")
foo(a)
This just produces the following output:
Calling foo() with A
args: ({'a': 1},)
kwargs: {}
It seems that none of the required functions are being called. I overloaded __getattribute__ additionally, just to check which/any class methods/members are being accessed, but nothing seems to be called. What exactly is happening here? I'm using Python 3.7 if that's relevant.
Well, I came across this question today because I was also searching for that answer. I notice though, that nobody has provided an answer and I could not find any answer online as well! Maybe my GoogleFu is not good enough, maybe it is a simple question, or simply nobody has put the effort to answer it.
Here is the answer then!
Let's define two classes.
A first one that inherits from list:
class Foo(list):
def __init__(self):
super().__init__()
def __getattribute__(self, item):
print('__getattribute__ called')
return super().__getattribute__(item)
def __iter__(self):
print('__iter__ is called')
return super().__iter__()
def __getitem__(self, item):
print('__getitem__ is called')
return super().__getitem__(item)
def __len__(self):
print('__len__ is called')
return super().__len__()
and a second one that inherits from dict:
class Bar(dict):
def __init__(self):
super().__init__()
def __getattribute__(self, item):
print('__getattribute__ called')
return super().__getattribute__(item)
def __iter__(self):
print('__iter__ is called')
return super().__iter__()
def __getitem__(self, item):
print('__getitem__ is called')
return super().__getitem__(item)
def __len__(self):
print('__len__ is called')
return super().__len__()
Then let's define a function to print a dict:
def bar(a, b):
print(f'a is {a} and b is {b}')
then, let's define our variables:
my_list = Foo()
my_list.extend([1, 2])
my_dict = Bar()
my_dict.update({'a': 1, 'b': 2})
Then, let's see that get's printed!
print(*a)
__iter__ is called
__len__ is called
1 2
and
bar(**b)
__getattribute__ called
__getitem__ is called
__getitem__ is called
a is 1 and b is 2
What is a simple example of decorating a class by defining the decorator as a class?
I'm trying to achieve what has been implemented in Python 2.6 using PEP 3129 except using classes not functions as Bruce Eckel explains here.
The following works:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
def wrappedClass(*args):
return cls(*args)
return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))
def newMethod(self, value):
return value * 2
#Decorator("decorated class")
class TestClass(object):
def __init__(self):
self.name = "TestClass"
print "init %s"%self.name
def TestMethodInTestClass(self):
print "test method in test class"
def newMethod(self, value):
return value * 3
Except, in the above, wrappedClass is not a class, but a function manipulated to return a class type. I would like to write the same callable as follows:
def __call__(self, cls):
class wrappedClass(cls):
def __init__(self):
... some code here ...
return wrappedClass
How would this be done?
I'm not entirely sure what goes into """... some code here ..."""
If you want to overwrite new_method(), just do it:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
class Wrapped(cls):
classattr = self.arg
def new_method(self, value):
return value * 2
return Wrapped
#Decorator("decorated class")
class TestClass(object):
def new_method(self, value):
return value * 3
If you don't want to alter __init__(), you don't need to overwrite it.
After this, the class NormalClass becomes a ClassWrapper instance:
def decorator(decor_arg):
class ClassWrapper:
def __init__(self, cls):
self.other_class = cls
def __call__(self,*cls_ars):
other = self.other_class(*cls_ars)
other.field += decor_arg
return other
return ClassWrapper
#decorator(" is now decorated.")
class NormalClass:
def __init__(self, name):
self.field = name
def __repr__(self):
return str(self.field)
Test:
if __name__ == "__main__":
A = NormalClass('A');
B = NormalClass('B');
print A
print B
print NormalClass.__class__
Output:
A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper