I am trying to learn decorators by following the 'python decorators in 12 steps'. http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
I tried replicating one of the In one of the code examples:
def outer(some_func):
def inner():
print ("before some_func")
ret = some_func()
return ret + 1
return inner
def foo():
return 1
def main():
decorated = outer(foo)
decorated()
if __name__ == "__main__": main()
This results in :
before some_func
In the example under Decorators!
>>> def outer(some_func):
... def inner():
... print ("before some_func")
... ret = some_func() # 1
... return ret + 1
... return inner
>>> def foo():
... return 1
>>> decorated = outer(foo) # 2
>>> decorated()
Returns:
before some_func
2
The main difference is that in the example, they are using Python running directly from cmd and I am using the Sublime text with python build as well as using a main() function. In my mind, I feel like these are doing the exact same thing. Is there something different between running code in the cmd versus with sublime that I am not getting?
The interactive Python interpreter automatically prints the results of a line if it is not assigned to a variable. This is useful for debugging. For example, if you call foo(), it will automatically print 1. The call below would not result in any extra prints in the interactive interpreter.
>>> result = decorated()
Related
Is there a library for interpreting python code within a python program?
Sample usage might look like this..
code = """
def hello():
return 'hello'
hello()
"""
output = Interpreter.run(code)
print(output)
which then outputs
hello
found this example from grepper
the_code = '''
a = 1
b = 2
return_me = a + b
'''
loc = {}
exec(the_code, globals(), loc)
return_workaround = loc['return_me']
print(return_workaround)
apparently you can pass global and local scope into exec. In your use case, you would just use a named variable instead of returning.
You can use the exec function. You can't get the return value from the code variable. Instead you can print it there itself.
code = """
def hello():
print('hello')
hello()
"""
exec(code)
I have used the following script to run the script directly and just to make a bash command line for running it outside the script (e.g. job scheduler).
def qsubcommand(func):
def wrapper(*args, **kwargs):
if kwargs.get('test', False):
cmdl = ' '.join(['this.py', func.__name__, *map(str, args)])
return cmdl
else:
return func(*args, **kwargs)
return wrapper
#qsubcommand
def calculate(value1, value2):
# do something
if __name__ == '__main__':
if len(sys.argv) > 1:
func, args = sys.argv[1], sys.argv[2:]
if func in locals().keys():
locals()[func](*args)
else:
raise NotImplementedError
I have a lot of functions like 'calculate'.
I'm working with the script for running and testing a program.
# When I want to run directly:
>>> calculate(4, 5)
# When I want to just print command line:
>>> calculate(4, 5, test=True)
'this.py calculate 4 5'
However, I want to use it in a context-dependent manner like below.
# When I want to run directly:
>>> test = False
>>> calculate(4, 5)
# When I want to just print command line:
>>> test = True
>>> calculate(4, 5)
'this.py calculate 4 5'
How can I modify to let the function recognize the variable outside the scope.
Is it possible to access a variable outside the function?
Thank you for your kind answers in advance.
Just put this on the part of the function where you want to check the variable:
if 'test' in globals() and test:
# do test
else:
# do normal
Functions can always access variables which are outside the function scope, they just can't edit them if you don't use the global keyword.
I'm trying to build a decorator-based dispatcher, such as you find used by Flask or Pyramid. I got something that works, but ran into a bit of a catch-22. The following code works, but only because foo() gets executed and sets the .mq_path-attribute. When starting the application and building a list of the dispatchable functions no attributes are thus set yet. I want to execute foo() driven by events.
I could "manually" prepare a list of functions ahead and updated as I add functions, but I enjoy the way Flask works, by just adding a decorator to a function that handles an URL (or in this case a MQ path).
list_of_paths = []
path_dispatcher = {}
def handle_mq(path):
def decorator(fn):
def decorated(*args,**kwargs):
decorated.mq_path = path
print "Hello from the handle_mq() decorator, your path is: {0}".format(path)
return fn(*args,**kwargs)
return decorated
return decorator
#handle_mq('/some/path')
def foo():
print "foo!"
foo() # <- this code only works if I first call the decorated function
for k, v in globals().items():
if hasattr(v, 'mq_path'):
list_of_paths.append(v.mq_path)
path_dispatcher[v.mq_path] = v
print list_of_paths
print path_dispatcher
path_dispatcher['/some/path']()
So basically the question is, how to gather a list of the decorated functions before they are first executed?
I'm on Python 2.7.
I found the answer!
list_of_paths = []
path_dispatcher = {}
def handle_mq(path):
def decorator(fn):
list_of_paths.append(path)
path_dispatcher[path] = fn
def decorated(*args,**kwargs):
print "Hello from handl_mq decorator, your path is: {0}".format(path)
return fn(*args,**kwargs)
return decorated
return decorator
#handle_mq('/some/path')
def foo():
print "foo!"
print list_of_paths
print path_dispatcher
path_dispatcher['/some/path']()
I try:
def test(w,sli):
s = "'{0}'{1}".format(w,sli)
exec(s)
return s
print test("TEST12344","[:2]")
its return 'TEST12344'[:2]
How to return value from exec in function
Think of running the following code.
code = """
def func():
print("std out")
return "expr out"
func()
"""
On Python Console
If you run func() on the python console, the output would be something like:
>>> def func():
... print("std out")
... return "expr out"
...
>>> func()
std out
'expr out'
With exec
>>> exec(code)
std out
>>> print(exec(code))
std out
None
As you can see, the return is None.
With eval
>>> eval(code)
will produce Error.
So I Made My exec_with_return()
import ast
import copy
def convertExpr2Expression(Expr):
Expr.lineno = 0
Expr.col_offset = 0
result = ast.Expression(Expr.value, lineno=0, col_offset = 0)
return result
def exec_with_return(code):
code_ast = ast.parse(code)
init_ast = copy.deepcopy(code_ast)
init_ast.body = code_ast.body[:-1]
last_ast = copy.deepcopy(code_ast)
last_ast.body = code_ast.body[-1:]
exec(compile(init_ast, "<ast>", "exec"), globals())
if type(last_ast.body[0]) == ast.Expr:
return eval(compile(convertExpr2Expression(last_ast.body[0]), "<ast>", "eval"),globals())
else:
exec(compile(last_ast, "<ast>", "exec"),globals())
exec_with_return(code)
exec() doesn't just evaluate expressions, it executes code. You would have to save a reference within the exec() call.
def test(w, sli):
exec('s = "{}"{}'.format(w, sli))
return s
If you just want to evaluate an expression, use eval(), and save a reference to the returned value:
def test(w,sli):
s = "'{0}'{1}".format(w,sli)
s = eval(s)
return s
However, I would recommend avoiding exec() and eval() in any real code whenever possible. If you use it, make sure you have a very good reason to do so.
My findings in Python 3.8 in 2020
in Eval Logic :
a="1+99"
a=eval(a)
print(a) # output: 100
in exec logic
exec ("a=33+110")
print(a) #output 143
I'm working on a script that takes a few minutes to run, and would like to provide some output to the user about its progress. Unfortunately i'm exceedingly lazy. what I'd like to do is write a function without the logging, and then apply a decorator to it which steps through the function and prints each line before executing that line. Basically what I'm looking for is a loggingdecorator such that:
>>> #loggingdecorator
... def myfunction():
... foo()
... bar()
... baz()
>>> myfunction()
Starting myfunction
foo() ... [OK]
bar() ... [OK]
baz() ... [OK]
myfunction Done!
Here's what I've tried so far:
import sys
def logging_tracer(frame, event, arg):
def local_tracer(local_frame, event, arg):
if frame is local_frame:
print frame.f_code.co_name, event, arg
print frame.f_code.co_name, event, arg
return local_tracer
def loggingdecorator(func):
def _wrapper():
old_trace_function = sys.gettrace()
sys.settrace(logging_tracer)
try:
result = func()
except:
raise
else:
return result
finally:
sys.settrace(old_trace_function)
return _wrapper
Unfortunately, this prints a bit too much; it follows function calls and prints them out, line by line as well (well, this doesn't actually print the source line, existing answers using inspect, combined with stuff on the frame object in the trace function would do it), but I'm a bit stumped as to how the logging_tracer unless the function in question is actually decorated.
So here's what I came up with. #Corley Brigman's comment got me started in the right direction. This is a bit hackey, sys.gettrace/settrace are rather promenently documented as "CPython implementation details", and so this solution should not be expected to work in other implementations. That said, it seems to work out pretty well. The tracing functionality in cpython does not provide any notification of "line finished executing", so the [ok] from my question doesn't really make any sense.
Fixing the recursive tracing issue is just a simple matter of keeping a cache of the functions that were decorated, and then only produce output if the frame being traced is from a function that was decorated.
import inspect
import sys
def logging_tracer(frame, event, arg):
lines, firstline = inspect.getsourcelines(frame)
def local_tracer(local_frame, event, arg):
if event == 'line' and frame is local_frame:
print event, frame.f_lineno,'\t', lines[frame.f_lineno - firstline]
#print event, lines[frame.f_lineno - firstline]
#print frame.f_code.co_name, frame.f_lineno, event, arg
if frame.f_code in LOG_THESE_FUNCTIONS:
print event, frame.f_lineno,'\t', lines[frame.f_lineno - firstline + (event == 'call')]
#print frame.f_code.co_name, event, arg
return local_tracer
else:
return None
LOG_THESE_FUNCTIONS = set()
def loggingdecorator(func):
LOG_THESE_FUNCTIONS.add(func.func_code)
def _wrapper():
old_trace_function = sys.gettrace()
sys.settrace(logging_tracer)
try:
result = func()
except:
raise
else:
return result
finally:
sys.settrace(old_trace_function)
return _wrapper
Here's an ugly example that works if there's only one indentation level:
import inspect
def myDec(func):
temp = list(inspect.getsourcelines(func)[0])
temp.append(' print("{} Done!")\n'.format(func.__name__))
for index in range(len(temp)-2, 0, -1):
temp.insert(index+1, " print('''{}...[OK]''')\n".format(temp[index].strip().rstrip("\n")))
temp.insert(1, ' print("Starting {}")\n'.format(func.__name__))
temp = "".join(temp)
exec(temp)
return locals()[func.__name__]
def foo():
a = 4+5
list_int = range(100)
foo = myDec(foo)
foo()
Really ugly though...
You can do something like this:
>>> class loggingdecorator:
... def __init__(self, func):
... self.func = func
... def __call__(self):
... print "Entering", self.func.__name__
... self.func()
... print "Exited", self.func.__name__
...
Then with each of your functions:
>>> #loggingdecorator
... def func1():
... print "Hello from func1(), how are you doing?"
...
>>> #loggingdecorator
... def func2():
... print "Hello from func2(), Whaddup Dawg...?"
...
>>> func1()
Entering func1
Hello from func1(), how are you doing?
Exited func1
>>> func2()
Entering func2
Hello from func2(), Whaddup Dawg...?
Exited func2
Found the example from this page