ฉันจะส่งเมธอดเป็นพารามิเตอร์ใน Python ได้อย่างไร


191

เป็นไปได้ไหมที่จะส่งเมธอดเป็นพารามิเตอร์ไปยังเมธอด?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

คำตอบ:


263

ใช่มันเป็นเพียงใช้ชื่อของวิธีการตามที่คุณเขียน วิธีการ / ฟังก์ชั่นเป็นวัตถุใน Python เช่นเดียวกับสิ่งอื่นและคุณสามารถส่งผ่านสิ่งเหล่านี้ในแบบที่คุณทำตัวแปร ในความเป็นจริงคุณสามารถคิดเกี่ยวกับวิธีการ (หรือฟังก์ชั่น) เป็นตัวแปรที่มีค่าเป็นวัตถุรหัส callable จริง

FYI ไม่มีcallวิธี - ฉันคิดว่ามันถูกเรียก__call__แต่คุณไม่จำเป็นต้องเรียกใช้อย่างชัดเจน:

def method1():
    return 'hello world'

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

method2(method1)

หากคุณต้องการmethod1ได้รับการเรียกพร้อมกับข้อโต้แย้งสิ่งต่าง ๆ ก็จะซับซ้อนขึ้นเล็กน้อย method2จะต้องมีการเขียนข้อมูลเล็กน้อยเกี่ยวกับวิธีการส่งผ่านข้อโต้แย้งไปยังmethod1และต้องได้รับค่าสำหรับการขัดแย้งเหล่านั้นจากที่อื่น ตัวอย่างเช่นหากmethod1ควรใช้อาร์กิวเมนต์หนึ่งตัว:

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

จากนั้นคุณสามารถเขียนmethod2เพื่อเรียกมันพร้อมกับอาร์กิวเมนต์หนึ่งตัวที่ผ่านเข้ามา:

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

หรือด้วยการโต้แย้งว่ามันคำนวณเอง:

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

คุณสามารถขยายสิ่งนี้เป็นชุดค่าอื่น ๆ ที่ส่งผ่านและค่าที่คำนวณเช่น

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)

หรือแม้กระทั่งกับอาร์กิวเมนต์ของคำหลัก

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

หากคุณไม่ทราบว่าเมื่อmethod2ใดmethodToRunจะมีการโต้แย้งอะไรจะเกิดขึ้นคุณยังสามารถใช้การเปิดกล่องถกเถียงในลักษณะทั่วไปได้:

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'})

ในกรณีนี้positional_argumentsจะต้องเป็นรายการหรือ tuple หรือคล้ายกันและkeyword_argumentsเป็น dict หรือคล้ายกัน ในmethod2คุณสามารถปรับเปลี่ยนpositional_argumentsและkeyword_arguments(เช่นการเพิ่มหรือลบการขัดแย้งบางอย่างหรือเปลี่ยนค่า) method1ก่อนที่คุณเรียก


34

ใช่มันเป็นไปได้ แค่เรียกมันว่า:

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

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

1
เกิดอะไรขึ้นถ้าไม่มีกรณีfoo?
Lei Yang

1
แล้วคุณก็ไม่จำเป็นต้อง foo เช่น: def method1(): pass def method2(method) return method() method2(method1)
ทอม

14

นี่คือตัวอย่างของคุณเขียนใหม่เพื่อแสดงตัวอย่างการทำงานแบบสแตนด์อโลน:

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

ใช่; ฟังก์ชั่น (และวิธีการ) เป็นวัตถุชั้นหนึ่งในงูหลาม ผลงานดังต่อไปนี้:

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

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

foo(bar)

ขาออก:

Running parameter f().
In bar().

คำถามประเภทนี้เล็กน้อยที่จะตอบโดยใช้ Python interpreter หรือสำหรับคุณสมบัติเพิ่มเติมเชลล์IPython


5

ถ้าคุณต้องการส่งเมธอดของคลาสเป็นอาร์กิวเมนต์ แต่ยังไม่มีวัตถุที่คุณจะเรียกมันคุณสามารถส่งวัตถุได้เมื่อคุณมีมันเป็นอาร์กิวเมนต์แรก (เช่น "ตัวเอง" การโต้เถียง).

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)

จะพิมพ์ "Hello World"


5

คำตอบที่ดีมากมาย แต่แปลกที่ไม่มีใครพูดถึงการใช้lambdaฟังก์ชั่น
ดังนั้นหากคุณไม่มีข้อโต้แย้งสิ่งต่าง ๆ จะดูเล็กน้อย:

def method1():
    return 'hello world'

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

method2(method1)

แต่บอกว่าคุณมีข้อโต้แย้งหนึ่งข้อ (หรือมากกว่า) ในmethod1:

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

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

แล้วคุณก็สามารถเรียกว่าเป็นmethod2method2(lambda: method1('world'))

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

ฉันพบว่าสิ่งนี้สะอาดกว่าคำตอบอื่น ๆ ที่กล่าวถึงที่นี่


หากนี่เป็นค่าในพจนานุกรมฉันจะเรียกใช้งานมันได้อย่างไรแทนที่จะคืนค่าฟังก์ชันวัตถุ แก้ไข: เพิ่งรู้ว่าฉันสามารถวาง()ส่วนท้ายของวัตถุในการโทรกลับของฉัน, duh
vaponteblizzard

3

วิธีการเป็นวัตถุที่เหมือนกัน ดังนั้นคุณสามารถส่งพวกเขาไปรอบ ๆ เก็บไว้ในรายการและ dicts ทำสิ่งที่คุณชอบกับพวกเขา สิ่งที่พิเศษเกี่ยวกับพวกเขาคือพวกมันเป็นวัตถุที่เรียกได้ดังนั้นคุณจึงสามารถเรียก__call__มันได้ ได้รับการเรียกโดยอัตโนมัติเมื่อคุณเรียกวิธีการมีหรือไม่มีข้อโต้แย้งเพื่อให้คุณเพียงแค่ต้องเขียน__call__methodToRun()


0

ไม่ใช่สิ่งที่คุณต้องการอย่างแน่นอน แต่เครื่องมือที่มีประโยชน์ที่เกี่ยวข้องคือgetattr()การใช้ชื่อของวิธีการเป็นพารามิเตอร์

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')()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.