Python:从命令行运行函数

Ste*_*ven 323 python command-line function

我的文件中有以下代码:

def hello():
    return 'Hi :)'
Run Code Online (Sandbox Code Playgroud)

我如何从命令行运行它?

Fré*_*idi 504

使用-c (命令)参数(假设您的文件已命名foo.py):

$ python -c 'import foo; print foo.hello()'
Run Code Online (Sandbox Code Playgroud)

或者,如果您不关心命名空间污染:

$ python -c 'from foo import *; print hello()'
Run Code Online (Sandbox Code Playgroud)

中间地带:

$ python -c 'from foo import hello; print hello()'
Run Code Online (Sandbox Code Playgroud)

  • 我注意到在windows shell上,你需要一个双引号而不是单引号.`$ python -c"import foo; foo.hello()"` (24认同)
  • 如果文件不在本地目录或PYTHONPATH中怎么办? (5认同)
  • @Jasper,你必须使用 python 3,它需要 print 函数将其参数放在括号中 (5认同)
  • 这是荒唐的。该答案有超过 700 个赞成票,但无法在任何当前支持的 python 版本上运行。请接受微小的修改,这实际上修复了损坏的代码。 (5认同)
  • 由于某种原因,这对我不起作用,而用“print(foo.hello())”替换“print foo.hello()”则有效。我没有 python 知识来解释为什么会这样,所以如果其他人可以解释发生了什么,那将不胜感激 (3认同)
  • @Aakanksha 感谢您的解释,这绝对有道理。编辑答案以包含括号似乎正确吗?如果我没记错的话,这将使它与 python 2 和 3 兼容。(在这样的时刻,我希望能够提出编辑建议。) (3认同)
  • 虽然这个答案是十年前写的,但它是今天谷歌的热门结果。我相信这就是这个网站的目的:一个寻找相关答案的地方,而不是不断发展的语言的证明。常见问题解答实际上提到保持帖子最新是进行编辑的重要原因。我想说,在这个答案中添加有关 python 版本的部分将是体现语言更改的更好方法,但我认为将代码更改为跨版本兼容是一个更优雅的解决方案。编辑历史将永远作为过去的证明。 (3认同)
  • @AakankshaChoudhary 我想如果这是这里评论的所有其他人的共同意见,我不会碰任何东西。不过我确实不同意。如果这是一些奇怪的边缘情况,我会同意评论就足够了。不过,就目前情况而言,提出这个问题的每个用户(没有使用 Python 的 EOL 版本)都会收到一个非功能性的答案(并且必须深入挖掘并单击“显示更多评论”才能找到如何修复它) )。我觉得如果不在帖子正文中添加它,也会让用户感到困惑...... (3认同)
  • 我只是说,这在 Python 3(或 2 年前还没有日落的任何其他 Python 版本)中不起作用。 (3认同)
  • 第二个是更笼统的答案。我有一个脚本定义了多个客户功能,仅根据需要调用一个 (2认同)

Wol*_*lph 121

只需放在hello()函数下面的某个位置,它就会在你执行时执行python your_file.py

对于更简洁的解决方案,您可以使用:

if __name__ == '__main__':
    hello()
Run Code Online (Sandbox Code Playgroud)

这样,只有在运行文件时才会执行该功能,而不是在导入文件时执行.

  • 如果`hello()`接受应该由命令行提供的参数怎么办? (3认同)
  • 此答案与import foo解决方案之间的区别是import foo允许在foo中调用任意函数而无需修改foo。 (3认同)
  • 在这种情况下,您可以将sys.argv发送给该方法。或通过hello方法访问它 (2认同)

Tam*_*más 56

python -c 'from myfile import hello; hello()'这里myfile必须使用Python脚本的基本名称来代替.(例如,myfile.py变成myfile).

但是,如果hello()您的Python脚本是"永久"主要入口点,那么通常的方法如下:

def hello():
    print "Hi :)"

if __name__ == "__main__":
    hello()
Run Code Online (Sandbox Code Playgroud)

这允许您只需运行python myfile.py或执行脚本python -m myfile.

这里有一些解释:__name__是一个特殊的Python变量,它保存当前正在执行的模块的名称,除非从命令行启动模块,在这种情况下它变为"__main__".

  • python -m foo -c'foo.bar()'和python -c'import foo有什么区别?foo.bar()'`?在第一种情况下,似乎忽略了-c参数,我得到了不同的行为。 (2认同)

D. *_*iya 35

我们可以写这样的东西。我已经与 python-3.7.x 一起使用

import sys

def print_fn():
    print("Hi")

def sum_fn(a, b):
    print(a + b)

if __name__ == "__main__":
    args = sys.argv
    # args[0] = current file
    # args[1] = function name
    # args[2:] = function args : (*unpacked)
    globals()[args[1]](*args[2:])

Run Code Online (Sandbox Code Playgroud)
python demo.py print_fn
python demo.py sum_fn 5 8
Run Code Online (Sandbox Code Playgroud)


Jos*_*rdo 27

我写了一个快速的小Python脚本,可以从bash命令行调用.它采用您要调用的模块,类和方法的名称以及要传递的参数.我称之为PyRun并且不使用.py扩展名并使用chmod + x PyRun使其可执行,以便我可以快速调用它,如下所示:

./PyRun PyTest.ClassName.Method1 Param1
Run Code Online (Sandbox Code Playgroud)

将其保存在名为PyRun的文件中

#!/usr/bin/env python
#make executable in bash chmod +x PyRun

import sys
import inspect
import importlib
import os

if __name__ == "__main__":
    cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
    if cmd_folder not in sys.path:
        sys.path.insert(0, cmd_folder)

    # get the second argument from the command line      
    methodname = sys.argv[1]

    # split this into module, class and function name
    modulename, classname, funcname = methodname.split(".")

    # get pointers to the objects based on the string names
    themodule = importlib.import_module(modulename)
    theclass = getattr(themodule, classname)
    thefunc = getattr(theclass, funcname)

    # pass all the parameters from the third until the end of 
    # what the function needs & ignore the rest
    args = inspect.getargspec(thefunc)
    z = len(args[0]) + 2
    params=sys.argv[2:z]
    thefunc(*params)
Run Code Online (Sandbox Code Playgroud)

这是一个示例模块,展示它是如何工作的.这保存在名为PyTest.py的文件中:

class SomeClass:
 @staticmethod
 def First():
     print "First"

 @staticmethod
 def Second(x):
    print(x)
    # for x1 in x:
    #     print x1

 @staticmethod
 def Third(x, y):
     print x
     print y

class OtherClass:
    @staticmethod
    def Uno():
        print("Uno")
Run Code Online (Sandbox Code Playgroud)

尝试运行这些示例:

./PyRun PyTest.SomeClass.First
./PyRun PyTest.SomeClass.Second Hello
./PyRun PyTest.SomeClass.Third Hello World
./PyRun PyTest.OtherClass.Uno
./PyRun PyTest.SomeClass.Second "Hello"
./PyRun PyTest.SomeClass.Second \(Hello, World\)
Run Code Online (Sandbox Code Playgroud)

注意最后一个转义括号的例子,它将元组作为第二个方法的唯一参数传入.

如果为方法所需的参数传递的参数太少,则会出现错误.如果你传球太多,它会忽略额外的东西.该模块必须在当前工作文件夹中,放入PyRun可以在您的路径中的任何位置.

  • 我不敢苟同; 这正是问题所在.他问你如何从文件中运行一个函数,这正是它的作用. (14认同)
  • 这很好,但这不是问题的答案. (2认同)

Noa*_*ker 18

将此代码段添加到脚本底部

def myfunction():
    ...


if __name__ == '__main__':
    globals()[sys.argv[1]]()
Run Code Online (Sandbox Code Playgroud)

您现在可以通过运行来调用您的函数

python myscript.py myfunction
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为您将命令行参数(函数名称的字符串)传递给locals具有当前本地符号表的字典.最后的parantheses将使函数被调用

  • @Ardhi:我不会在产品中这样做,因为它允许调用文件中的任何全局函数,这使得它变得脆弱。使用 [pytest 进行简单的测试设置](https://docs.pytest.org/en/6.2.x/getting-started.html#create-your-first-test)。 (2认同)

Sau*_*ani 7

我需要在命令行上使用各种 python 实用程序(范围、字符串等),并专门为此编写了工具pyfunc 。您可以使用它来丰富您的命令行使用体验:

 $ pyfunc -m range -a 1 7 2
 1
 3
 5

 $ pyfunc -m string.upper -a test
 TEST

 $ pyfunc -m string.replace -a 'analyze what' 'what' 'this'
 analyze this
Run Code Online (Sandbox Code Playgroud)


Cha*_*ton 6

让我们自己更容易一点,只需使用一个模块......

尝试: pip install compago

然后写:

import compago
app = compago.Application()

@app.command
def hello():
    print "hi there!"

@app.command
def goodbye():
    print "see ya later."

if __name__ == "__main__":
    app.run()
Run Code Online (Sandbox Code Playgroud)

然后使用如下:

$ python test.py hello
hi there!

$ python test.py goodbye
see ya later.
Run Code Online (Sandbox Code Playgroud)

注意:目前Python 3中存在一个错误,但在Python 2中效果很好.

编辑:一个更好的选择,在我看来是谷歌的模块,这使得传递函数参数变得容易.它是安装的pip install fire.从他们的GitHub:

这是一个简单的例子.

import fire

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

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

if __name__ == '__main__':
  fire.Fire(Calculator)
Run Code Online (Sandbox Code Playgroud)

然后,从命令行,您可以运行:

python calculator.py double 10  # 20
python calculator.py double --number=15  # 30
Run Code Online (Sandbox Code Playgroud)

  • +1。Fire 甚至有一种无需更改脚本即可调用函数的方法:“python -m fire file_name method_name”。它还有一个内置的 argparser。 (2认同)

Eri*_*nil 6

该脚本与此处的其他答案类似,但它还列出了可用的函数,以及参数和文档字符串:

"""Small script to allow functions to be called from the command line.
Run this script without argument to list the available functions:

    $ python many_functions.py
    Available functions in many_functions.py:

    python many_functions.py a  : Do some stuff

    python many_functions.py b  : Do another stuff

    python many_functions.py c x y : Calculate x + y

    python many_functions.py d  : ?

Run this script with arguments to try to call the corresponding function:

    $ python many_functions.py a
    Function a

    $ python many_functions.py c 3 5
    3 + 5 = 8

    $ python many_functions.py z
    Function z not found
"""

import sys
import inspect

#######################################################################
#                         Your functions here                         #
#######################################################################

def a():
    """Do some stuff"""
    print("Function a")

def b():
    """Do another stuff"""
    a()
    print("Function b")

def c(x, y):
    """Calculate x + y"""
    print(f"{x} + {y} = {int(x) + int(y)}")

def d():
    # No doc
    print("Function d")

#######################################################################
#         Some logic to find and display available functions          #
#######################################################################

def _get_local_functions():
    local_functions = {}
    for name, obj in inspect.getmembers(sys.modules[__name__]):
        if inspect.isfunction(obj) and not name.startswith('_') and obj.__module__ == __name__:
            local_functions[name] = obj
    return local_functions

def _list_functions(script_name):
    print(f"Available functions in {script_name}:")
    for name, f in _get_local_functions().items():
        print()
        arguments = inspect.signature(f).parameters
        print(f"python {script_name} {name} {' '.join(arguments)} : {f.__doc__ or '?'}")


if __name__ == '__main__':
    script_name, *args = sys.argv
    if args:
        functions = _get_local_functions()
        function_name = args.pop(0)
        if function_name in functions:
            function = functions[function_name]
            function(*args)
        else:
            print(f"Function {function_name} not found")
            _list_functions(script_name)
    else:
        _list_functions(script_name)
Run Code Online (Sandbox Code Playgroud)

不带参数运行此脚本以列出可用函数:

$ python many_functions.py
Available functions in many_functions.py:

python many_functions.py a  : Do some stuff

python many_functions.py b  : Do another stuff

python many_functions.py c x y : Calculate x + y

python many_functions.py d  : ?
Run Code Online (Sandbox Code Playgroud)

使用参数运行此脚本以尝试调用相应的函数:

$ python many_functions.py a
Function a

$ python many_functions.py c 3 5
3 + 5 = 8

$ python many_functions.py z
Function z not found
Run Code Online (Sandbox Code Playgroud)


vas*_*cop 5

如果你pip install runp运行runp包安装它:

runp myfile.py hello

您可以在以下网址找到存储库:https://github.com/vascop/runp


Tor*_*e J 5

有趣的是,如果目标是打印到命令行控制台或执行其他一些微小的python操作,您可以将输入管道输入python解释器,如下所示:

echo print("hi:)") | python
Run Code Online (Sandbox Code Playgroud)

以及管道文件..

python < foo.py
Run Code Online (Sandbox Code Playgroud)

*请注意,扩展名不一定是.py,第二个工作.**另请注意,对于bash,您可能需要转义字符

echo print\(\"hi:\)\"\) | python
Run Code Online (Sandbox Code Playgroud)