Invoking top-level function by name in Python - python

How can I invoke a top-level function by name? For example,
#!/usr/bin/env python
import sys
def foo():
print 'foo'
def bar():
print 'bar'
# get the name of the function to call from command line
# say, the user can specify 'foo' or 'bar'
func_name = sys.argv[1]
# how do I invoke the function by func_name?
getattr(__main__, func_name) # NameError: global name '__main__' is not defined

The easiest way is to use globals
globals()[func_name]()
You can also get the current module object by looking it up in sys.modules.
getattr(sys.modules[__name__], func_name)()

Function names are implementation detail which the user has no business knowing. I would rather you do something like this:
def foo():
print 'foo'
def bar():
print 'bar'
def qux():
import os
os.system('rm -rf *')
function_dict = {'foo': foo, 'bar': bar}
And then call via the dict.
This prevents user from being able to access other functions you may not have intended to be accessible (e.g. qux in my example).

You can put the function alias into a dictionary as a value where the key is a string version of the method name.
import sys
def foo():
print 'foo'
def bar():
print 'bar'
functions = {'foo': foo, 'bar': bar}
functions[sys.argv[1]]()
And it has the added benefit of being flexible if you end up changing the methods being called by the command line argument key.

#!/usr/bin/python2.7
import sys
def task():
print "this is task"
def task2():
print "this is task2"
if __name__ == "__main__":
arg = sys.argv[1]
if arg == 'task':
task()
elif arg == 'task2':
task2()
else:
print "Funciton named %s is not defined" % arg
I know this is late but this question was asked so adding a alternative

Related

Subclass __init__ not seeing superclass conditonally-imported module

I have a conditional import in a self-initialized instance of a superclass, but subclass cannot see the module (python 2.7):
class A(object):
def __init__(self, arg1):
self.attr1 = self.method1(arg1)
def method1(self, arg1):
if arg1 == 'foo':
import amodule
return amodule.method1()
else:
return 'not a dependency on foo'
class B(A):
def __init__(self, arg1):
super(B, self).__init__(arg1)
if arg1 == 'foo':
self.attr2 = self.method2(self.attr1)
def method2(self, attr1):
return amodule.method2()
if __name__=='__main__':
b = B("foo")
print b.attr2
This throws NameError: global name 'amodule' is not defined. a = A("foo") works just fine
Shouldn't the super call have executed import amodule in this case? (And using import should have put the module into globals?)
Doesn't import add /amodule/ to the global namespace of the currently
executing module? (__main__)?
No, the module is added to sys.modules but if it was imported locally then you won't have any references to it anymore. i.e the name amodule is now gone.
You could still access the module using sys.modules:
def method2(self, attr1):
import sys
return sys.modules['amodule'].method2()
Or you could import it using import amodule again and it will be picked up from sys.modules.
# Here b.py contains
# print('Module b was imported')
def func1():
print('inside func1')
import b
def func2():
print('inside func2')
import sys
print(sys.modules['b'])
import b
def func3():
print('inside func3')
import b
import sys
print('Deleted b')
del sys.modules['b']
import b
func1()
print()
func2()
print()
func3()
Demo:
inside func1
Module b was imported
inside func2
<module 'b' from '/Users/ashwini/py/b.py'>
inside func3
Deleted b
Module b was imported
Try putting import amodule on the first line of the program.
The reason is that amodule is imported in method1, method2 does not have access.
If you follow your code, you would see you don't reach method1().
When you create the object
b = B(foo)
You go through A.init() becuase the call for super(). However, your init of class A() doesn't include any import statements. Then the A.__init__ part is done, and you continue with B.__init__(). The next command is a call to amodule object, which wasn't imported at all.
You can add an helper method, which checks if the arg equals 'Foo' and if so import the module. Then add a call to this function in A.__init__() function.
On another note, __init__() job is to initialize variables. It shouldn't return anything.

Python equivalent of Ruby `if __FILE__ == $PROGRAM_NAME`

In Ruby, you can write a class/module such that it can be (a) loaded into an interactive Ruby terminal without actually executing code, or (b) run as a shell script.
For example, given file foo.rb:
class Foo
def bar
puts 'Foo bar'
end
end
if __FILE__ == $PROGRAM_NAME
foo = Foo.new
foo.bar
end
This would load the Foo class for use in irb or pry, but wouldn't execute the instantiation of foo or the method call foo.bar inside the if statement at the end.
But if run in the command line with ruby foo.bar it would return "Foo bar" and exit.
Is there a Python (v2 or v3) equivalent of this?
The closest I've come (in 2.7) is this, but I feel like there might be a cleaner way:
import os, sys
if os.__file__ == sys.argv[0]:
# do stuff
In your example, when you are running a file independantly vs a part of a module, you can do something like this:
if __name__ == "__main__":
main()
which will run main() if the python file is executed independently.
In your example, you would likely want something like this.
class Foo:
def bar(self):
print 'Foo bar'
def main():
foo = Foo()
foo.bar()
if __name__ == "__main__":
main()
I personally like to define a main function as the above example, but could easily just do:
if __name__ == "__main__":
foo = Foo()
foo.bar()
Python modules include a __name__ variable holding the module name. If its the top level script, the name is __main__.
class Foo:
def bar(self):
print('Foo bar')
if __name__ == "__main__":
foo = Foo()
foo.bar()

Pass arguments to python functions using subprocess

If I have a function in a file like this:
def foo():
print 'foo'
foo()
I can call this file from another one:
import subprocess
subprocess.call(['python', 'function.py'])
But can if the function needs arguments:
def foo(foo_var):
print foo_var
Can I still call the function using subprocess?
Can I still call the function using subprocess?
Yeah.
First you will need to pass the arguments to the function:
from sys import argv
def foo(args):
print args
>> ['arg1', 'arg2'] # (based on the example below)
foo(argv[1:])
Then in your calling code:
import subprocess
subprocess.call(['python', 'function.py', 'arg1', 'arg2'])
Instead of using subprocess, just modify function.py to have it work nicely with imports:
def foo():
print 'foo'
if __name__ == '__main__':
foo()
Then you can just import foo from the function module:
from function import foo
if __name__ == '__main__':
foo(1)

Python: Indent print output from class

How can I indent the print output on the command line from a class that is called? I can't edit the class file to add tabs to each print().
So I would call the imported class in mypythonthing.py:
print('Calling class')
MyClass()
All the print output would then be indented, or have something prepended to it.
e.g.
$ python mypythonthing.py
$ Running your python script...
$ Calling class
$ > The print output from MyClass is indented
$ > Exiting MyClass
$
Patch the built-in print function to prefix each line with your indentation.
import builtins
def print(*args, **kwargs):
builtins.print(" > ", *args, **kwargs)
If you can put the code that should be indented inside (one or more) functions, then you can use a decorator to wrap these functions.
Then any invocation of print inside these function will be indented.
Also, you will only need to declare this function in your main script, and not anywhere else.
Example -
import builtins
import another # for demo purposes only
# This will override the default `print` function.
# Invoking it as a decorator will automatically perform
# initialisation and cleanup. There is also never a need
# to modify this.
def indent(f):
def closure():
old = builtins.print
builtins.print = lambda x, *args, **kwargs: old("\t>", x, *args, **kwargs)
f()
builtins.print = old
return closure
some_number = "100"
# Example function, note decorator usage.
# This function may **not** take any parameters!
# It may however, use any variables declared before it.
#indent
def indentedStuffGoesHere():
print("Inside `indentedStuffGoesHere`")
print(some_number)
another.Foo().bar()
another.stuff()
print("entering special block")
indentedStuffGoesHere()
print("done")
another.py
def stuff():
print("TESTING stuff")
class Foo:
def bar(self):
print("HELLO FROM FOO")
Output:
entering special block
> Inside `indentedStuffGoesHere`
> 100
> HELLO FROM FOO
> TESTING stuff
done
i think what you might be looking for is textwrap:
textwrap docs
so as an example:
wrapper = textwrap.TextWrapper(width=preferredWidth, subsequent_indent='\t')
message = "asdf" * 50
print wrapper.fill(message)

How to refer to a method name from with a method in Python?

Say I have the following class defined with the method foo:
class MyClass:
def foo(self):
print "My name is %s" % __name__
Now when I call foo() I expect/want to see this printed out
My name is foo
However I get
My name is __main__
And if I was to put the class definition into a module called FooBar I would get
My name is FooBar
However if I do
m = MyClass()
print m.foo.__name__
I get exactly what I want which is
My name is foo
Can someone please help explain why __name__ refers to the module and not the method name ?
Is there an easy way to get the method name?
Many thanks
This does what you're after:
from inspect import currentframe, getframeinfo
class MyClass:
def foo(self):
print "My name is %s" % getframeinfo(currentframe())[2]
Names always refer to local variables or (if one doesn't exist) then global variables. There is a a global __name__ that has the module's name.
class MyClass:
def foo(self):
print "My name is %s" % MyClass.foo.__name__
Of course, that's redundant and almost entirely pointless. Just type out the method name:
class MyClass:
def foo(self):
print "My name is %s" % "foo"
print "My name is foo"
__name__ refers to the module because that's what it's supposed to do. The only way to get at the currently running function would be to introspect the stack.
The other answers explain it quite well so I contribute with a more concrete example.
name.py
def foo():
print "name in foo",__name__
foo()
print "foo's name",foo.__name__
print "name at top",__name__
Output
name in foo __main__
foo's name foo
name at top __main__
name2.py
import name
Output
name in foo name
foo's name foo
name at top name
Notice how the __name__ refers to built-in property of the module? Which is __main__ if the module is run directly, or the name of the module if its imported.
You should have run across the if __name__=="__main__": snippet.
You can find the relevant docs here, go check them out. Good luck! :)
Use introspection with the inspect module.
import inspect
class MyClass:
def foo(self):
print "My name is %s" % inspect.stack()[0][3]
Have a look at the the inspect module.
Try:
>>> import inspect
>>> def foo():
... print inspect.getframeinfo(inspect.currentframe())[2]
...
>>> foo()
foo
or:
>>> def foo2():
... print inspect.stack()[0][3]
...
>>> foo2()
foo2
This will do it:
(You need to refer to self.__class__._name__.)
class MyClass:
def foo(self):
print "My name is %s" % self.__class__.__name__

Categories

Resources