Chạy chức năng từ dòng lệnh


363

Tôi có mã này:

def hello():
    return 'Hi :)'

Làm thế nào tôi có thể chạy nó trực tiếp từ dòng lệnh?


21
Có lẽ bạn có ý print "Hi :)"thay vì return 'Hi :)'.
Tamás

Câu trả lời:


567

Với đối số -c (lệnh) (giả sử tệp của bạn được đặt tên foo.py):

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

Ngoài ra, nếu bạn không quan tâm đến ô nhiễm không gian tên:

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

Và nền tảng giữa:

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

32
Tôi lưu ý rằng trên windows shell, bạn cần một trích dẫn kép thay vì đơn. $python -c "import foo;foo.hello()"
Arindam Roychowdhury

6
Điều gì xảy ra nếu tệp không nằm trong thư mục cục bộ hoặc trên PYTHONPATH?
Konstantin

2
Câu thứ hai là một câu trả lời tổng quát hơn. Tôi có một tập lệnh được xác định nhiều chức năng của khách hàng và chỉ gọi một chức năng tùy theo nhu cầu của tôi
xappppp

1
Vì một số lý do, điều này không hiệu quả với tôi, trong khi thay thế print foo.hello()bằng print(foo.hello()). Tôi không có kiến ​​thức về con trăn để giải thích tại sao lại như vậy, vì vậy nếu người khác có thể giải thích những gì có thể xảy ra, điều đó sẽ được đánh giá rất cao
Jasper

2
@Aakanksha Cảm ơn lời giải thích, và điều đó chắc chắn có ý nghĩa. Có vẻ đúng khi chỉnh sửa câu trả lời để bao gồm dấu ngoặc đơn? Điều đó sẽ làm cho nó tương thích với cả python 2 và 3 nếu tôi không nhầm. (Vào những lúc như thế này, tôi rất muốn có thể đưa ra đề xuất chỉnh sửa.)
Jasper

130

Chỉ cần đặt hello()ở đâu đó bên dưới chức năng và nó sẽ thực thi khi bạn làmpython your_file.py

Đối với một giải pháp gọn gàng hơn, bạn có thể sử dụng điều này:

if __name__ == '__main__':
    hello()

Bằng cách đó, chức năng sẽ chỉ được thực thi nếu bạn chạy tệp chứ không phải khi bạn nhập tệp.


3
Và nếu hello()có các đối số nên được cung cấp bởi dòng lệnh thì sao?
Ẩn danh

2
Trong trường hợp đó bạn có thể gửi sys.argvđến phương thức. Hoặc truy cập nó từ phương thức hello
Wolph

3
Một điểm khác biệt giữa câu trả lời này và giải pháp nhập foo là nhập foo cho phép gọi một hàm tùy ý trong foo mà không cần sửa đổi foo.
plafratt

Điều đó đúng, nhưng tôi sẽ không đề xuất giải pháp đó ngoài mục đích thử nghiệm
Wolph

@Wolph hey với cấu trúc này, làm thế nào để tôi thực thi một chức năng riêng biệt (không bao gồm bên trong hello()) và chạy nó từ dòng lệnh?
Souvik Ray

66

python -c 'from myfile import hello; hello()'nơi myfilephải được thay thế bằng tên cơ sở của tập lệnh Python của bạn. (Ví dụ, myfile.pytrở thành myfile).

Tuy nhiên, nếu hello()là điểm nhập chính "vĩnh viễn" trong tập lệnh Python của bạn, thì cách thông thường để làm điều này như sau:

def hello():
    print "Hi :)"

if __name__ == "__main__":
    hello()

Điều này cho phép bạn thực thi tập lệnh đơn giản bằng cách chạy python myfile.pyhoặc python -m myfile.

Một số giải thích ở đây: __name__là một biến Python đặc biệt chứa tên của mô-đun hiện đang được thực thi, ngoại trừ khi mô-đun được bắt đầu từ dòng lệnh, trong trường hợp đó nó sẽ trở thành "__main__".


2
Sự khác biệt giữa python -m foo -c 'foo.bar()'và là python -c 'import foo; foo.bar()'gì? Tôi nhận được hành vi khác nhau trong đó có vẻ như đối số -c bị bỏ qua trong trường hợp đầu tiên.
Abram

29

Tôi đã viết một tập lệnh Python nhỏ có thể gọi được từ một dòng lệnh bash. Nó lấy tên của mô-đun, lớp và phương thức bạn muốn gọi và các tham số bạn muốn truyền. Tôi gọi nó là PyRun và bỏ phần mở rộng .py và làm cho nó có thể thực thi được với chmod + x PyRun để tôi có thể gọi nó nhanh chóng như sau:

./PyRun PyTest.ClassName.Method1 Param1

Lưu cái này trong một tập tin gọi là 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)

Đây là một mô-đun mẫu để hiển thị cách nó hoạt động. Điều này được lưu trong một tệp có tên 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")

Hãy thử chạy các ví dụ sau:

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

Lưu ý ví dụ cuối cùng về việc thoát dấu ngoặc đơn để truyền trong một tuple là tham số duy nhất cho phương thức thứ hai.

Nếu bạn truyền quá ít tham số cho những gì phương thức cần, bạn sẽ gặp lỗi. Nếu bạn vượt qua quá nhiều, nó bỏ qua các tính năng bổ sung. Các mô-đun phải nằm trong thư mục làm việc hiện tại, đặt PyRun có thể ở bất cứ đâu trong đường dẫn của bạn.


2
Thật tuyệt, nhưng nó không thực sự là một câu trả lời cho câu hỏi.
Francis Colas

14
Tôi có ý kiến ​​khác; nó chính xác là câu hỏi Anh ấy hỏi làm thế nào để bạn chạy một chức năng từ một tập tin và đó chính xác là những gì nó làm.
Joseph Gagliardo

Bạn có thể giải thích bit về cmd_folder đang làm gì không?
RyanDay

26

thêm đoạn mã này vào cuối tập lệnh của bạn

def myfunction():
    ...


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

Bây giờ bạn có thể gọi chức năng của bạn bằng cách chạy

python myscript.py myfunction

Điều này hoạt động vì bạn đang chuyển đối số dòng lệnh (một chuỗi tên của hàm) vào locals, một từ điển với bảng ký hiệu cục bộ hiện tại. Các parantheses ở cuối sẽ làm cho hàm được gọi.

cập nhật: nếu bạn muốn hàm chấp nhận một tham số từ dòng lệnh, bạn có thể chuyển vào sys.argv[2]như sau:

def myfunction(mystring):
    print mystring


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

Bằng cách này, chạy python myscript.py myfunction "hello"sẽ xuất ra hello.


Phương thức này có thể chấp nhận một tham số cho hàm không? Chẳng hạn nhưmyfunction(12)
Thiếu tá

@MajorMajor Tôi đã cập nhật câu trả lời để bao gồm cách thực hiện việc này
Noam Hacker

Đây có phải là bất kỳ nguy hiểm làm điều này trong sản xuất trực tiếp? Giống như muốn làm cho nó như là một bài kiểm tra đơn vị.
Ardhi

9

Chúng ta hãy làm điều này dễ dàng hơn một chút với bản thân và chỉ cần sử dụng một mô-đun ...

Thử: pip install compago

Sau đó viết:

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()

Sau đó sử dụng như vậy:

$ python test.py hello
hi there!

$ python test.py goodbye
see ya later.

Lưu ý: Hiện tại có một lỗi trong Python 3, nhưng hoạt động rất tốt với Python 2.

Chỉnh sửa: Một tùy chọn thậm chí còn tốt hơn, theo ý kiến ​​của tôi là mô-đun cháy của Google, điều này giúp dễ dàng vượt qua các đối số chức năng. Nó được cài đặt với pip install fire. Từ GitHub của họ:

Đây là một ví dụ đơn giản.

import fire

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

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

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

Sau đó, từ dòng lệnh, bạn có thể chạy:

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

+1. Fire thậm chí còn có cách gọi hàm mà không thay đổi tập lệnh : python -m fire file_name method_name. Nó cũng có một argparser tích hợp.
dùng3265569

6

Thật thú vị, nếu mục tiêu là in ra bảng điều khiển dòng lệnh hoặc thực hiện một số thao tác python phút khác, bạn có thể chuyển đầu vào vào trình thông dịch python như vậy:

echo print("hi:)") | python

cũng như các tập tin đường ống ..

python < foo.py

* Lưu ý rằng tiện ích mở rộng không phải là .py để thứ hai hoạt động. ** Cũng lưu ý rằng đối với bash, bạn có thể cần phải thoát các ký tự

echo print\(\"hi:\)\"\) | python

Xem xét ví dụ về foo.py với hello (), đây là cách người ta có thể sử dụng nó với ý tưởng trên. echo import foo;foo.hello() | python
Arindam Roychowdhury

Có cách nào để vượt qua trong các đối số dòng lệnh với phương thức này không?
sparkonhdfs

1
FWIW, phần sau đây sạch hơn một chút cho ví dụ thứ ba:echo 'print("hi:)")' | python
user3166580

5

Nếu bạn cài đặt gói runp với pip install runpvấn đề là chạy:

runp myfile.py hello

Bạn có thể tìm thấy kho lưu trữ tại: https://github.com/vascop/runp


1
Dự án không tương thích với Python 3.
dim8

4

Tôi có một yêu cầu sử dụng các tiện ích python khác nhau (phạm vi, chuỗi, v.v.) trên dòng lệnh và đã viết công cụ pyfunc cụ thể cho điều đó. Bạn có thể sử dụng nó để làm phong phú thêm kinh nghiệm sử dụng dòng lệnh của bạn:

 $ 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

Luôn luôn là một tùy chọn để nhập python trên dòng lệnh với lệnh python

sau đó nhập tệp của bạn để nhập example_file

sau đó chạy lệnh với example_file.hello ()

Điều này tránh chức năng sao chép .pyc kỳ lạ mọc lên mỗi khi bạn chạy python -c, v.v.

Có thể không thuận tiện như một lệnh đơn, nhưng cách khắc phục nhanh để nhắn tin một tệp từ dòng lệnh và cho phép bạn sử dụng python để gọi và thực thi tệp của mình.


1

Một cái gì đó như thế này: 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

Điều này hoạt động trong bash.

$ ip='"hi"' ; fun_name='call_from_terminal' 
$ python -c "import ${fun_name} as cft; cft.test_term_fun(${ip})"
hi

1

Dưới đây là tệp Odd_Even_feft.py có định nghĩa của hàm.

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

Bây giờ để gọi tương tự từ Dấu nhắc lệnh bên dưới là các tùy chọn làm việc cho tôi.

Tùy chọn 1 Đường dẫn đầy đủ của exe \ python.exe -c "nhập Odd_Even_feft; Odd_Even_feft.OE (100)"

Tùy chọn 2 Đường dẫn đầy đủ của exe \ python.exe -c "từ Odd_Even_feft nhập OE; OE (100)"

Cảm ơn.


0

Hàm này không thể chạy từ dòng lệnh vì nó trả về một giá trị sẽ không được xử lý. Bạn có thể loại bỏ trả lại và sử dụng in thay thế


-2

Sử dụng công cụ python-c ( pip cài đặt python-c ) và sau đó chỉ cần viết:

$ python-c foo 'hello()'

hoặc trong trường hợp bạn không có xung đột tên hàm trong tệp python của mình:

$ python-c 'hello()'

-2

Trước tiên, bạn phải gọi hàm như họ đã nói với bạn hoặc founction sẽ không hiển thị gì ở đầu ra, sau đó lưu tệp và sao chép đường dẫn của tệp bằng cách nhấp chuột phải vào thư mục của tệp và nhấp vào "sao chép tệp" sau đó đi đến terminal và viết: - cd "đường dẫn của tệp" - tên python "của tệp chẳng hạn (main.py)" sau đó nó sẽ hiển thị đầu ra của mã của bạn.


-4

Làm cho cuộc sống của bạn dễ dàng hơn, cài đặt Spyder. Mở tệp của bạn sau đó chạy nó (bấm vào mũi tên màu xanh lá cây). Sau đó, hello()phương thức của bạn được xác định và được biết đến với Bảng điều khiển IPython, vì vậy bạn có thể gọi nó từ bảng điều khiển.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.