ฟังก์ชั่นที่มากเกินไปใน Python


93

เป็นไปได้ไหมที่จะมีฟังก์ชันโอเวอร์โหลดใน Python?

ใน C # ฉันจะทำสิ่งที่ชอบ

void myfunction (int first, string second)
{
    // Some code
}

void myfunction (int first, string second , float third)
{
    // Some different code
}

จากนั้นเมื่อฉันเรียกใช้ฟังก์ชันมันจะแยกความแตกต่างระหว่างทั้งสองตามจำนวนอาร์กิวเมนต์ เป็นไปได้ไหมที่จะทำสิ่งที่คล้ายกันใน Python


ดูเหมือนว่าอาจเป็นโพสต์ที่ซ้ำกัน โปรดอย่าตั้งค่าสถานะเป็น C # เนื่องจากคำถามไม่เกี่ยวข้องกับ C # function-overloading-in-python-missing
Jethro



คำตอบ:


104

แก้ไขสำหรับฟังก์ชั่นทั่วไปการจัดส่งเดี่ยวใหม่ใน Python 3.4 โปรดดูที่http://www.python.org/dev/peps/pep-0443/

โดยทั่วไปคุณไม่จำเป็นต้องโอเวอร์โหลดฟังก์ชันใน Python Python พิมพ์แบบไดนามิกและสนับสนุนอาร์กิวเมนต์เสริมสำหรับฟังก์ชัน

def myfunction(first, second, third = None):
    if third is None:
        #just use first and second
    else:
        #use all three

myfunction(1, 2) # third will be None, so enter the 'if' clause
myfunction(3, 4, 5) # third isn't None, it's 5, so enter the 'else' clause

3
แต่โปรดทราบว่าการเรียกใช้ฟังก์ชันต่างๆตามประเภทของอาร์กิวเมนต์นั้นยากกว่ามาก (แม้ว่าจะไม่เป็นไปไม่ได้ก็ตาม)
Andrew Jaffe

9
มีความแตกต่างระหว่าง overloading / polymorphism และ conditionals คุณหมายความว่าเราไม่ต้องการโพลีมอร์ฟิสม์เนื่องจากเรามีเงื่อนไขหรือไม่?
วัล

1
@Val ฉันกำลังพูดโดยพื้นฐานแล้วว่าในภาษาที่พิมพ์แบบไดนามิกคุณไม่จำเป็นต้องมีการใช้ภาษามากเกินไปเพราะคุณสามารถเลียนแบบรหัสได้เล็กน้อยและสามารถรับความหลากหลายได้ด้วยวิธีนั้น
agf

1
@Val ฉันกำลังบอกว่าระหว่างอาร์กิวเมนต์ที่เป็นทางเลือกและประเภทไดนามิกแบบที่คุณมีใน Python คุณไม่จำเป็นต้องใช้วิธีการสไตล์ Java มากเกินไปเพื่อให้เกิดความหลากหลาย
agf

3
@navidoo ฉันจะเถียงว่านั่นไม่ใช่ความคิดที่ดี - ฟังก์ชั่น shoud ไม่ส่งคืนสิ่งที่แตกต่างอย่างสิ้นเชิง อย่างไรก็ตามคุณสามารถกำหนดฟังก์ชันเครื่องกำเนิดไฟฟ้าในพื้นที่ภายในฟังก์ชันหลักเรียกใช้และส่งคืนเครื่องกำเนิดไฟฟ้าที่เป็นผลลัพธ์ - จากภายนอกจะเหมือนกับว่าฟังก์ชันหลักเป็นเครื่องกำเนิดไฟฟ้า ตัวอย่างที่นี่
agf

51

ในหลามปกติคุณไม่สามารถทำสิ่งที่คุณต้องการได้ มีสองการประมาณใกล้เคียง:

def myfunction(first, second, *args):
    # args is a tuple of extra arguments

def myfunction(first, second, third=None):
    # third is optional

อย่างไรก็ตามหากคุณต้องการทำสิ่งนี้จริงๆคุณสามารถทำให้มันใช้งานได้ (เสี่ยงต่อการทำให้พวกอนุรักษนิยมขุ่นเคือง; o) ในระยะสั้นคุณจะต้องเขียนwrapper(*args)ฟังก์ชันที่ตรวจสอบจำนวนอาร์กิวเมนต์และผู้รับมอบสิทธิ์ตามความเหมาะสม "แฮ็ค" ประเภทนี้มักจะทำผ่านมัณฑนากร ในกรณีนี้คุณสามารถบรรลุสิ่งต่างๆเช่น:

from typing import overload

@overload
def myfunction(first):
    ....

@myfunction.overload
def myfunction(first, second):
    ....

@myfunction.overload
def myfunction(first, second, third):
    ....

และคุณจะใช้สิ่งนี้โดยการสร้างoverload(first_fn) ฟังก์ชัน (หรือตัวสร้าง) ส่งคืนอ็อบเจ็กต์ที่เรียกได้โดยที่__call__(*args) เมธอดใช้การมอบหมายที่อธิบายไว้ข้างต้นและoverload(another_fn) เมธอดจะเพิ่มฟังก์ชันพิเศษที่สามารถมอบหมายให้ได้

คุณสามารถดูตัวอย่างของสิ่งที่คล้ายกันได้ที่นี่http://acooke.org/pytyp/pytyp.spec.dispatch.htmlแต่เป็นวิธีการที่มากเกินไปตามประเภท เป็นแนวทางที่คล้ายกันมาก ...

อัปเดต: และสิ่งที่คล้ายกัน (โดยใช้ประเภทอาร์กิวเมนต์) จะถูกเพิ่มลงใน python 3 - http://www.python.org/dev/peps/pep-0443/


rangebuiltin ใช้เกินเพื่อให้มันเป็นจริงสับ? github.com/python/typeshed/blob/master/stdlib/2and3/…
CptJero

9

ใช่มันเป็นไปได้ ฉันเขียนโค้ดด้านล่างใน Python 3.2.1:

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

การใช้งาน:

myfunction=overload(no_arg_func, one_arg_func, two_arg_func)

สังเกตว่าแลมบ์ดาที่ส่งคืนโดยoverloadฟังก์ชันเลือกฟังก์ชันที่จะเรียกขึ้นอยู่กับจำนวนอาร์กิวเมนต์ที่ไม่มีชื่อ

วิธีแก้ปัญหาไม่สมบูรณ์แบบ แต่ในขณะนี้ฉันไม่สามารถเขียนอะไรให้ดีขึ้นได้


1

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

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

หากคุณไม่จำเป็นต้องโอเวอร์โหลดตามประเภท แต่ตามจำนวนอาร์กิวเมนต์ให้ใช้อาร์กิวเมนต์คำหลัก


3
ฉันไม่คิดว่าเขารู้เกี่ยวกับข้อโต้แย้งที่เป็นทางเลือก
agf

0

วิธีการมากเกินไปเป็นเรื่องยุ่งยากใน python อย่างไรก็ตามอาจมีการใช้การส่งผ่านตัวแปร dict, list หรือ primitive

ฉันได้ลองใช้บางอย่างสำหรับกรณีการใช้งานของฉันแล้วสิ่งนี้จะช่วยให้เข้าใจคนที่ใช้วิธีการนี้มากเกินไป

ลองใช้ตัวอย่างในหนึ่งใน stackoverflow thread:

class overload method พร้อมเรียก method จาก class อื่น

def add_bullet(sprite=None, start=None, headto=None, spead=None, acceleration=None):

ส่งผ่านอาร์กิวเมนต์จากคลาสระยะไกล:

add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},accelaration=10.6}

หรือ add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},speed=['10','20,'30']}

ดังนั้นการจัดการจึงทำได้สำหรับรายการพจนานุกรมหรือตัวแปรดั้งเดิมจากการโอเวอร์โหลดวิธีการ

ลองใช้รหัสของคุณ

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