Làm cách nào để tôi truyền một phương thức làm tham số trong Python


188

Có thể truyền một phương thức làm tham số cho một phương thức không?

self.method2(self.method1)

def method1(self):
    return 'hello world'

def method2(self, methodToRun):
    result = methodToRun.call()
    return result

Câu trả lời:


261

Đúng vậy, chỉ cần sử dụng tên của phương thức, như bạn đã viết. Các phương thức / hàm là các đối tượng trong Python, giống như mọi thứ khác và bạn có thể chuyển chúng xung quanh cách bạn thực hiện các biến. Trong thực tế, bạn có thể nghĩ về một phương thức (hoặc hàm) như một biến có giá trị là đối tượng mã có thể gọi thực tế.

FYI, không có callphương pháp nào - tôi nghĩ nó được gọi __call__, nhưng bạn không cần phải gọi nó một cách rõ ràng:

def method1():
    return 'hello world'

def method2(methodToRun):
    result = methodToRun()
    return result

method2(method1)

Nếu bạn muốn method1được gọi bằng các đối số, thì mọi thứ sẽ phức tạp hơn một chút. method2phải được viết với một chút thông tin về cách truyền đối số method1và nó cần lấy giá trị cho các đối số đó từ đâu đó. Chẳng hạn, nếu method1được cho là lấy một đối số:

def method1(spam):
    return 'hello ' + str(spam)

sau đó bạn có thể viết method2để gọi nó với một đối số được truyền vào:

def method2(methodToRun, spam_value):
    return methodToRun(spam_value)

hoặc với một đối số mà nó tự tính toán:

def method2(methodToRun):
    spam_value = compute_some_value()
    return methodToRun(spam_value)

Bạn có thể mở rộng giá trị này sang các kết hợp giá trị khác được truyền vào và các giá trị được tính toán, như

def method1(spam, ham):
    return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(methodToRun, ham_value):
    spam_value = compute_some_value()
    return methodToRun(spam_value, ham_value)

hoặc thậm chí với các đối số từ khóa

def method2(methodToRun, ham_value):
    spam_value = compute_some_value()
    return methodToRun(spam_value, ham=ham_value)

Nếu bạn không biết, khi viết method2, những đối số methodToRunnào sẽ diễn ra, bạn cũng có thể sử dụng giải nén đối số để gọi nó theo cách chung:

def method1(spam, ham):
    return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(methodToRun, positional_arguments, keyword_arguments):
    return methodToRun(*positional_arguments, **keyword_arguments)

method2(method1, ['spam'], {'ham': 'ham'})

Trong trường hợp này positional_argumentscần phải là một danh sách hoặc tuple hoặc tương tự, và keyword_argumentslà một dict hoặc tương tự. Trong method2bạn có thể sửa đổi positional_argumentskeyword_arguments(ví dụ để thêm hoặc xóa một số đối số nhất định hoặc thay đổi các giá trị) trước khi bạn gọi method1.


34

Vâng, nó là có thể. Chỉ cần gọi nó:

class Foo(object):
    def method1(self):
        pass
    def method2(self, method):
        return method()

foo = Foo()
foo.method2(foo.method1)

1
Nếu không có ví dụ foothì sao?
Lôi Dương

1
Sau đó, bạn chỉ cần không cần foo, ví dụ: def method1(): pass def method2(method) return method() method2(method1)
Tom

14

Dưới đây là ví dụ của bạn được viết lại để hiển thị một ví dụ hoạt động độc lập:

class Test:
    def method1(self):
        return 'hello world'

    def method2(self, methodToRun):
        result = methodToRun()
        return result

    def method3(self):
        return self.method2(self.method1)

test = Test()

print test.method3()

6

Đúng; hàm (và phương thức) là các đối tượng lớp đầu tiên trong Python. Các công việc sau đây:

def foo(f):
    print "Running parameter f()."
    f()

def bar():
    print "In bar()."

foo(bar)

Đầu ra:

Running parameter f().
In bar().

Các loại câu hỏi này không quan trọng để trả lời bằng trình thông dịch Python hoặc, để biết thêm các tính năng, trình bao IPython .


5

Nếu bạn muốn truyền một phương thức của một lớp làm đối số nhưng chưa có đối tượng mà bạn sẽ gọi nó, bạn có thể chỉ cần truyền đối tượng một khi bạn có nó làm đối số đầu tiên (tức là "tự" tranh luận).

class FooBar:

    def __init__(self, prefix):
        self.prefix = prefix

    def foo(self, name):
        print "%s %s" % (self.prefix, name)


def bar(some_method):
    foobar = FooBar("Hello")
    some_method(foobar, "World")

bar(FooBar.foo)

Điều này sẽ in "Hello World"


4

Rất nhiều câu trả lời hay nhưng lạ mà không ai nhắc đến khi sử dụng lambdahàm.
Vì vậy, nếu bạn không có tranh luận, mọi thứ trở nên tầm thường:

def method1():
    return 'hello world'

def method2(methodToRun):
    result = methodToRun()
    return result

method2(method1)

Nhưng giả sử bạn có một (hoặc nhiều) đối số trong method1:

def method1(param):
    return 'hello ' + str(param)

def method2(methodToRun):
    result = methodToRun()
    return result

Sau đó, bạn có thể chỉ cần gọi method2như method2(lambda: method1('world')).

method2(lambda: method1('world'))
>>> hello world
method2(lambda: method1('reader'))
>>> hello reader

Tôi thấy điều này sạch sẽ hơn nhiều so với các câu trả lời khác được đề cập ở đây.


Nếu đây là một giá trị trong từ điển, làm thế nào tôi có thể thực thi nó thay vì trả về một đối tượng hàm? Chỉnh sửa: Chỉ cần nhận ra tôi chỉ có thể đặt ()ở cuối đối tượng trong cuộc gọi trở lại của mình, duh.
vaponteblizzard

3

Phương thức là đối tượng như bất kỳ khác. Vì vậy, bạn có thể vượt qua chúng, lưu trữ chúng trong danh sách và ký hiệu, làm bất cứ điều gì bạn thích với chúng. Điều đặc biệt về chúng là chúng là những vật thể có thể gọi được để bạn có thể gọi __call__chúng. __call__được gọi tự động khi bạn gọi phương thức có hoặc không có đối số để bạn chỉ cần viết methodToRun().


0

Không chính xác những gì bạn muốn, nhưng một công cụ hữu ích có liên quan là getattr(), sử dụng tên của phương thức làm tham số.

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()
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.