I'd like to know whether my method is called by the user directly or by another method. To make it less abstract:
class myclass():
def __init__(self, ...):
....
def method1(self, ...):
...
--- some if statement --
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(...)
return x*2
myinstance = myclass(...)
myinstance.method1(...)
--> 'Hello'
myinstance.callmethod(...)
--> -
Hopefully my class makes clear what I'd like to do: When the user calls 'method1' the print statement shall be executed but if 'method1' is called by another method like 'callmethod' the print statement shall not be executed. Therefore I need 'some if statement' which checks whether 'method1' is called by the user directly or by another method. Thanks for you help!
No, and you don't want to do this.
If you want to change behaviour depending on the way a method is called, then you need to use a parameter. You can use a default value to make this simpler, for example:
def method1(self, do_print=True):
...
if do_print:
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(do_print=False)
return x*2
Now, calling myinstance.method1() will print, whereas myinstance.callmethod() will not.
It's actually achievable using the python inspector, like e.g.:
import inspect
class myclass():
def __init__(self):
pass
def method1(self):
(frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]
if function_name == '<module>':
print "Hello"
return 2
def callmethod(self):
x = self.method1()
return x*2
myinstance = myclass()
myinstance.method1()
myinstance.callmethod()
but I agree with Daniel it's not an elegant way to achieve the result as it hides some behaviour.
For further details also see: this post
Related
I need to doc-test a method which has to be wrapped with a decorator that does not apply #functools.wraps or functools.update_wrapper to the method being wrapped. In this case, the doctest does not see the docstring of the method to be tested:
#third_party_decorator
def method_to_be_tested():
"""
>>> method_to_be_tested()
"foo"
"""
return "foo"
This question is similar, however, I cannot change the code of the decorator.
What is the best thing I can do?
You may not be able to change the code of third_party_decorator, but you can wrap it once again to address the problem, and even re-use the same name if necessary:
def third_party_decorator(f):
# badly behaved decorator, this removed f's docstring
def no_docstring():
return f()
return no_docstring
old_third_party_decorator = third_party_decorator
def third_party_decorator(f):
# replace third_party_decorator AND preserve docstring
new_f = old_third_party_decorator(f)
new_f.__doc__ = f.__doc__
return new_f
#third_party_decorator
def method_to_be_tested():
"""
>>> method_to_be_tested()
'foo'
"""
return "foo"
import doctest
print(doctest.testmod())
A small meta-decorator to fix this:
def w(decorator):
def wrapper(func):
return wraps(func)(decorator(func))
return wrapper
Use:
#w(third_party_decorator)
def method_to_be_tested():
"""
>>> method_to_be_tested()
"foo"
"""
return "foo"
Or, monkey-patch it (do it only once):
third_party_decorator = w(third_party_decorator)
I want to use two type of decorators:
a)
#new
def foo():
print("foo")
b)
#new(arg1, arg2, arg3, ...)
def bar():
print("bar")
Basically, I want to make different handlers for the "new message" event. You should be able to write #message.new if you'd like to use it for all the messages or #message.new(filter) if you only want the handler to override the unfiltered handler to process messages from certain people or only the messages that have certain attachments to them.
My first thought was that the decorator could check whether its first argument is a function. If it is, it would guess that it's being used as #message.new. If the first argument is not a function, it would return a decorator.
from inspect import isfunction
def new(*args):
x = args[0]
if isfunction(x):
return new_noargs(x)
else:
return gen_new_args(args)
def new_noargs(func):
def munc():
print("new_noargs")
func()
return munc
def gen_new_args(args):
def dec(func):
def zunc():
print("new_args:", args)
func()
return zunc
return dec
And it works:
#new
def foo():
print("foo")
#new(1,2,3)
def bar():
print("bar")
It looks very clumsy and unpythonic, though. Is there a more convenient way to solve my problem? Also, if I'd like to use #new(some_function), the current new method would decide that it's being called like this:
#new
def some_function():
...
How can I improve my code?
Workaround
#overengineer is a decorator that allows another decorator to be called without brackets. It's still too complicated, but more reusable.
def overengineer(decorator):
def dec(*args):
x = args[0]
if isfunction(x):
return decorator()(x)
else:
return decorator(*args)
return dec
#overengineer
def new(*args):
def dec(func):
def zunc():
print("args:", args)
func()
return zunc
return dec
I guess the premise of the question is flawed as I don't lose much by writing #new() instead of #new, but I gain consistency and simplicity: new is just a decorator. Alternatively, I could make two different decorators.
Suppose I have this decorator:
def decorator(f):
def f_wrap(*args):
for item in args:
print(args)
return f(*args)
return f_wrap
When used as "permanent" decorators with the # syntax, args retrieves the arguments of the wrapped function. For example, when used with the class below, I receive the instance of MyObject.
Class MyObject(object):
def __init__(self):
pass
#decorator
def function(self):
return
How can I achieve the same result using a "fluid" decorator. Or a decorator that is not permanently bound to the function it is decorating? For example:
def decorator(f):
def f_wrap(*args):
if (not args):
print("Nothing in args")
return f(*args)
return f_wrap
class MyClass(object):
def __init__(self):
pass
def function(self):
return
if __name__ == "__main__":
myobj = MyClass()
myobj.function = decorator(myobj.function)
myobj.function()
In this case, the args tuple always returns empty (I always get "Nothing in args"), even though I anticipated that it would return the instance variable myobj.
EDIT:
In case it was not clear from #AChampion's post the solution is to simply call the fluid-decoratored method as an "unbound" method. E.g.,
from types import MethodType
def decorator(f):
def f_wrap(*args):
# I replaced this with an iteration through
# args. It's a bit more demonstrative.
for item in args:
print(item)
return f(*args)
return f_wrap
class MyClass(object):
def __init__(self):
pass
def function(self):
return
if __name__ == "__main__":
myobj = MyClass()
myobj.function = MethodType(decorator(MyClass.function), myobj)
myobj.function()
The reason for the difference is that you are wrapping different things, a unbound method vs a bound method:
class MyObject(object):
#decorator
def function(self):
pass
Is equivalent to:
import types
class MyClass(object):
def function(self):
pass
m = MyClass(object)
m.function = types.MethodType(decorator(MyClass.function), m)
Not:
m.function = decorator(m.function)
The first being an unbound method, the second being a bound method.
You aren't using all properly. all returns a bool on whether all conditions are met inside what you are checking for in all. In your case, you aren't really doing anything. You will always evaluate to True with how you are using all.
I believe what you are looking for is simply this:
if not args:
Now, ultimately what this checks is if the method you are executing has *args. For the case of the function you have, you aren't passing any arguments, therefore, with the if not args check, you will actually get:
"Nothing in args"
However, if you add an argument to your method as such:
def function(self, x):
return
Then call: myobj.function(1)
You will not get "Nothing in args".
To answer your last question about not getting your instance. If you print out f using this method of calling your decorator:
myobj.function = decorator(myobj.function)
myobj.function()
You will get a bound method:
<bound method MyClass.function of <__main__.MyClass object at 0x102002390>>
Now, set up your decorator as such:
#decorator
def function(self):
return
You will see you get a function attached to your class object:
<function MyClass.function at 0x102001620>
Hence showing that they aren't doing the exact same thing you would expect. Hope this helps clarify a bit.
I have a class which maintains a list of functions. These functions are just objects sitting in a queue and every so often the class pops one off and executes it. However, there are times when I would like to print out this list, and I'm imagining code as follows:
for function in self.control_queue:
print function.summarize()
if function.ready():
function()
In other words, I would like to call methods called summarize() and ready(), that I want to define somewhere, on these function objects. Also, I would like to be able to toss anonymous functions on this queue - i.e., generate everything dynamically.
you can make it a class and define __call__
class MyClass():
def summarize(self):
#summarize stuff
pass
def ready(self):
#ready stuff
pass
def _call__(self):
#put the code here, for when you call myClass()
pass
How you run it:
function = MyClass()
print function.summarize()
if function.ready():
function()
You have a couple possible approaches.
You could add the definitions to functions.
def foo():
pass
# later..
foo.summarize = lambda: "To pair with bar"
foo.ready = lambda: True
You could create class objects to wrap the function operation.
class Func():
def summarize(self):
return "Function!"
def ready(self):
return self.ready
def __call__(self):
# Act as a function
Or you can have a function which checks the function label for these capabilities.
def summarize_func(func):
return func.__name__ # Or branch here on specific names/attributes
def ready_func(func):
return True # Or branch on names/attributes
Finally to accommodate anonymous functions you can check for prescience of these attributes and return optimistically if the attributes are absent. Then you can combine above approaches with something that will work on any function.
def summarize_func(func):
if hasattr(func, summarize):
return func.summarize()
else:
# Note this will just be '<lambda>' for anonymous funcs
return func.__name__
def ready_func(func):
if hasattr(func, ready):
return func.ready()
else:
return True
One option is to implement function as a class instance:
class Function(object):
def summarize(self): pass # some relevant code here
def __call__(self): pass # and there
and use it later with
function = Function()
With __call__ magic method implemented, this function becomes a callable object.
For sure, you can assign attributes to functions, but it is rather obscure and conterintuitive:
>>> def summ(a): return sum(a)
...
>>> def function(a): return a
...
>>> function.sum=summ
>>> function.sum([1,2,3])
6
I've been stuck on this for a long time (like literally weeks), I've completed everything else in the code but this. I've also researched a lot but can't get anywhere near the solution. The only reason I waited a week to come here is because I wanted to solve this myself, but now, I give up!
Now, suppose I have the following code:
class test:
def meth1(self, obj):
self.hello = {}
return self.hello.obj()
def meth2(self):
test.meth1(self, 'keys')
Now, when I create an instance and try to call the method meth2like this:
x = test()
x.meth2()
It gives me an error for obvious reasons. How can I get it do what I want-- pass an argument to a function and use that argument as an object of another object?
Looks like you want getattr():
def meth1(self, obj):
self.hello = {}
return getattr(self.hello, obj)()
getattr(a, b) is equivalent to a.b (where b in the second case is the string that the b of the first case holds). In this case, a is self.hello and b is obj. From your snippet, it looks like you want to call the obj attribute as opposed to returning it directly, which is why we have a () at the end.
>>> class test:
... def meth1(self, obj):
... self.hello = {}
... return getattr(self.hello, obj)()
... def meth2(self):
... return test.meth1(self, 'keys')
...
>>> x = test()
>>> x.meth2()
[]