I have a class in a separate file called test_class.py. It looks something like this:
class test():
def __init__(self, X, Y):
self.X = X
self.Y = Y
def get_sum(self):
return self.X + self.Y
I would now like to create a wrapper class that also has the get_sum() function as a method. This is what I'm trying (inspired and motivated by the problem in this post: https://stackoverflow.com/a/7089719):
from test_class import test
tmp = test(1,3)
tmp.get_sum()
This outputs 4, so far so good. Now I try to create the wrapper as follows:
class Wrapper(object):
def __init__(self, method_name, module_name):
self.get_sum = method_name
self.test = module_name
def __call__(self, *args, **kwargs):
method = __import__(self.module, globals(), locals(), [self.get_sum,])
return method(*args, **kwargs)
wr = Wrapper('get_sum', 'test')
wr.get_sum()
Which just results in the following error TypeError: 'str' object is not callable
I know this is because wr.get_sum evaluates to a string, but I don't know how to ensure I have access to the methods defined in my test class.
Related
I'm trying to implement privacy modifiers into python using decorators.
My problem is that whenever I decorate a method that has self as an argument, when the method is called using dot notation, it doesn't pass self in automatically.
Public decorator class:
class Public:
def __init__(self, method, *args):
if type(method).__name__ == 'function':
self.method = method
def __call__(self, *args, **kwargs):
return self.method(*args, **kwargs)
Example code:
class Test:
#Public
def test(self):
return "Hello"
class Test1(Test):
def __init__(self):
super().__init__()
print(self.test())
x = Test1()
How do I pass self into Public.__call__?
I tried regularly passing in self:
class Test:
#Public
def test(self):
return "Hello"
class Test1(Test):
def __init__(self):
super().__init__()
print(self.test(self))
x = Test1()
which works but I would much rather not have to do that every time I need to call a method.
I found an answer
Here's how if anyone else is doing something similar:
First I had to create a decorator function that changed the getattribute function in the class
def modifiable(cls):
if isinstance(cls, type):
original_getattr = cls.__getattribute__
def getattr(_self, name):
attr = original_getattr(_self, name)
if isinstance(attr, Modifier):
def wrapper(*args, **kwargs):
return attr(_self, *args, **kwargs)
return wrapper
return attr
cls.__getattribute__ = getattr
return cls
I also created an empty Modifier class that all the privacy modifiers inherit from to make it easier to check if a method is modified.
example code:
#modifiable
class Test:
#Protected
def test(self):
return "Hello"
#modifiable
class Test1(Test):
x = 1
def __init__(self):
super().__init__()
print(self.test())
test = Test1()
print(test.test())
and output:
Hello
Traceback (most recent call last):
File "C:\Users\tyson\OneDrive\Documents\GitHub\better-decorators\src\test.py", line 21, in <module>
print(test.test())
privacy.AccessError: test is a protected method
(privacy.AccessError is a custom error)
I want to create a decorator class AddToHistory to modify history entries of other classes instances when a certain method got called.
So, for example, in pseudo code:
class AddToHistory(object):
...
def __call__(self, ...):
instance.history.append(fun_name)
class MyClass(object):
def __init__(self):
self.history = []
#AddToHistory
def methodA():
...
#AddToHistory
def methodB(input):
...
def methodC():
...
inst = MyClass()
print(inst.history)
>>> []
inst.methodA()
print(inst.history)
>>> ['methodA']
inst.methodB(myinput)
print(inst.history)
>>> ['methodA', 'methodB']
inst.methodC()
print(inst.history)
>>> ['methodA', 'methodB']
The decorator should automatically use the name of the decorated method.
I already searched and tried for quite some time but couldn't find a good way to implement this.
Any hints from your side?
Thanks a lot in advance!
Using a decorator function instead but you can turn it into a decorator class if you really insist (but unless you want a parameterized decorator there's not good reason for a decorator class here):
from functools import wraps
def add_to_history(func):
#wraps(func)
def wrapper(self, *args, **kw):
self.history.append(func.__name__)
return func(self, *args, **kw)
return wrapper
class MyClass(object):
def __init__(self):
self.history = []
#add_to_history
def methodA(self):
return "method A"
#add_to_history
def methodB(self, input):
return "method B %s" % input
def methodC(self):
return "methodC"
inst = MyClass()
print(inst.history)
inst.methodA()
print(inst.history)
inst.methodB("myinput")
print(inst.history)
inst.methodC()
print(inst.history)
I have an issue with using a class to decorate another class' method. Code is as follows:
class decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args):
return self.func(*args)
class test(object):
#decorator
def func(self, x, y):
print x, y
t = test()
t.func(1, 2)
It shows this error
TypeError: func() takes exactly 3 arguments (2 given).
If called using:
t.func(t, 1, 2)
then it passes. But then if the decorator is taken away, then this line will have issue again.
Why this is happening and how to solve it?
Edit: second version of the code to show the self in decorator.__call__ should be different than the self in test.func:
class decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args):
return self.func(*args)
class test(object):
def __init__(self):
self.x = 1
self.y = 2
#decorator
def func(self):
print self
print self.x, self.y
t = test()
t.func()
This shows the same error. But
t.func(t)
works but not ideal.
To work as a method, an object in a class needs to implement part of the descriptor protocol. That is, it should have a __get__ method that returns a callable object which has been "bound" to the instance the method was looked up on.
Here's one way that you could make that work, using a wrapper function:
class decorator(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
def wrapper(*args):
return self.func(instance, *args) # note, self here is the descriptor object
return wrapper
You could instead return an instance of some other class from __get__, rather than a function, and use the __call__ method of that other class to implement the wrapper. If you're not using a closure though, you'd need to pass the instance to the wrapper class explicitly (as well as the function, since self.func won't work outside the descriptor class).
I have problem solving this question, I have the following class:
class test:
#auth
def method1(self, x):
return x
#auth
def method2(self, x, y):
return x+y
def method3(self, z):
return z
I applied the decorator in both methods, follow:
class auth:
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
self.f(*args, **kwargs)
So far no problem, however I need (NEED) to use the following code:
def run():
klass = globals()["test"]()
method1 = getattr(klass, "method1")
print(method1.__code__.co_varnames)
# should print (self, x)
method2 = getattr(klass, "method2")
print(method2.__code__.co_varnames)
# should print (self, x, y)
method3 = getattr(klass, "method3")
print(method3.__code__.co_varnames)
# i get (self, z) < without decorator
But I get now:
AttributeError: 'auth' object has no attribute '__code__'
What makes sense if we think that the signature of method "method1 and method2" is now "auth".
So how do I get the arguments with or without decorators.
I started reading about the "inspect" but there are many reports about being slow.
The "original" method is stored in the f attribute of the auth object. Instead of method1.__code__.co_varnames use method1.f.__code__.co_varnames
Annotations just contain an object and are not the object itsself, it is an object of class auth and not function. To access the function itsself, you can write methodN.f.__code__.co_varnames or assign a copy of the __dict__ object of the function to the auth-object in __init__ itsself.
class auth:
def __init__(self, f):
self.__dict__.update(f.__dict__)
# now the initialisations
self.f = f
def __call__(self, *args, **kwargs):
self.f(*args, **kwargs)
Edit:
You should initialize the members/call super after updating the dict, because f could be overriden by the update, eg. you define another decorator-class and it has also a member f.
I have written a chainable API (in a similar style to jQuery) as follows:
class ChainableAPI:
def show(self):
self.visibility = 1
return self
def goBlue(self):
self.color = 'Blue'
return self
def die(self):
self.life = 0
return self
chainableAPI = ChainableAPI()
(chainableAPI
.goBlue()
.show()
.die()
.goBlue())
Notice how each method of ChainableAPI ends with return self. Is there a way to have all methods to return self automatically? That way I do not have to specify return self manually for each method.
You could use a decorator:
import functools
def chainable(func):
#functools.wraps(func)
def decorated(*args, **kwargs):
func(*args, **kwargs)
return args[0]
return decorated
Then the class would look like this:
class Foo(object):
#chainable
def show(self):
self.visibility = True
#chainable
def go_blue(self):
self.color = 'blue'
But is it better than just writing return self?
Also, a class decorator could be written to apply the chainable decorator to all methods not starting with _:
def all_chainable(klass):
for k, v in klass.__dict__.items():
if not k.startswith('_') and callable(v):
setattr(klass, k, chainable(v))
return klass
Example:
#all_chainable
class Foo(object):
def show(self):
self.visibility = True
Still, no matter how cool it may be I still think you should just use return self. But this shows how powerfull Python is.