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.
Related
I was looking around the aiortc examples when I notice a decorator that has a method on it:
#pc.on("datachannel")
def on_datachannel(channel):
...
I don't really understand how this work or what does this code do. I've been searching about decorators and I know it's possible to have class decorators but none about using methods. Can anyone elaborate on this?
#foo
def bar(): ...
This syntax is merely sugar for this:
def bar(): ...
bar = foo(bar)
So, this:
#pc.on('datachannel')
def on_datachannel(channel): ...
is the same as:
def on_datachannel(channel): ...
on_datachannel = pc.on('datachannel')(on_datachannel)
pc is some object, pc.on is a method on it, pc.on('datachannel') calls it and it returns a function, pc.on('datachannel')(on_datachannel) calls that returned function passing it the on_datachannel function.
The implementation of pc.on is something like this:
class PC:
def on(self, event):
...
def wrapper(fn):
...
def inner_wrapper(*args, **kwargs):
...
fn(*args, **kwargs)
return inner_wrapper
return wrapper
pc = PC()
All that inner part is entirely a regular decorator accepting arguments. That it's defined on a class makes no difference to it.
I'm going to pass a function dynamically to another class as shown below
class simulator(object):
def __init__(self, fn_):
print(self.test(fn_))
def test(self, fn):
return fn(self, 20)
class t(object):
s = 'def get_fitness(x, y):\n return x+y'
exec(s)
def fnGetFitness(self,genes):
return get_fitness(genes, 10)
simulator(fnGetFitness)
t()
but i face error below:
File "N:/Job/GA/mine/dyn.py", line 25, in fnGetFitness
return get_fitness(genes, 10)
NameError: name 'get_fitness' is not defined
i guess its something related to scopes but i can't handle it
anyone on this?
EDIT :
this is a simpler code, showing the problem :
class t(object):
def __init__(self):
exec('def get_fitness(x, y):\n return x+y')
print(get_fitness(2,3))
t()
nothing to do with exec. What you're doing is equivalent (with safety removed) to:
class t(object):
def get_fitness(x,y):
return x+y
but your method definition is at class level, but not on the simulator class.
simulator(fnGetFitness) calls fnGetFitness out of t class context, so it doesn't know your new function.
That cannot work (also get_fitness should be decorated as #staticmethod because it doesn't have a self parameter)
What works is to define dynamically (or not) the function at global level so class can call it
s = 'def get_fitness(x, y):\n return x+y'
exec(s)
class t(object):
def fnGetFitness(self,genes):
return get_fitness(genes, 10)
simulator(fnGetFitness)
t()
that fixed it, but honestly I'm puzzled about the purpose (already took me a while to figure out how to make something run from your code)
EDIT: a simpler and somehow different (and exec related) code has been posted in comments:
class t(object):
def __init__(self):
exec('def get_fitness(x, y):\n return x+y')
print(get_fitness(2,3))
t()
this raises NameError: name 'get_fitness' is not defined
now this has to do with exec. When __init__ is parsed, get_fitness isn't known because the parser didn't see it as a local variable, even if at the time of execution, it is set in locals() dictionary by exec (related: why is 'ord' seen as an unassigned variable here?).
A workaround is to fetch the function in the local variables like this:
class t(object):
def __init__(self):
exec('def get_fitness(x, y):\n return x+y')
print(locals()["get_fitness"](2,3))
t()
this works & prints 5.
My Understanding:
Based on what I understand about decorator, the following code
def myDecorator(func):
...
#myDecorator
def myFunc()
is equivalent to
myFunc = myDecorator(myFunc)
My Experiment
So I'm playing around with this concept with the following code
def myDecorator(func):
func()
#myDecorator
def myFunc():
print("MyFunc is run")
#myDecorator
def myFunc2():
print("MyFunc2 is run")
myFunc
The output is
MyFunc is run
MyFunc2 is run
My Question
What happen? Why the line MyFunc2 is run is printed? Aren't myFunc is equivalent to myFunc = myDecorator(myFunc)? If this is the case why myFunc2 statement is run?
You are passing a function object to the myDecorator() function. That function receives the function object as the func parameter. You then call that function with func().
You are right that #myDecorator on a function object causes that decorator to be called, with the function object being passed in. But you seem to be confused about when that happens. It happens the moment Python executes the def statement:
>>> def myDecorator(func):
... func()
...
>>> #myDecorator
... def foo():
... print('The foo() function is called')
...
The foo() function is called
Note that because myDecorator() has no return statement, foo is now bound to None:
>>> foo is None
True
Your last line, myFunc, does nothing more than just reference the None object. You didn't call it, so that expression does not cause anything to be printed. You can't call it, because None is not callable.
For the sake of completness - a "generic" correct decorator returns a new function object, taht then replaces the original function in the scope it was declared:
def myDecorator(func):
def wrapper(*args, **kwargs):
"""Calls original function with whatever parameters
and returns its return value.
"""
print("Running decorator code")
return func(*ars, **kwargs)
# Returns the newly created 'wrapper' function
# that will replace the original "func"
return wrapper
#myDecorator
def myFunc():
print("MyFunc is run")
#myDecorator
def myFunc2():
print("MyFunc2 is run")
myFunc()
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.
I have a module where I want to call a method not defined in that module. Is it possible?
#module
def foo():
print bar()
#main
from foo import foo
def bar():
return "Foo bar"
def main():
foo.foo()
No, you cannot. Python looks up undefined names in the same module a function is defined in.
You'll have to pass in a function reference instead:
def foo(func):
print func()
then in main:
def main():
foo.foo(bar)
You could add the function from one module to the other, but passing it as a callback is probably neater. It depends on the situation.
#module
def foo(bar):
print bar()
#main
from foo import foo
def bar():
return "Foo bar"
def main():
foo(bar)