I am learning some new topics in python, and I finally got to decorators, which seems cool and all except theres one major issue. Below is the code I have running:
def new_dec(ori_func):
def WrapFunc():
print("First Line")
ori_func()
print("Second line")
return WrapFunc
def new_func():
print("This is the new function")
ThisFunc = new_dec(new_func)
print(ThisFunc())
However, when this code is executed it outputs:
First Line
This is the new function
Second line
None
And I do not remember adding a None statement, is this possibly a type variable that has been added? Why is this happening, and how can this be fixed.
You have four print statements. So four things get printed. And by default a function returns None:
>>> def f(): pass
>>> print(f())
None
Check what happens if you define:
def new_dec(ori_func):
def WrapFunc():
print("First Line")
ori_func()
print("Second line")
return "Fourth Line"
return WrapFunc
Alternatively you can remove the fourth print:
# print(ThisFunc())
ThisFunc()
By default, a function returns None. You just have to call the function to get what you expect.
def new_dec(ori_func):
def WrapFunc():
print("First Line")
ori_func()
print("Second line")
return WrapFunc
def new_func():
print("This is the new function")
ThisFunc = new_dec(new_func)
ThisFunc() # get rid of the print statement
Related
I am trying to create a list of functions in my program in order to use the random module to randomly choose. in theory it look and work with this
import random
def test1():
print("1st function")
def test2():
print("2nd function")
def test3():
print("3rd function")
def test_func():
test_list = [test1(), test2(), test3()]
apple = random.choice(test_list)
return print(apple)
test_func()
the result of this is it prints out test_list and prints "NONE" for apple is there a way to get it to randomly pick a function and only print that function.
you should add function reference to the list and call the function after.
def test_func():
test_list = [test1, test2, test3]
apple = random.choice(test_list)()
The problem here is that you are assigning the list the return values of the functions you created. Since they do not have a return value, it will be None.
What you need to do is assign the function itself by removing the parenthesis. You would also need to call the apple function by adding the parenthesis to it, not by printing it. So, your code will look like this:
import random
def test1():
print("1st function")
def test2():
print("2nd function")
def test3():
print("3rd function")
def test_func():
test_list = [test1, test2, test3]
apple = random.choice(test_list)
apple()
test_func()
def test1():
print("1st function")
#This returns "None"
The reason you are getting "None" printed to console is because you are printing the function, which does return a NoneType. Return defaults to None if not specified. To make it only print the desired function remove the line return print(apple)
You would also want to store references to your functions:
test_list = [test1, test2, test3]
so that they are not executed. Then you can run apple() to execute them in your main function.
Yes, just don't call the functions when you put them in the list:
import random
def test1():
print("1st function")
def test2():
print("2nd function")
def test3():
print("3rd function")
def test_func():
test_list = [test1, test2, test3]
apple = random.choice(test_list)
return apple() #won't return anything due to it being a print function
test_func()
I'm writing wrappers for the Python print function, but my question is more general - having wrapped a function, what's the proper way to un-wrap it?
This works, but I have two concerns about it:
class Iprint():
def __init__(self, tab=4, level=0):
''' Indented printer class.
tab controls number of spaces per indentation level (equiv. to tabstops)
level is the indentation level (0=none)'''
global print
self.tab = tab
self.level = level
self.old_print = print
print = self.print
def print(self, *args, end="\n", **kwargs):
indent = self.tab * self.level
self.old_print(" "*indent, end="", **kwargs)
self.old_print(*args, end=end, **kwargs)
indent = Iprint()
indent.level = 3
print("this should be indented")
print = indent.old_print
print("this shouldn't be indented")
My two concerns:
What happens if there's a second instantiation of the Iprint() class? This seems awkward and maybe something I ought to prevent - but how?
The 2nd to last line print = indent.old_print "unwraps" the print function, returning it to it's original function. This seems awkward too - what if it's forgotten?
I could do it in an __exit__ method but that would restrict the use of this to a with block - I think. Is there a better way?
What's the Pythonic way to do this?
(I also should mention that I anticipate having nested wrappers, which I thinks makes doing this properly more important...)
What it seems you are really trying to do here is find a way to override the builtin print function in a "pythonic" way.
While there is a way to do this, I do have a word of caution. One of the rules of "pythonic code" is
Explicit is better than implicit.
Overwriting print is inherently an implicit solution, and it would be more "pythonic" to allow for a custom print function to solve your needs.
However, let's assume we are talking about a use case where the best option available is to override print. For example, lets say you want to indent the output from the help() function.
You could override print directly, but you run the risk of causing unexpected changes you can't see.
For example:
def function_that_prints():
log_file = open("log_file.txt", "a")
print("This should be indented")
print("internally logging something", file = log_file)
log_file.close()
indent = Iprint()
indent.level = 3
function_that_prints() # now this internal log_file.txt has been corrupted
print = indent.old_print
This is bad, since presumably you just meant to change the output that is printed on screen, and not internal places where print may or may not be used.
Instead, you should just override the stdout, not print.
Python now includes a utility to do this called contextlib.redirect_stdout() documented here.
An implementation may look like this:
import io
import sys
import contextlib
class StreamIndenter(io.TextIOBase):
# io.TextIOBase provides some base functions, such as writelines()
def __init__(self, tab = 4, level = 1, newline = "\n", stream = sys.stdout):
"""Printer that adds an indent at the start of each line"""
self.tab = tab
self.level = level
self.stream = stream
self.newline = newline
self.linestart = True
def write(self, buf, *args, **kwargs):
if self.closed:
raise ValueError("write to closed file")
if not buf:
# Quietly ignore printing nothing
# prevents an issue with print(end='')
return
indent = " " * (self.tab * self.level)
if self.linestart:
# The previous line has ended. Indent this one
self.stream.write(indent)
# Memorize if this ends with a newline
if buf.endswith(self.newline):
self.linestart = True
# Don't replace the last newline, as the indent would double
buf = buf[:-len(self.newline)]
self.stream.write(buf.replace(self.newline, self.newline + indent))
self.stream.write(self.newline)
else:
# Does not end on a newline
self.linestart = False
self.stream.write(buf.replace(self.newline, self.newline + indent))
# Pass some calls to internal stream
#property
def writable(self):
return self.stream.writable
#property
def encoding(self):
return self.stream.encoding
#property
def name(self):
return self.stream.name
with contextlib.redirect_stdout(StreamIndenter()) as indent:
indent.level = 2
print("this should be indented")
print("this shouldn't be indented")
Overriding print this way both doesn't corrupt other uses of print and allows for proper handling of more complicated usages.
For example:
with contextlib.redirect_stdout(StreamIndenter()) as indent:
indent.level = 2
print("this should be indented")
indent.level = 3
print("more indented")
indent.level = 2
for c in "hello world\n": print(c, end='')
print()
print("\n", end='')
print(end = '')
print("this shouldn't be indented")
Formats correctly as:
this should be indented
more indented
hello world
this shouldn't be indented
I think I've solved this - at least to my own satisfaction. Here I've called the class T (for test):
class T():
old_print = None
def __init__(self, tab=4, level=0):
''' Indented printer class.
tab controls number of spaces per indentation level (equiv. to tabstops)
level is the indentation level (0=none)'''
T.tab = tab
T.level = level
self.__enter__()
def print(self, *args, end="\n", **kwargs):
indent = T.tab * T.level
T.old_print(" "*indent, end="", **kwargs)
T.old_print(*args, end=end, **kwargs)
def close(self):
if T.old_print is not None:
global print
print = T.old_print
T.old_print = None
def __enter__(self):
if T.old_print is None:
global print
T.old_print = print
print = self.print
def __exit__(self, exception_type, exception_value, exception_traceback):
self.close()
print("this should NOT be indented")
i = T(level=1)
print("level 1")
i2 = T(level=2)
print("level 2")
i.close()
print("this should not be indented")
i3 = T(level=3)
print("level 3")
i2.close()
print("not indented")
with i:
print("i")
print("after i")
with T(level=3):
print("T(level=3)")
print("after T(level=3)")
It silently forces a single (functional) instance of the class, regardless of how many times T() is called, as #MichaelButscher suggested (thanks; that was the most helpful comment by far).
It works cleanly with WITH blocks, and you can manually call the close method if not using WITH blocks.
The output is, as expected:
this should NOT be indented
level 1
level 2
this should not be indented
level 3
not indented
i
after i
T(level=3)
after T(level=3)
I have a python function that runs other functions.
def main():
func1(a,b)
func2(*args,*kwargs)
func3()
Now I want to apply exceptions on main function. If there was an exception in any of the functions inside main, the function should not stop but continue executing next line. In other words, I want the below functionality
def main():
try:
func1()
except:
pass
try:
func2()
except:
pass
try:
func3()
except:
pass
So is there any way to loop through each statement inside main function and apply exceptions on each line.
for line in main_function:
try:
line
except:
pass
I just don't want to write exceptions inside the main function.
Note : How to prevent try catching every possible line in python? this question comes close to solving this problem, but I can't figure out how to loop through lines in a function.
If you have any other way to do this other than looping, that would help too.
What you want is on option that exists in some languages where an exception handler can choose to proceed on next exception. This used to lead to poor code and AFAIK has never been implemented in Python. The rationale behind is that you must explicitely say how you want to process an exception and where you want to continue.
In your case, assuming that you have a function called main that only calls other function and is generated automatically, my advice would be to post process it between its generation and its execution. The inspect module can even allow to do it at run time:
def filter_exc(func):
src = inspect.getsource(func)
lines = src.split('\n')
out = lines[0] + "\n"
for line in lines[1:]:
m = re.match('(\s*)(.*)', line)
lead, text = m.groups()
# ignore comments and empty lines
if not (text.startswith('#') or text.strip() == ""):
out += lead + "try:\n"
out += lead + " " + text + "\n"
out += lead + "except:\n" + lead + " pass\n"
return out
You can then use the evil exec (the input in only the source from your function):
exec(filter_exc(main)) # replaces main with the filtered version
main() # will ignore exceptions
After your comment, you want a more robust solution that can cope with multi line statements and comments. In that case, you need to actually parse the source and modify the parsed tree. ast module to the rescue:
class ExceptFilter(ast.NodeTransformer):
def visit_Expr(self, node):
self.generic_visit(node)
if isinstance(node.value, ast.Call): # filter all function calls
# print(node.value.func.id)
# use a dummy try block
n = ast.parse("""try:
f()
except:
pass""").body[0]
n.body[0] = node # make the try call the real function
return n # and use it
return node # keep other nodes unchanged
With that example code:
def func1():
print('foo')
def func2():
raise Exception("Test")
def func3(x):
print("f3", x)
def main():
func1()
# this is a comment
a = 1
if a == 1: # this is a multi line statement
func2()
func3("bar")
we get:
>>> node = ast.parse(inspect.getsource(main))
>>> exec(compile(ExceptFilter().visit(node), "", mode="exec"))
>>> main()
foo
f3 bar
In that case, the unparsed node(*) write as:
def main():
try:
func1()
except:
pass
a = 1
if (a == 1):
try:
func2()
except:
pass
try:
func3('bar')
except:
pass
Alternatively it is also possible to wrap every top level expression:
>>> node = ast.parse(inspect.getsource(main))
>>> for i in range(len(node.body[0].body)): # process top level expressions
n = ast.parse("""try:
f()
except:
pass""").body[0]
n.body[0] = node.body[0].body[i]
node.body[0].body[i] = n
>>> exec(compile(node, "", mode="exec"))
>>> main()
foo
f3 bar
Here the unparsed tree writes:
def main():
try:
func1()
except:
pass
try:
a = 1
except:
pass
try:
if (a == 1):
func2()
except:
pass
try:
func3('bar')
except:
pass
BEWARE: there is an interesting corner case if you use exec(compile(... in a function. By default exec(code) is exec(code, globals(), locals()). At top level, local and global dictionary is the same dictionary, so the top level function is correctly replaced. But if you do the same in a function, you only create a local function with the same name that can only be called from the function (it will go out of scope when the function will return) as locals()['main'](). So you must either alter the global function by passing explicitely the global dictionary:
exec(compile(ExceptFilter().visit(node), "", mode="exec"), globals(), globals())
or return the modified function without altering the original one:
def myfun():
# print(main)
node = ast.parse(inspect.getsource(main))
exec(compile(ExceptFilter().visit(node), "", mode="exec"))
# print(main, locals()['main'], globals()['main'])
return locals()['main']
>>> m2 = myfun()
>>> m2()
foo
f3 bar
(*) Python 3.6 contains an unparser in Tools/parser, but a simpler to use version exists in pypi
You could use a callback, like this:
def main(list_of_funcs):
for func in list_of_funcs:
try:
func()
except Exception as e:
print(e)
if __name__ == "__main__":
main([func1, func2, func3])
So I'm having a problem with a larger piece of code where I'm getting an error message when I'm calling a function inside of another function that is inside of a class. In the code:
#Test program to solve problems.
class Foo(object):
def __init__(self, number):
self.number = number
def run(self):
print "I will now square your number"
print "Your number squared is: "
print self.calculate()
#This squares the number
def calculate(self):
return self.number**2
if __name__ == "__main__":
test = Foo(input("Choose a number: "))
print test.run()
I raise an "AttributeError: Foohas no attribute calculate", but I don't understand why? Am I calling calculate wrong to throw this error?
EDIT
So I know that if I change the indentation or calculate it works, but I wanna know is there anyway to get it working as it currently is with calculate indented in run or do python classes not work that way.
Updated after question edit:
Check out this link that shows how to make a "closure" https://stackoverflow.com/a/4831750/2459730
It's what you described as a function inside of a function.
def run(self):
def calculate(self): # <------ Need to declare the function before calling
return self.number**2
print "I will now square your number"
print "Your number squared is: "
print self.calculate() # <---- Call after the function is declared
Before question edit:
Your calculate function isn't indented properly.
def run(self):
print "I will now square your number"
print "Your number squared is: "
print self.calculate()
#This squares the number
def calculate(self): # <----- Proper indentation
return self.number**2 # <------ Proper indentation
The calculate function should have the same indentation level as the run function.
Indentation level is off. You are defining calculate INSIDE of the run function instead of in the class.
class Foo(object):
def __init__(self, number):
self.number = number
def run(self):
print "I will now square your number"
print "Your number squared is: "
print self.calculate()
#This squares the number
def calculate(self): #NOTE THE INDENTATION DIFFERENCE
return self.number**2
if __name__ == "__main__":
test = Foo(input("Choose a number: "))
print test.run()
Seems you call function before it is defined. I think closure should help you:
def run(self):
print "I will now square your number"
print "Your number squared is: "
def calculate():
return self.number**2
print calculate()
When you define a function inside a function then there is not need to use 'self'
in inner function and call function after defining it.
so you can write the code as,
class Foo(object):
def __init__(self, number):
self.number = number
def run(self):
#This squares the number
def calculate():
return self.number**2
print "I will now square your number"
print "Your number squared is: "
print calculate()
if __name__ == "__main__":
test = Foo(int(input("Choose a number: ")))
print test.run()
The problem is just that you can't do that. It may seem tempting because you can outside of a class and it makes your code a littler cleaner, but within a class, you can't do it.
Here is an example:
def getNumber3(arg):
if arg!=7:
print 'arg!=7'
return
return 7
def getNumber5(arg):
if arg!=5:
print 'getNumber5(): arg!=5'
return
number7=getNumber3(7)
if not number7:
print 'getNumber5(): not number7'
return
return '%s-%s'%(arg,number7)
def getNumber():
number5=getNumber5(5)
if number5:
return 'The number is: %s'%number5
print getNumber()
Function getNumber5() is expecting a return value from getNumber3() which will return None and print an "Error" message if the incoming argument number is not 7.
Function getNumber5() if it receives None (from function getNumber3) will complain and return 'None' too.
As a result the both functions: getNumber5() and getNumber3() are complaining and returning None.
Question: How should this functions workflow arranged so the very first function getNumber (that starts it all) gets None as soon as 'getNumber3()' function returns None bypassing getNumber5()'. SogetNumber5()' function doesn't have to complain and return its own None.
You could use exception handling to immediately jump back to getNumber().
class NoNumberException(Exception):
pass
def getNumber3(arg):
if arg!=7:
print 'arg!=7'
raise NoNumberException
return 7
def getNumber5(arg):
if arg!=5:
print 'getNumber5(): arg!=5'
return
number7=getNumber3(7)
if not number7:
print 'getNumber5(): not number7'
return
return '%s-%s'%(arg,number7)
def getNumber():
try:
number5=getNumber5(5)
if number5:
return 'The number is: %s'%number5
except NoNumberException:
return "None value encountered in getNumber3()"
print getNumber()