1

Related to this question Command line arguments in python.

With the SYS module, how can I use a command line argument as a function name and function value, within my code - without importing some other module?

I'd like a solution that uses sys only. Also, please no variable-length params answers. Those are confusing. Assume that just the function name and one function variable are specified at the command line.

import sys

def reversal(aaa): return aaa[::-1]

a = sys.argv[1]
b = sys.argv[2]

print a(b)

At the command line

cpu_location$ python blah.py reversal 'abcdefg'

Traceback (most recent call last):
File "blah.py", line 8, in <module>
print a(b)
TypeError: 'str' object is not callable

I want to know how to make sys.argv[1] be considered a function name, thereby calling the function I have defined.

The other posts I see on this are a mash up of: - dealing with C/C++ and adding some other module - not using sys at all - using the argv items as values for functions, and names of other files, instead of names of functions

1
  • Easiest is using fabric Commented Apr 24, 2015 at 18:00

3 Answers 3

6

Better than the eval solution would be:

a = globals()[sys.argv[1]]
a(b)

globals() returns a dictionary mapping global variables names to those global variables. So globals()['reversal'] evaluates to the reversal function.

It's safer than the eval function. With your approach you could do something like:

python blah.py 'lambda x: x+"hi"' foobar

Which would print foobarhi, which is unexpected because that's not a function name.

Sign up to request clarification or add additional context in comments.

3 Comments

I don't get it. What's wrong with your example? In my case, the first parameter will always be a function I defined in the script itself. That's why I want it to be the function name.
@VISQL: It's just a general guideline to avoid eval and exec whenever possible. It allows people to make the script do just about whatever they want. With this approach you constrain the behavior to exactly what you want, namely, getting a function from a function name.
If I do globals()['funname'] the call is ignored, if I do it the normal funname() way it works. Anything I have forgot to consider?
1

2 hours later, I find the answer. I think it's worth it to post it here in a very simple fashion.

Basiclaly there is no "function" data type in Python, but someone did mention a function eval, which is built-in. Execute python commands passed as strings in command line using python -c (No -c is needed for my own example)

The solution, is to change

a = sys.argv[1]

to

a = eval(sys.argv[1])

This will make the passed in word, reversal, be evaluated. It will evaluate to a function. Then the a(b) call will be a perfect call of a function on a string, like how it's defined. Output will be like:

cpu_location$ python blah.py reversal unquoted
detouqnu

cpu_location$ python blah.py reversal 'withquotes'
setouqhtiw

3 Comments

Please don't use eval(), especially without sanitizing the input. What it does is evaluate the argument as Python code, which is extremely dangerous. Read this for more info.
Thanks. Article is over my head at the moment. I will keep this in mind if I build something more intricate. This project is just for me, to practice. Easier to test my simple functions at command line, than to put all my tests inside the script and get a screen full of text when I run the script - with output for every single function in there.
(Years later). I also used to this sys.argv method to build my own file splitter. It had positional arguments, and could be told to split just one file into x lines per file, or to split all files in a directory in the same way. These args were parsed from the command line using sys.argv. However, none of the items passed at the command line were evaluated as functions.
0

use google module: fire

pip install fire

Here's a simple example:

import fire

class Calculator(object):
  """A simple calculator class."""

  def double(self, number):
    return 2 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

Then, from the command line, you can run:

python calculator.py double 10  # 20
python calculator.py double --number=15  # 30

1 Comment

Nice functionality. In this case, Calculator can be called only though. Back when I was writing this, I intended to have multiple functions of different names (not ant class) in one file that I would like to call from the command line. argv + eval works for this purpose. Any name passed as the first argument would be treated as the function name, and subsequent args as arguments to that function. Also, I tended to prefer small examples to be done via built-ins, rather than modules that aren't defaults.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.