Câu hỏi Gọi một chức năng của một mô-đun bằng cách sử dụng tên của nó (một chuỗi)


Cách tốt nhất để đi về việc gọi một hàm được đưa ra một chuỗi với tên của hàm trong một chương trình Python. Ví dụ: giả sử tôi có mô-đun foovà tôi có một chuỗi có nội dung "bar". Cách tốt nhất để gọi về foo.bar()?

Tôi cần lấy giá trị trả về của hàm, đó là lý do tại sao tôi không sử dụng eval. Tôi đã tìm ra cách để làm điều đó bằng cách sử dụng eval để xác định một hàm temp trả về kết quả của hàm gọi đó, nhưng tôi hy vọng rằng có một cách thanh lịch hơn để thực hiện điều này.


1189
2017-08-06 03:36


gốc




Các câu trả lời:


Mô-đun giả định foo với phương pháp bar:

import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()

Theo như vậy, các dòng 2 và 3 có thể được nén thành:

result = getattr(foo, 'bar')()

nếu điều đó có ý nghĩa hơn đối với trường hợp sử dụng của bạn. Bạn có thể dùng getattr trong thời trang này trên các phương thức ràng buộc lớp thể hiện, các phương thức mức mô đun, các phương thức lớp ... danh sách tiếp tục.


1443
2017-08-06 03:57



hasattr hoặc getattr có thể được sử dụng để xác định nếu một hàm được định nghĩa. Tôi đã có một ánh xạ cơ sở dữ liệu (eventType và xử lý functionName) và tôi muốn chắc chắn rằng tôi không bao giờ "quên" để xác định một trình xử lý sự kiện trong python của tôi - Shaun
Điều này hoạt động nếu bạn đã biết tên module. Tuy nhiên, nếu bạn muốn người dùng cung cấp tên mô-đun dưới dạng chuỗi, điều này sẽ không hoạt động. - Blairg23
Nếu bạn cần tránh một NoneType không phải là ngoại lệ có thể gọi, bạn cũng có thể sử dụng hình thức ba đối số getattr: getattr (foo, 'bar', lambda: None). Tôi xin lỗi vì định dạng; ứng dụng android stackexchange rõ ràng là khủng khiếp. - geekofalltrades
Xem thêm câu trả lời được cung cấp bởi @sastanin nếu bạn chỉ quan tâm đến ví dụ về các chức năng của mô-đun cục bộ / hiện tại của bạn. - NuSkooler
Lưu ý: +1 thú vị, điều này làm tôi hiểu thêm một lần nữa rằng trong Python mọi thứ đều là một đối tượng. Do đó, nó cũng hoạt động với các biến, bạn có thể truy cập các biến của mô-đun như bất kỳ biến nào của đối tượng khác. - tuned


locals()["myfunction"]()

hoặc là

globals()["myfunction"]()

người dân địa phương trả về một từ điển với bảng biểu tượng cục bộ hiện tại. globals trả về một từ điển với bảng biểu tượng toàn cầu.


401
2018-05-07 12:45



Phương pháp này với globals / local là tốt nếu phương thức bạn cần gọi được định nghĩa trong cùng một mô-đun mà bạn đang gọi. - Joelmob
@ Joelmob là có cách nào khác để có được một đối tượng bằng chuỗi ra khỏi không gian tên gốc? - Nick T
@ NickT Tôi chỉ nhận thức được những phương pháp này, tôi không nghĩ rằng có bất kỳ những người khác mà điền vào chức năng tương tự như thế này, ít nhất tôi không thể nghĩ ra một lý do tại sao nên có nhiều hơn nữa. - Joelmob
Tôi đã có một lý do cho bạn (thực sự những gì đã dẫn tôi ở đây): Module A có một chức năng F mà cần phải gọi một chức năng theo tên. Mô-đun B nhập khẩu Mô-đun A và gọi hàm F với yêu cầu gọi hàm G, được định nghĩa trong Mô-đun B. Cuộc gọi này thất bại vì, rõ ràng, hàm F chỉ chạy với các hình cầu được xác định trong Mô-đun F - vì vậy tổng số () ['G'] = Không. - David Stein


Giải pháp của Patrick có lẽ là sạch nhất. Nếu bạn cũng cần phải tự động chọn mô-đun, bạn có thể nhập mô-đun như:

module = __import__('foo')
func = getattr(module, 'bar')
func()

243
2017-08-07 11:35



Tôi không hiểu rằng bình luận cuối cùng. __import__ có quyền riêng của nó và câu tiếp theo trong các tài liệu được đề cập nói: "Sử dụng trực tiếp __import __ () là rất hiếm, ngoại trừ trong trường hợp bạn muốn nhập một mô-đun có tên chỉ được biết khi chạy". Vì vậy: +1 cho câu trả lời nhất định. - hoffmaje
Sử dụng importlib.import_module. Các tài liệu chính thức nói về __import__: "Đây là một hàm nâng cao không cần thiết trong lập trình Python hàng ngày, không giống như importlib.import_module ()." docs.python.org/2/library/functions.html#__import__ - glarrain
@glarrain Miễn là bạn ổn với chỉ hỗ trợ 2.7 trở lên. - Xiong Chiamiov
@Xiong Chaimiov, importlib.import_module được hỗ trợ trong 3.6. Xem docs.python.org/3.6/library/… - cowlinator
@cowlinator Có, 3,6 là một phần của "2,7 trở lên", cả hai trong ngữ nghĩa phiên bản nghiêm ngặt và trong ngày phát hành (nó đến khoảng sáu năm sau đó). Nó cũng không tồn tại trong ba năm sau bình luận của tôi. ;) Trong nhánh 3.x, mô-đun đã có từ khoảng 3.1. 2,7 và 3,1 bây giờ là khá cổ đại; bạn vẫn sẽ tìm thấy các máy chủ treo xung quanh mà chỉ hỗ trợ 2,6, nhưng nó có thể có giá trị có importlib là lời khuyên tiêu chuẩn hiện nay. - Xiong Chiamiov


Chỉ là một đóng góp đơn giản. Nếu lớp mà chúng ta cần để dụ là trong cùng một tập tin, chúng ta có thể sử dụng một cái gì đó như thế này:

# Get class from globals and create an instance
m = globals()['our_class']()

# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')

# Call it
func()

Ví dụ:

class A:
    def __init__(self):
        pass

    def sampleFunc(self, arg):
        print('you called sampleFunc({})'.format(arg))

m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')

# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')

Và, nếu không phải là một lớp học:

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')

81
2017-08-19 09:40





Cho một chuỗi, với một đường dẫn python hoàn chỉnh đến một hàm, đây là cách tôi đã đi về việc nhận được kết quả của hàm đã nói:

import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()

65
2017-10-16 00:24



Điều này đã giúp tôi. Đó là một phiên bản nhẹ của __import__ chức năng. - Pankaj Bhambhani
Người bạn đời giải quyết gọn gàng! - Nebulosar


Câu trả lời (tôi hy vọng) không ai từng muốn

Đánh giá hành vi

getattr(locals().get("foo") or globals().get("foo"), "bar")()

Tại sao không thêm tự động nhập

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

Trong trường hợp chúng tôi có thêm từ điển, chúng tôi muốn kiểm tra

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

Chúng ta cần đi sâu hơn

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()

31
2018-04-09 10:17





Câu trả lời tốt nhất theo Hỏi đáp về lập trình Python sẽ là:

functions = {'myfoo': foo.bar}

mystring = 'myfoo'
if mystring in functions:
    functions[mystring]()

Ưu điểm chính của kỹ thuật này là các chuỗi không cần phải khớp với tên của các hàm. Đây cũng là kỹ thuật chính được sử dụng để mô phỏng cấu trúc trường hợp


28
2017-10-24 13:20





Đối với những gì nó có giá trị, nếu bạn cần phải vượt qua tên (hoặc lớp) của hàm và tên ứng dụng dưới dạng một chuỗi, thì bạn có thể thực hiện điều này:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)

18
2018-02-14 05:55



Chỉ một chút chung chung hơn là handler = getattr(sys.modules[__name__], myFnName) - lony


Thử cái này. Trong khi điều này vẫn còn sử dụng eval, nó chỉ sử dụng nó để triệu tập hàm từ ngữ cảnh hiện tại. Sau đó, bạn có chức năng thực sự để sử dụng như bạn muốn.

Lợi ích chính của tôi từ việc này là bạn sẽ nhận được bất kỳ lỗi nào liên quan đến eval tại thời điểm triệu hồi hàm. Sau đó, bạn sẽ nhận được chỉ có các lỗi liên quan đến chức năng khi bạn gọi.

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)

15
2017-12-07 18:29



Điều này sẽ rất nguy hiểm. chuỗi có thể có bất cứ điều gì và eval sẽ kết thúc eval-ling nó mà không cần bất kỳ xem xét. - iankit
Chắc chắn, bạn phải chú ý đến bối cảnh bạn đang sử dụng nó, liệu điều này có phù hợp hay không, với những rủi ro đó. - tvt173


không có gì được gợi ý đã giúp tôi. Tôi đã khám phá ra điều này mặc dù.

<object>.__getattribute__(<string name>)(<params>)

Tôi đang sử dụng python 2,66

Hi vọng điêu nay co ich


14
2017-12-28 16:56



Trong khía cạnh nào thì điều này tốt hơn so với getattr ()? - V13
Chính xác những gì tôi muốn. Làm việc như một say mê! Hoàn hảo!! self.__getattribute__('title') bằng self.title - ioaniatr