Con trỏ hàm Python


75

Tôi có một tên hàm được lưu trữ trong một biến như thế này:

myvar = 'mypackage.mymodule.myfunction'

và bây giờ tôi muốn gọi chức năng của mình như thế này

myvar(parameter1, parameter2)

Cách dễ nhất để đạt được điều này là gì?


4
Tại sao không lưu trữ chính hàm? myvar = mypackage.mymodule.myfunctionsạch hơn nhiều.
ironfroggy 17/02/10

1
Từ một bình luận bên dưới: «Nó phải là một chuỗi vì tại nơi nó được xác định, ứng dụng không biết chức năng mong muốn, vì nó là một ứng dụng chung chung.» - schneck
badp 17/02/10

Câu trả lời:


112
funcdict = {
  'mypackage.mymodule.myfunction': mypackage.mymodule.myfunction,
    ....
}

funcdict[myvar](parameter1, parameter2)

1
Tôi tự hỏi hiệu suất đạt được ở đây là gì nếu hàm sẽ được gọi là rất nhiều lần (trong một vòng lặp, đệ quy, v.v.)?
zanlok

5
Tham chiếu đã được giải quyết, vì vậy chỉ cần tra cứu trong dict mất bất kỳ thời gian nào ngoài việc gọi một hàm cục bộ. Và thậm chí điều đó có thể được giảm thiểu bằng cách chỉ nhìn lên một lần.
Ignacio Vazquez-Abrams

"Mypackage.mymodule.my Chức năng" này là gì? Tôi có thể đọc thêm về điều đó ở đâu?
Orvar Korvar

@OrvarKorvar: Thay thế bằng tên và tham chiếu mà bạn chọn.
Ignacio Vazquez-Abrams

À, giờ thì tôi hiểu rồi. fundict là một từ điển.
Orvar Korvar

41

Sẽ đẹp hơn nhiều khi có thể chỉ lưu trữ chính hàm, vì chúng là các đối tượng hạng nhất trong python.

import mypackage

myfunc = mypackage.mymodule.myfunction
myfunc(parameter1, parameter2)

Tuy nhiên, nếu bạn phải nhập động gói, thì bạn có thể đạt được điều này thông qua:

mypackage = __import__('mypackage')
mymodule = getattr(mypackage, 'mymodule')
myfunction = getattr(mymodule, 'myfunction')

myfunction(parameter1, parameter2)

Tuy nhiên, hãy nhớ rằng tất cả công việc đó áp dụng cho bất kỳ phạm vi nào bạn hiện đang ở. Nếu bạn không duy trì chúng bằng cách nào đó, bạn không thể tin tưởng vào việc chúng ở lại nếu bạn rời khỏi phạm vi cục bộ.


15
def f(a,b):
    return a+b

xx = 'f'
print eval('%s(%s,%s)'%(xx,2,3))

ĐẦU RA

 5

Tôi sẽ đưa ra một phiếu ủng hộ để chống lại sự phản đối. Nó có thể không phải là giải pháp tốt nhất, tôi nghĩ đó là một câu trả lời hữu ích vì nó cho thấy một ví dụ hoạt động đầy đủ.
Bryan Oakley

5
@zanlok Đúng là như vậy! :-) hồi đó tôi không biết điều đó.
Pratik Deoghare

@PratikDeoghare Tôi mới bắt đầu bằng python, bạn có thể giải thích những gì (xx = 'f') đang làm, cảm ơn.
RaHuL

9

Dễ nhất

eval(myvar)(parameter1, parameter2)

Bạn không có hàm "con trỏ". Bạn có một chức năng "tên".

Mặc dù điều này hoạt động tốt, bạn sẽ có một số lượng lớn người nói với bạn rằng đó là "không an toàn" hoặc "rủi ro bảo mật".


1
"không an toàn": Nếu myvar xuất phát từ người dùng nhập vào, vâng :)
Federico A. Ramponi

1
@schneck, vậy tại sao nó có thể phải là một chuỗi?
Mike Graham

2
@schneck: Nếu eval ('chuỗi') không tạo ra hàm chính xác, thì câu hỏi của bạn chưa hoàn thành. Bạn đã bỏ qua một cái gì đó quan trọng. Bạn có thể thử đăng nội dung nào đó hoạt động cùng với thông báo lỗi chi tiết về nội dung không hoạt động.
S.Lott

2
@Derrick Turn, @Truptych: Họ chỉ đúng nếu chuỗi đến từ một mạng xã hội độc hại. Đầu vào của người dùng từ những người chưa được xác thực trên internet có khả năng liên quan đến các mạng xã hội độc hại. Hầu hết mọi thứ khác thường không liên quan đến các mạng xã hội độc hại, giảm nguy cơ bảo mật xuống chính xác nguy cơ giống như việc ai đó xóa tất cả mã nguồn của ứng dụng.
S.Lott

6
@schneck, tôi không hiểu ý bạn là "vì đó là một ứng dụng chung" có thể có nghĩa ở đây. Nếu bạn đã định nghĩa đây là một chuỗi ký tự, bạn đã biết đủ về nó mà bạn không cần phải làm như vậy.
Mike Graham

6

Tại sao không lưu trữ chính hàm? myvar = mypackage.mymodule.myfunctionsạch hơn nhiều.


4
modname, funcname = myvar.rsplit('.', 1)
getattr(sys.modules[modname], funcname)(parameter1, parameter2)

2

eval(compile(myvar,'<str>','eval'))(myargs)

compile (..., 'eval') chỉ cho phép một câu lệnh duy nhất, do đó không thể có các lệnh tùy ý sau một cuộc gọi, nếu không sẽ có Lỗi cú pháp. Sau đó, một chút xác thực nhỏ ít nhất có thể hạn chế biểu thức thành một thứ gì đó trong khả năng của bạn, chẳng hạn như kiểm tra 'mypackage' để bắt đầu.


2

Tôi đã gặp sự cố tương tự khi tạo thư viện để xử lý xác thực. Tôi muốn chủ sở hữu ứng dụng sử dụng thư viện của mình có thể đăng ký một lệnh gọi lại với thư viện để kiểm tra ủy quyền đối với các nhóm LDAP mà người được xác thực đang ở trong đó. Cấu hình sẽ được chuyển vào dưới dạng tệp config.py được nhập và chứa một lệnh với tất cả các thông số cấu hình.

Tôi phải làm việc này:

>>> class MyClass(object):
...     def target_func(self):
...         print "made it!"
...    
...     def __init__(self,config):
...         self.config = config
...         self.config['funcname'] = getattr(self,self.config['funcname'])
...         self.config['funcname']()
... 
>>> instance = MyClass({'funcname':'target_func'})
made it!

Có cách nào để làm điều này không?

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.