Trong Python, tôi có thể gọi main () của một mô-đun được nhập không?


86

Trong Python, tôi có một mô-đun myModule.py nơi tôi xác định một vài hàm và một hàm main () , có một vài đối số dòng lệnh.

Tôi thường gọi đây là main () từ một tập lệnh bash. Bây giờ, tôi muốn đặt mọi thứ vào một gói nhỏ , vì vậy tôi nghĩ rằng có thể tôi có thể biến tập lệnh bash đơn giản của mình thành một tập lệnh Python và đặt nó trong gói.

Vì vậy, làm cách nào để thực sự gọi hàm main () của myModule.py từ hàm main () của MyFormerBashScript.py? Tôi thậm chí có thể làm điều đó? Làm cách nào để chuyển bất kỳ đối số nào cho nó?


Nếu bạn đã nhập myModule, thì bạn sẽ có thể gọi myModule.main(). Bạn đã thử những gì cho đến nay?
Marius

Tôi lo lắng bởi các đối số đầu vào, mà tôi thường truyền từ một tập lệnh shell.
Ricky Robinson,

Có hợp lý khi gọi nó bằng subprocessmô-đun không?
BenDundee

Tôi đoán nó sẽ dễ dàng hơn, vâng.
Ricky Robinson,

Câu trả lời:


114

Nó chỉ là một chức năng. Nhập nó và gọi nó:

import myModule

myModule.main()

Nếu bạn cần phân tích cú pháp các đối số, bạn có hai tùy chọn:

  • Phân tích cú pháp chúng trong main(), nhưng chuyển vào sys.argvdưới dạng tham số (tất cả mã bên dưới trong cùng một mô-đun myModule):

    def main(args):
        # parse arguments using optparse or argparse or what have you
    
    if __name__ == '__main__':
        import sys
        main(sys.argv[1:])
    

    Bây giờ bạn có thể nhập và gọi myModule.main(['arg1', 'arg2', 'arg3'])từ một mô-đun khác.

  • main() nhận các tham số đã được phân tích cú pháp (một lần nữa tất cả mã trong myModulemô-đun):

    def main(foo, bar, baz='spam'):
        # run with already parsed arguments
    
    if __name__ == '__main__':
        import sys
        # parse sys.argv[1:] using optparse or argparse or what have you
        main(foovalue, barvalue, **dictofoptions)
    

    và nhập và gọi myModule.main(foovalue, barvalue, baz='ham')ở nơi khác và chuyển các đối số trong python nếu cần.

Mẹo ở đây là phát hiện khi nào mô-đun của bạn đang được sử dụng làm tập lệnh; khi bạn chạy tệp python dưới dạng tập lệnh chính ( python filename.py) không có importcâu lệnh nào được sử dụng, vì vậy python sẽ gọi mô-đun đó "__main__". Nhưng nếu cùng một filename.pymã đó được coi là một mô-đun ( import filename), thì thay vào đó, python sẽ sử dụng mã đó làm tên mô-đun. Trong cả hai trường hợp, biến __name__được đặt và thử nghiệm dựa trên đó cho bạn biết mã của bạn đã được chạy như thế nào.


3
Chắc chắn rồi. Nhưng những gì về các đối số đầu vào? Tôi sử dụng argparse, vì vậy khi tôi gọi script từ một thiết bị đầu cuối, tôi thực hiện $ python myModule -a input_a -b input_b --parameterC input_c. Nó sẽ hoạt động như thế nào từ trong mã python? Đó là những gì tôi không thể tìm thấy từ một tìm kiếm đơn giản.
Ricky Robinson

@RickyRobinson: mở rộng để cho thấy rằng bạn có thể có nó theo cả hai cách; chỉ cần truyền các đối số được phân tích cú pháp hoặc sắp được phân tích cú pháp.
Martijn Pieters

1
Cảm ơn. Bạn cũng có thể vui lòng chỉ định đoạn mã nào thuộc về mô-đun hoặc tập lệnh nào? Nó trông cồng kềnh hơn những gì tôi nghĩ lúc đầu.
Ricky Robinson,

@RickyRobinson: Cả hai đoạn trích đều thuộc cùng một mô-đun; Tôi đã nói rõ điều đó.
Martijn Pieters

42

Câu trả lời của Martijen có lý, nhưng nó đã thiếu một điều gì đó quan trọng mà người khác có thể thấy rõ ràng nhưng tôi lại khó hiểu.

Trong phiên bản mà bạn sử dụng argparse, bạn cần có dòng này trong nội dung chính.

args = parser.parse_args(args)

Thông thường, khi bạn đang sử dụng argparse chỉ trong một script bạn chỉ viết

args = parser.parse_args()

và parse_args tìm các đối số từ dòng lệnh. Nhưng trong trường hợp này, hàm main không có quyền truy cập vào các đối số dòng lệnh, vì vậy bạn phải cho argparse biết các đối số là gì.

Đây là một ví dụ

import argparse
import sys

def x(x_center, y_center):
    print "X center:", x_center
    print "Y center:", y_center

def main(args):
    parser = argparse.ArgumentParser(description="Do something.")
    parser.add_argument("-x", "--xcenter", type=float, default= 2, required=False)
    parser.add_argument("-y", "--ycenter", type=float, default= 4, required=False)
    args = parser.parse_args(args)
    x(args.xcenter, args.ycenter)

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

Giả sử bạn đặt tên này là mytest.py Để chạy nó, bạn có thể thực hiện bất kỳ thao tác nào trong số này từ dòng lệnh

python ./mytest.py -x 8
python ./mytest.py -x 8 -y 2
python ./mytest.py 

cái nào trả về tương ứng

X center: 8.0
Y center: 4

hoặc là

X center: 8.0
Y center: 2.0

hoặc là

X center: 2
Y center: 4

Hoặc nếu bạn muốn chạy từ một tập lệnh python khác, bạn có thể làm

import mytest
mytest.main(["-x","7","-y","6"]) 

cái nào trả về

X center: 7.0
Y center: 6.0

4
Đây chính là điều tôi cần - cảm ơn bạn rất nhiều cho các phụ lục hữu ích
HFBrowning

Điều này có thể đã hoạt động với Python 2, nhưng trong Python 3, nó không hoạt động nữa, không thể gọi hàm main () của một mô-đun:AttributeError: module 'sqlacodegen' has no attribute 'main'
NaturalBornCamper

24

Nó phụ thuộc. Nếu mã chính được bảo vệ bởi một ifnhư trong:

if __name__ == '__main__':
    ...main code...

thì không, bạn không thể làm cho Python thực thi điều đó vì bạn không thể ảnh hưởng đến biến tự động __name__.

Nhưng khi tất cả mã nằm trong một hàm, thì có thể. Thử

import myModule

myModule.main()

Điều này hoạt động ngay cả khi mô-đun tự bảo vệ bằng một __all__.

from myModule import *có thể không mainhiển thị với bạn, vì vậy bạn thực sự cần nhập chính mô-đun đó.


Ồ được rồi, cảm ơn vì đã làm rõ. Tôi đặt mọi thứ trong một hàm main (), vì vậy nó sẽ ổn. Tôi lo lắng hơn về cách truyền các đối số đầu vào cho chính "thứ hai" này. Bất kỳ cách dễ dàng để làm như vậy?
Ricky Robinson,

Chắc chắn rồi:import sys; module.main(sys.argv);
Aaron Digulla,

Đây là một lời giải thích thay thế tuyệt vời về việc truy cập __main__đó đã giúp tôi, cảm ơn @AaronDigulla
Charlie G

Đây là một thủ thuật để gọi một chính từ chức năng khác: stackoverflow.com/a/20158605/3244382
PatriceG

3

Tôi cũng có nhu cầu sử dụng argparsenhư vậy. Điều là parse_argshàm của một argparse.ArgumentParsercá thể đối tượng mặc định lấy các đối số của nó từ sys.args. Công việc xung quanh, theo dòng Martijn, bao gồm việc làm cho điều đó rõ ràng, vì vậy bạn có thể thay đổi các đối số mà bạn chuyển sang parse_argsnhư mong muốn.

def main(args):
    # some stuff
    parser = argparse.ArgumentParser()
    # some other stuff
    parsed_args = parser.parse_args(args)
    # more stuff with the args

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

Điểm mấu chốt là chuyển args để parse_argshoạt động. Sau này, để sử dụng main, bạn cứ làm như Martijn nói.


3

Câu trả lời tôi đang tìm kiếm đã được trả lời ở đây: Làm thế nào để sử dụng python argparse với args khác với sys.argv?

Nếu main.pyparse_args()được viết theo cách này, thì việc phân tích cú pháp có thể được thực hiện tốt

# main.py
import argparse
def parse_args():
    parser = argparse.ArgumentParser(description="")
    parser.add_argument('--input', default='my_input.txt')
    return parser

def main(args):
    print(args.input)

if __name__ == "__main__":
    parser = parse_args()
    args = parser.parse_args()
    main(args)

Sau đó, bạn có thể gọi main()và phân tích cú pháp các đối số với parser.parse_args(['--input', 'foobar.txt'])nó trong một tập lệnh python khác:

# temp.py
from main import main, parse_args
parser = parse_args()
args = parser.parse_args([]) # note the square bracket
# to overwrite default, use parser.parse_args(['--input', 'foobar.txt'])
print(args) # Namespace(input='my_input.txt')
main(args)

0

Giả sử bạn cũng đang cố gắng chuyển các đối số dòng lệnh.

import sys
import myModule


def main():
    # this will just pass all of the system arguments as is
    myModule.main(*sys.argv)

    # all the argv but the script name
    myModule.main(*sys.argv[1:])

Cảm ơn. Tôi thực sự đang sử dụng argparsethay vì sys.argv. Nó sẽ thay đổi như thế nào trong trường hợp này? Ngoài ra, từ tập lệnh bên ngoài, tôi chỉ muốn chuyển một vài đối số đầu vào mà người dùng nhập vào, trong khi các đối số đầu vào khác cho tập lệnh bên trong (myModule.py) được tôi mã hóa cứng.
Ricky Robinson,

Nếu không nhìn thấy mã, thật khó để trả lời chi tiết cụ thể. Nói chung, bạn sẽ chỉ chuyển bất kỳ đối số nào. Giải *nén một mảng f(a) => f([1,2,3])so với f(*a) => f(1,2,3) Bạn có thể dễ dàng làm myModule.main(sys.argv[1], "other value", 39)hoặc bất cứ điều gì.
agoebel
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.