Запустить функцию из командной строки

363

У меня есть этот код:

def hello():
    return 'Hi :)'

Как бы я запустить это прямо из командной строки?

Стивен
источник
21
Возможно, вы имели в виду print "Hi :)"вместо return 'Hi :)'.
Тамас

Ответы:

567

С аргументом -c (команды) (при условии, что ваш файл назван foo.py):

$ python -c 'import foo; print foo.hello()'

В качестве альтернативы, если вас не волнует загрязнение пространства имен:

$ python -c 'from foo import *; print hello()'

И золотая середина

$ python -c 'from foo import hello; print hello()'
Фредерик Хамиди
источник
32
Я заметил, что в оболочке Windows вам нужна двойная кавычка вместо одинарной. $python -c "import foo;foo.hello()"
Ариндам Ройчоудхури
6
Что если файл не находится в локальном каталоге или на PYTHONPATH?
Константин
2
Второй ответ более общий. У меня есть сценарий, определяющий несколько функций клиента, и я вызываю только одну из них в зависимости от моих потребностей
xappppp
1
По некоторым причинам, это не сработало для меня, в то время как замена print foo.hello()на print(foo.hello())сделал. Я не обладаю знаниями Python, чтобы объяснить, почему это так, поэтому, если кто-то еще сможет объяснить, что может происходить, это будет с благодарностью
Джаспер
2
@Aakanksha Спасибо за объяснение, и это определенно имеет смысл. Кажется ли правильным отредактировать ответ, включив в него скобки? Это сделало бы его совместимым с Python 2 и 3, если я не ошибаюсь. (В такие моменты мне бы хотелось иметь возможность внести изменения.)
Джаспер
130

Просто поместите hello()где-нибудь ниже функции, и она будет выполняться, когда вы делаетеpython your_file.py

Для более аккуратного решения вы можете использовать это:

if __name__ == '__main__':
    hello()

Таким образом, функция будет выполняться только при запуске файла, а не при импорте файла.

Wolph
источник
3
А что если hello()принимать аргументы, которые должны быть предоставлены командной строкой?
Аноним
2
В этом случае вы можете отправить sys.argvв метод. Или получить доступ к нему из Привет метод
Вольф
3
Одно из различий между этим ответом и решением import foo состоит в том, что import foo позволяет вызывать произвольную функцию в foo без изменения foo.
плафрат
Это правда, но я бы не рекомендовал это решение вне тестовых целей
Wolph
@ Вольф, эй с этой структурой, как мне выполнить отдельную функцию (не входящую в hello()нее) и запустить ее из командной строки?
Сувик Рэй
66

python -c 'from myfile import hello; hello()'где myfileдолжно быть заменено базовым именем вашего скрипта Python. (Например, myfile.pyстановится myfile).

Однако, если hello()ваша «постоянная» основная точка входа в вашем скрипте Python, то обычный способ сделать это следующим образом:

def hello():
    print "Hi :)"

if __name__ == "__main__":
    hello()

Это позволяет вам выполнить скрипт просто запустив python myfile.pyили python -m myfile.

Некоторое объяснение здесь: __name__это специальная переменная Python, которая содержит имя выполняемого в данный момент модуля, кроме случаев, когда модуль запускается из командной строки, и в этом случае он становится "__main__".

Тамаш
источник
2
В чем разница между python -m foo -c 'foo.bar()'и python -c 'import foo; foo.bar()'? Я получаю другое поведение, когда кажется, что аргумент -c игнорируется в первом случае.
Абрам
29

Я написал небольшой скрипт на Python, который можно вызывать из командной строки bash. Он принимает имя модуля, класса и метода, который вы хотите вызвать, и параметры, которые вы хотите передать. Я назвал его PyRun, отключил расширение .py и сделал его исполняемым с помощью chmod + x PyRun, чтобы я мог просто быстро вызвать его, как показано ниже:

./PyRun PyTest.ClassName.Method1 Param1

Сохраните это в файле с именем 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)

Вот пример модуля, чтобы показать, как это работает. Это сохраняется в файле с именем 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")

Попробуйте запустить эти примеры:

./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\)

Обратите внимание на последний пример экранирования скобок для передачи кортежа в качестве единственного параметра для метода Second.

Если вы передадите слишком мало параметров для того, что нужно методу, вы получите ошибку. Если вы пройдете слишком много, он игнорирует дополнительные. Модуль должен находиться в текущей рабочей папке, поставить PyRun можно в любом месте вашего пути.

Иосиф Гальярдо
источник
2
Это хорошо, но это не совсем ответ на вопрос.
Фрэнсис Колас
14
Позволю себе не согласиться; это точно вопрос. Он спросил, как вы запускаете функцию из файла, и это именно то, что он делает.
Джозеф Гальярдо
Можете ли вы объяснить, что делает бит с cmd_folder?
RyanDay
26

добавьте этот фрагмент в конец вашего скрипта

def myfunction():
    ...


if __name__ == '__main__':
    globals()[sys.argv[1]]()

Теперь вы можете вызвать вашу функцию, запустив

python myscript.py myfunction

Это работает, потому что вы передаете аргумент командной строки (строку имени функции) в localsсловарь с текущей таблицей локальных символов. Парантезы в конце сделают функцию вызываемой.

update: если вы хотите, чтобы функция принимала параметр из командной строки, вы можете передать sys.argv[2]вот так:

def myfunction(mystring):
    print mystring


if __name__ == '__main__':
    globals()[sys.argv[1]](sys.argv[2])

Таким образом, бег python myscript.py myfunction "hello"будет выводить hello.

Ноам Хакер
источник
Возможно ли для этого метода принять параметр для функции? Такие какmyfunction(12)
майор майор
@MajorMajor Я обновил ответ, чтобы включить, как это сделать
Ноам Хакер
это какая-то опасность делать это в живом производстве? Хотелось бы сделать это как юнит-тест.
Ardhi
9

Давайте сделаем это немного проще для себя и просто используем модуль ...

Пытаться: 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()

Затем используйте так:

$ python test.py hello
hi there!

$ python test.py goodbye
see ya later.

Примечание: в данный момент в Python 3 есть ошибка , но она прекрасно работает с Python 2.

Edit: даже лучший вариант, на мой взгляд , является модуль огня от Google , который позволяет легко передавать аргументы функции. Это установлено с 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)

Затем из командной строки вы можете запустить:

python calculator.py double 10  # 20
python calculator.py double --number=15  # 30
Чарльз Клейтон
источник
+1. Огонь даже есть способ вызова функции без изменения сценария: python -m fire file_name method_name. Он также имеет встроенный argparser.
user3265569
6

Интересно, что если цель состояла в том, чтобы напечатать на консоль командной строки или выполнить какую-либо другую мелкую операцию на python, вы можете передать ввод в интерпретатор python следующим образом:

echo print("hi:)") | python

а также файлы труб ..

python < foo.py

* Обратите внимание, что расширение не должно быть .py для второго, чтобы работать. ** Также обратите внимание, что для bash вам может понадобиться экранировать символы

echo print\(\"hi:\)\"\) | python
Тори Дж
источник
Рассматривая пример foo.py с hello (), мы можем использовать его с приведенной выше идеей. echo import foo;foo.hello() | python
Ариндам Ройховдхури
Есть ли способ передать аргументы командной строки с этим методом?
sparkonhdfs
1
FWIW, следующее немного чище для третьего примера:echo 'print("hi:)")' | python
user3166580
5

Если вы устанавливаете пакет runp с pip install runpвопросом запуска:

runp myfile.py hello

Вы можете найти репозиторий по адресу: https://github.com/vascop/runp

vascop
источник
1
Проект не совместим с Python 3.
dim8
4

У меня было требование использовать различные утилиты 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
Саураб Хирани
источник
1

Всегда есть возможность ввести python в командной строке с помощью команды python

затем импортируйте ваш файл, чтобы импортировать example_file

затем выполните команду с example_file.hello ()

Это позволяет избежать странной функции копирования .pyc, которая возникает при каждом запуске python -c и т. Д.

Может быть, не так удобно, как одиночная команда, но это хорошее быстрое решение для текстового файла из командной строки и позволяет использовать python для вызова и выполнения вашего файла.

user2495144
источник
1

Примерно так: call_from_terminal.py

# call_from_terminal.py
# Ex to run from terminal
# ip='"hi"'
# python -c "import call_from_terminal as cft; cft.test_term_fun(${ip})"
# or
# fun_name='call_from_terminal'
# python -c "import ${fun_name} as cft; cft.test_term_fun(${ip})"
def test_term_fun(ip):
    print ip

Это работает в Bash.

$ ip='"hi"' ; fun_name='call_from_terminal' 
$ python -c "import ${fun_name} as cft; cft.test_term_fun(${ip})"
hi
Аль Конрад
источник
1

Ниже приведен файл Odd_Even_function.py, в котором есть определение функции.

def OE(n):
    for a in range(n):
        if a % 2 == 0:
            print(a)
        else:
            print(a, "ODD")

Теперь, чтобы вызвать то же самое из командной строки ниже, варианты работали для меня.

Параметры 1 Полный путь к exe \ python.exe -c "import Odd_Even_function; Odd_Even_function.OE (100)"

Вариант 2 Полный путь к exe \ python.exe -c "из Odd_Even_function import OE; OE (100)"

Спасибо.

Моксит Мехта
источник
0

Эту функцию нельзя запустить из командной строки, так как она возвращает значение, которое останется без изменений. Вы можете удалить возврат и использовать вместо этого печать

Shubham
источник
-2

Используйте инструмент python-c ( pip install python-c ) и затем просто напишите:

$ python-c foo 'hello()'

или если в ваших файлах python нет столкновений с именами функций:

$ python-c 'hello()'
weakmoons
источник
-2

Сначала вы должны вызвать функцию, как они сказали вам, или основание ничего не отобразит в выходных данных, после чего сохраните файл и скопируйте путь к файлу, щелкнув правой кнопкой мыши на папке файла и нажав «Копировать файл», затем зайдите в терминал и напишите: - cd "путь к файлу" - python "имя файла, например (main.py)", после чего он отобразит вывод вашего кода.

ShahadM
источник
-4

Сделайте свою жизнь проще, установите Spyder. Откройте файл и запустите его (нажмите зеленую стрелку). После этого ваш hello()метод определяется и известен консоли IPython, поэтому вы можете вызывать его из консоли.

Ivana
источник