Reputation: 1
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?
Upvotes: 0
Views: 476
Reputation: 280181
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.
Upvotes: 1
Reputation: 1907
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
Upvotes: 2
Reputation:
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
Upvotes: 0
Reputation: 1699
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:
Upvotes: 0