I was going throught the basic Flask tutorial which has the following code:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
Also I went through the basics of Python decorators from many websites including Stackoverflow Decorators
I was of the assumption that in the previous code, the function hello will be changed and decorated, and for running the application I need to call the function hello() somewhere. How does Flask determine the name of the function it has to call.
Does just wrapping the function definition with a decorator somehow marks that function? If so, how?
For example in the below code, somewhere down the line I'm calling the function I've decorated:
def decorate(foo):
print("I'm doing a lot of important stuff right now")
def inner():
print("Some stuff 1")
foo()
print("Some stuff 2")
return inner
#decorate
def hello():
print("Hello")
hello()
In decorate, foo is the function you are decorating (in this case, hello). You can store the function in a list or dictionary somewhere, since it's a normal object.
For example:
decorated_functions = []
def decorate(foo):
def inner():
print("Some stuff 1")
foo()
print("Some stuff 2")
decorated_functions.append(inner)
return inner
#decorate
def hello():
print("Hello")
## The above is the same as:
# def hello():
# print("Hello")
# hello = decorate(hello)
print(decorated_functions[0] == hello) # prints True
decorated_functions[0]() # prints "Some stuff 1", "Hello", and "Some stuff 2"
hello() # same as above
Decorators are actually a very simple construct in Python. The following two examples are equivalent:
#foo
def bar():
pass
def bar():
pass
bar = foo(bar)
So your definition of hello in your first example is the equivalent to this:
def hello():
return "Hello World!"
hello = app.route("/")(hello)
The double function calls might be a bit confusing so lets rewrite it like this:
_tempfn = app.route("/")
hello = _tempfn(hello)
So it should be clear now that app.route isn't actually a decorator, it's a function that creates decorators. Now what isn't obvious is what the newly decorator does. Without looking at the source for Flash, it's likely that it adds the function hello to a dictionary member of a app. So app.route is implemented something like this:
class app(object):
def route(self, path):
def decorator(fn):
self.pathmap[path] = fn
return fn
return decorator
Note that this is pretty much a condensed version of the explanation given in the link that Jon Piparsky provided.
The decorator is simply registering the function in a lookup table. Decorators don't need to modify a function in any way, there are so many other useful things, decorators can do.
In fact, decorators in python
#some_decorator
def foo():
pass
are only a short form of
def foo():
pass
foo = some_decorator(foo)
and the function some_decorator can do anything with its arguments and can return any return value, but usually returns a function.
Related
I am trying to learn decorators and have overcome a strange condition while having multiple decorators for a method. I have two decorators #makeupper and #decorator_maker_with_arguments.
#decorator_maker_with_arguments demonstrates how the arguments are accessed inside a decorator. This works perfectly fine by printing the supplied args but I see #makeupper malfunctioning. It prints None. I have put a print statement next to its method definition to see if its called and it printed but never prints the letters in hello() uppercase.
When I comment out #decorator_maker_with_arguments("swadhikar", "c") I see the #makeupper works good. Can someone explain what I am tangling here?
def makeupper(some_fun):
def wrapper(arg1, arg2):
return some_fun(arg1, arg2).upper()
return wrapper
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
"""Decorator make that demonstrates decorators with arguments"""
print "I am a decorator maker and you passed \"{}:{}\" while calling me...".format(decorator_arg1, decorator_arg2)
def my_decorator(fn):
def wrapper(fn_arg1, fn_arg2):
print "I am the wrapper and I can access the method args \"{}:{}\"".format(fn_arg1, fn_arg2)
return wrapper
return my_decorator
#decorator_maker_with_arguments("swadhikar", "c")
#makeupper
def hello(ar1, ar2):
return "Hello User!"
Result:
I am a decorator maker and you passed "swadhikar:c" while calling me...
I am the wrapper and I can access the method args "hello_arg1:another hello arg..."
None
but I see #makeupper malfunctioning. It prints None
makeupper isn't malfunctioning. The outer decorator decorator_maker_with_arguments isn't calling the wrapper of makeupper.
And then you have a None because you're not returning anything from the wrapper of decorator_maker_with_arguments.
The following modifications to decorator_maker reflect the proposed adjustments:
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
"""Decorator make that demonstrates decorators with arguments"""
print "I am a decorator maker and you passed \"{}:{}\" while calling me...".format(decorator_arg1, decorator_arg2)
def my_decorator(fn):
def wrapper(fn_arg1, fn_arg2):
out = fn(fn_arg1, fn_arg2)
print "I am the wrapper and I can access the method args \"{}:{}\"".format(fn_arg1, fn_arg2)
return out
return wrapper
return my_decorator
Output:
I am a decorator maker and you passed "swadhikar:c" while calling me...
I am the wrapper and I can access the method args "hello_arg1:another hello arg..."
HELLO USER!
You could add some syntactic sugar by decorating your wrappers with functool.wraps, but arguably it's necessary, at least if you want to keep things like function names, docstrings, etc.
You can add return statement inside my_decorator wrapper function.
Like following:
def makeupper(some_fun):
def wrapper(arg1, arg2):
return some_fun(arg1, arg2).upper()
return wrapper
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
"""Decorator make that demonstrates decorators with arguments"""
print "I am a decorator maker and you passed \"{}:{}\" while calling me...".format(decorator_arg1, decorator_arg2)
def my_decorator(fn):
def wrapper(fn_arg1, fn_arg2):
print "I am the wrapper and I can access the method args \"{}:{}\"".format(fn_arg1, fn_arg2)
return fn(fn_arg1, fn_arg2)
return wrapper
return my_decorator
#decorator_maker_with_arguments("swadhikar", "c")
#makeupper
def hello(ar1, ar2):
return "Hello User!"
print hello('arg1', 'arg2')
Output:
I am a decorator maker and you passed "swadhikar:c" while calling me...
I am the wrapper and I can access the method args "arg1:arg2"
HELLO USER!
I am trying to use methods of my own class instead of funcons.
But ths code fails due to "syntax error". What am i doing wrong?
from bottle import route, run, template
class controller():
def test(self):
return ("<h1>Its a main page!</h1>")
def hello(self,name):
return "Hello {0}".format(name)
sc = controller()
#route('/test')
sc.test()
#route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
#route('/')
def indexFunc():
return ('<h1>Hello on first App!!</h1>!')
run(host='localhost', port=8080)
sc.test() returns a string. You can't decorate a string. So the first problem is, you are calling that method (and therefore trying to decorate its result) instead of decorating the method itself.
The second problem is that the # decorator syntax must be followed by a function definition, i.e., a def keyword. You could write a function that does nothing but call sc.test(), as shown by llyas. Or you can take advantage of the fact that the # is simply syntactic sugar for a function call, and just write:
route('/test')(sc.test)
You cannot decorate a function call, you decorate a function definition.
Try replacing this line:
sc.test()
wiith this:
#route('/test')
def view():
return sc.test()
I am trying to use bottle.py to build some webpages. It seems like a major part of using bottle is learning to use decorators but I have read the python docs explanation of what decorators are but I am still not sure I understand them.
The docs say:
"A Python decorator is a specific change to the Python syntax that allows us to more conveniently alter functions and methods (and possibly classes in a future version)."
It sounds like you are calling a function with some changes made but I am not sure why you would do it this way or how to read the decorator.
Looking at some bottle code:
if __name__ == '__main__':
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static').replace('\\', '/')
HOST = os.environ.get('SERVER_HOST', 'localhost')
try:
PORT = int(os.environ.get('SERVER_PORT', '5555'))
except ValueError:
PORT = 5555
#bottle.route('/static/<filepath:path>')
def server_static(filepath):
"""Handler for static files, used with the development server.
When running under a production server such as IIS or Apache,
the server should be configured to serve the static files."""
return bottle.static_file(filepath, root=STATIC_ROOT)
# Starts a local test server.
bottle.run(server='wsgiref', host=HOST, port=PORT)
What does this line do #bottle.route('/static/<filepath:path>')?
If its a fancy function call then why do it this way rather than just calling the function?
Thanks for your help! :D
Check out this code:
def my_decorator(func):
return lambda: print("goodbye")
def greet():
print('hello')
result = my_decorator(greet)
result()
--output:--
goodbye
The following is a shortcut to accomplish the same thing:
def my_decorator(func):
return lambda: print("goodbye")
#my_decorator
def greet():
print('hello')
greet()
--output:--
goodbye
The #my_decorator syntax takes the function below it, greet, and makes this call:
greet = my_decorator(greet)
The my_decorator() function has to be defined so that:
It takes a function as an argument.
Returns a function.
A Python decorator is a specific change to the Python syntax that
allows us to more conveniently alter functions and methods (and
possibly classes in a future version).
Okay, so let's say that you want to add to whatever the greet() function does:
def my_decorator(func): # func = greet
def add_to_greet():
func() #<*********This is greet()
print('world') #<***This is additional stuff.
return add_to_greet
#my_decorator
def greet():
print('hello')
greet()
--output:--
hello
world
What does this line do #bottle.route('/static/<filepath:path>')
Okay, are you ready? If the #some_name syntax specifies an argument, for instance:
#wrapper('world')
def do_stuff():
First python will execute the following call:
#wrapper('world')
def do_stuff():
...
#****HERE:
decorator = wrapper('world') #decorator is a newly created variable
The wrapper() function must be defined to:
Take any old argument, e.g. 'world'
Return a function that:
Takes a function as an argument.
Returns a function.
Secondly, python will execute the call:
#wrapper('world')
def do_stuff():
...
decorator = wrapper('world')
#*****HERE:
do_stuff = decorator(do_stuff)
Whew! Here is an example:
def wrapper(extra_greeting):
def my_decorator(func):
def add_to_greet():
func()
print(extra_greeting)
return add_to_greet
return my_decorator
#wrapper('world')
def greet():
print('hello')
greet()
--output:--
hello
world
Now, let's analyze this decorator:
#bottle.route('/static/<filepath:path>')
def server_static(filepath):
bottle -- a module
route -- a function(or other callable) defined in the bottle module
'/static/<filepath:path>' -- a route
So the bottle module might look like this:
#bottle.py
def route(your_route): #your_route <= '/static/<filepath:path>'
def my_decorator(func): #The decorator syntax will cause python to call this function with server_static as the argument
def do_stuff(filepath):
func(filepath) #Call the server_static() function with the part of the url that matched filepath
return do_stuff #This function will be called when your code calls server_static(...)
return my_decorator
If its a fancy function call then why do it this way rather than just
calling the function?
Advanced stuff.
Comment: Perhaps you forgot to explain what specifically that route decorator does?
#route('/hello')
def hello():
return "Hello World!"
The route() decorator binds a piece of code to an URL path. In this
case, we link the /hello path to the hello() function. This is called
a route (hence the decorator name) and is the most important concept
of this framework. You can define as many routes as you want. Whenever
a browser requests a URL, the associated function is called and the
return value is sent back to the browser. It’s as simple as that.
http://bottlepy.org/docs/dev/tutorial.html
A path can include wild cards:
The simplest form of a wildcard consists of a name enclosed in angle
brackets (e.g. <name>)....Each wildcard matches one or more
characters, but stops at the first slash (/).
The rule /<action>/<item> matches as follows:
Path Result
/save/123 {'action': 'save', 'item': '123'}
/save/123/ No Match
/save/ No Match
//123 No Match
Filters are used to define more specific wildcards, and/or transform
the matched part of the URL before it is passed to the callback. A
filtered wildcard is declared as <name:filter>
The following standard filters are implemented:
:path matches all characters including the slash character in a non-greedy way and may be used to match more than one path
segment.
http://bottlepy.org/docs/dev/routing.html
A decorator is just a function wrapper, it takes some computable and surround it with more computables, technically a decorators is a function that returns a function(or an object, in fact there are decorator classes).
Lets say for example you want to make a logger decorator, this logger decorator will execute something and log who is executing it:
def loggger(name):
def wrapper(f):
def retF(*args, **kwargs):
print name, "is executing"
f(*args, **kwargs)
return retF
return wrapper
So, we have our decorator that will print "Daniel is executing" before call our desired function, for example
#logger("Daniel")
def add2Nums(a,b):
return a+b
>>> add2Nums(1,2)
>>> Daniel is executing
>>> 3
Bottle just works the same way, in the
#bottle.route('/static/<filepath:path>')
it just wrapps your server_static call so whenever some acces that route your function is called.
I am trying to understand the usage of #main annotation in python.
With the below python program,
def cube(x):
return x * x * x
def run_tests():
printf("Should be 1:", cube(1))
printf("Should be 8:", cube(2))
printf("Should be 27:", cube(3))
#main
def main():
print("Starting")
run_tests()
print("Ending.")
I get the following error:
PS C:\Users\MOHET01\Desktop> python.exe -i .\cube.py
Traceback (most recent call last):
File ".\cube.py", line 9, in <module>
#main
NameError: name 'main' is not defined
>>>
Function that is imported from ucb is as shown below:
def main(fn):
"""Call fn with command line arguments. Used as a decorator.
The main decorator marks the function that starts a program. For example,
interact()
#main
def my_run_function():
# function body
Use this instead of the typical __name__ == "__main__" predicate.
"""
if inspect.stack()[1][0].f_locals['__name__'] == '__main__':
args = sys.argv[1:] # Discard the script name from command line
print(args)
print(*args)
print(fn)
fn(*args) # Call the main function
return fn
My question:
Despite i define function with intrinsic name main, Why do i see this error?
I should use this:
def main():
#Do something
if __name__ == "__main__":
#Here use the method that will be the main
main()
I hope this helps
The #main decorator is implemented in a file your course provides, but you have not imported it. The page you linked says to use
from ucb import main, interact
to import the ucb.py features in your program.
As for why the error says name 'main' is not defined, that's because the function definition doesn't actually finish defining anything until the decorators execute. The reuse of the name main for both the decorator and the decorated function is confusing; the main in #main is a different function from the main you're defining in def main(): .... The main in #main is defined to run the decorated function if the file is run as a script, while the main in def main(): ... is the function to be run.
I would strongly recommend not using anything like this decorator when you don't have to. The standard way to perform the task the decorator performs is to write
if __name__ == '__main__':
whatever_function_you_would_have_put_the_decorator_on()
or if you want to handle command line arguments like the decorator would,
if __name__ == '__main__':
import sys
whatever_function_you_would_have_put_the_decorator_on(*sys.argv[1:])
The decorator is an attempt to hide the issues of sys.argv and __name__ so you don't have to know about them, but it has a problem. If you try to write something like this:
#main
def hello():
print(hello_string)
hello_string = 'Hi there.'
you'll get a NameError, because hello_string won't be assigned until after the decorator runs. If you continue to write Python beyond this course, you'll find that using if __name__ == '__main__' is less bug-prone and more understandable to other programmers than using a decorator for this.
You are using the function before it is defined. In other words, you need to define the main function higher up (in the document) than where you use it as a decorator:
def main():
pass
#main
def somefunction():
pass
The #main notation means the main function is being used to "decorate", or modify, another function. There are various articles on python decorators:
http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
http://www.artima.com/weblogs/viewpost.jsp?thread=240808
http://www.jeffknupp.com/blog/2013/11/29/improve-your-python-decorators-explained/
You can only use a decorator on a different function. Example:
def foo(f):
def inner():
print("before")
f()
print("after")
return inner
#foo
def bar():
print("bar")
if __name__ == "__main__":
bar()
Output:
before
bar
after
I have a static class that has a method hello. I want to run the decorator method bar before hello. However, using the following code I always get a "name 'bar' is not defined" error. Does anyone know what's going on? Thanks!
class foo():
#staticmethod
#bar
def hello():
print "hello"
def bar(fn):
def wrapped():
print "bar"
return fn()
return wrapped
foo.hello()
Because it's not defined yet. Besides, that decorator shouldn't be a method at all.
def bar(fn):
# ...
class foo(object):
#staticmethod
#bar
def hello():
# ...
# ...
Also, don't use static methods, unless you really know what you're doing. Make it a free function instead.
You can just change your code to:
def bar(fn):
def wrapped():
print "bar"
return fn()
return wrapped
class foo():
#staticmethod
#bar
def hello():
print "hello"
foo.hello()
This happens because you have to define a function before you call it. This is a problem because this:
#bar
def hello():
print "hello"
is equivalent to:
def hello():
print "hello"
hello = bar(hello)
So you were trying to call the function before you defined it.