ฟังก์ชั่นการโทรหลามภายในชั้นเรียน


242

ฉันมีรหัสนี้ซึ่งคำนวณระยะทางระหว่างสองพิกัด ทั้งสองฟังก์ชั่นมีทั้งภายในชั้นเดียวกัน

อย่างไรก็ตามฉันจะเรียกใช้ฟังก์ชันdistToPointในฟังก์ชันได้isNearอย่างไร

class Coordinates:
    def distToPoint(self, p):
        """
        Use pythagoras to find distance
        (a^2 = b^2 + c^2)
        """
        ...

    def isNear(self, p):
        distToPoint(self, p)
        ...

41
ลอง: self.distToPoint (p)
momeara

เกิดอะไรขึ้นถ้าใกล้และ distToPoint กำลังรับอาร์กิวเมนต์ที่แตกต่างกัน แล้วเราจะเรียก distToPoint ที่อยู่ในชั้นเรียนได้อย่างไร? ทุกคนสามารถอธิบายสิ่งนั้นให้ฉันได้โปรด
Raghavendra Gupta

คำตอบ:


394

เนื่องจากสิ่งเหล่านี้เป็นฟังก์ชันสมาชิกเรียกว่าเป็นฟังก์ชันสมาชิกในอินสแตนซ์, self.

def isNear(self, p):
    self.distToPoint(p)
    ...

2
แต่ระวัง self.foo () จะใช้ลำดับการแก้ไขเมธอดซึ่งอาจแก้ไขฟังก์ชันในคลาสอื่น
ฟรานซิสดาวี่

จะเกิดอะไรขึ้นถ้าเราไม่ใช้ตัวเอง? และโทรโดยตรง distToPoint (p)
Marlon Abeykoon

3
@Marlon Abeykoon "ตัวเอง" อาร์กิวเมนต์จะหายไป
Pitipaty

1
เกิดอะไรขึ้นถ้าใกล้และ distToPoint กำลังรับอาร์กิวเมนต์ที่แตกต่างกัน แล้วเราจะเรียก distToPoint ที่อยู่ในชั้นเรียนได้อย่างไร? ทุกคนสามารถอธิบายสิ่งนั้นให้ฉันได้โปรด
Raghavendra Gupta

46

ไม่ได้ผลเพราะ distToPointอยู่ภายในชั้นเรียนของคุณเพื่อให้คุณจะต้องนำหน้าด้วย ClassName classname.distToPoint(self, p)ถ้าคุณต้องการที่จะเรียกมันเช่นนี้ คุณไม่ควรทำอย่างนั้น วิธีที่ดีกว่าที่จะทำคือการอ้างถึงวิธีการโดยตรงผ่านเช่นชั้น (ซึ่งเป็นอาร์กิวเมนต์แรกของวิธีการเรียน) self.distToPoint(p)เช่นดังนั้น:


@Aleski หากเป็นวิธีการทั่วไป (โดยทั่วไปสำหรับทุกกรณีและไม่มีตัวแปรเฉพาะที่อ้างอิงในวิธีการนี้) คุณช่วยอธิบายได้ไหมว่าทำไมจึงไม่ควรใช้ classname.distToPoint (self, p)
Yugmorf

2
@Yugmorf: มีเพียงสถานการณ์เดียวที่ควรใช้classname.distToPoint(self, p): เมื่อคุณกำหนดคลาสย่อยที่แทนที่distToPointแต่จำเป็นต้องเรียกใช้ต้นฉบับ หากคุณพยายามโทรself.distToPoint(p)ตามปกติในกรณีนั้นคุณจะต้องโทรหาวิธีที่คุณเพิ่งกำหนดและเข้าสู่การเรียกซ้ำแบบไม่สิ้นสุด หากไม่ได้อยู่ในชั้นเรียนมีเพียงสถานการณ์เดียวที่คุณจะใช้classname.distToPoint(obj, p)แทนobj.distToPoint(p): ถ้า obj อาจเป็นตัวอย่างของคลาสย่อย แต่คุณต้องโทรหาต้นฉบับที่distToPointกำหนดไว้(ต่อ)
Aleksi Torhamo

1
ในclassnameแทนรุ่นแทนที่ใน subclass - แต่ทราบว่านี้เป็น hacky มากและไม่ควรทำในทั่วไปโดยไม่ต้องมากเหตุผลที่ดี โปรดทราบว่าคุณแบ่งความแตกต่างชนิดย่อยเมื่อคุณเรียกใช้เมธอดอย่างชัดเจนผ่านคลาส (ในตัวอย่างทั้งสองข้างต้นคุณต้องการทำเช่นนั้นโดยเฉพาะ) ดังนั้นในระยะสั้น: คุณควรเรียกใช้เมธอดอย่างชัดเจนผ่านคลาสเมื่อคุณต้องการหลีกเลี่ยงความหลากหลายย่อยชนิดด้วยเหตุผล [ดี] หากวิธีนี้ไม่ได้ถูกแทนที่ทั้งสองวิธีจะเท่ากัน แต่self.distToPoint(p)สั้นกว่าและอ่านได้ง่ายกว่า(ต่อ)
Aleksi Torhamo

ดังนั้นคุณควรใช้อย่างแน่นอน ทีนี้มาถึงคำถามเฉพาะของคุณ: หากวิธีการของคุณไม่ได้ใช้ตัวแปรอินสแตนซ์ใด ๆ บางทีมันควรจะเป็นคลาสเมธอดแทน? คุณสร้างสิ่งเหล่านั้นด้วยการเพิ่ม@classmethodหน้าเมธอดและหลังจากนั้นคุณจะไม่ได้รับอินสแตนซ์ ( self) เป็นอาร์กิวเมนต์แรกอีกต่อไป - แทนคุณได้รับคลาสดังนั้นคุณควรตั้งชื่ออาร์กิวเมนต์แรกเช่น clsแทน. หลังจากนั้นคุณสามารถเรียกวิธีการเรียนอย่างเช่นobj.distToPoint(p)หรือclassname.distToPoint(p)(สังเกตการขาดobj) คุณควรจะยังคงอาจจะใช้(ต่อ)
Aleksi Torhamo

obj.distToPoint(p)แม้ว่าถ้าคุณมีตัวอย่างที่เกี่ยวข้องอยู่ในมือยกเว้น - อีกครั้งคุณมีเหตุผล [ดี] ที่จะหลีกเลี่ยง polymorphism ชนิดย่อยเนื่องจากวิธีการในชั้นเรียนอาจถูกแทนที่ในคลาสย่อยโดยทั่วไป แน่นอนถ้าคุณไม่มีอินสแตนซ์ที่เกี่ยวข้องพร้อมใช้งานคุณควรเรียกclassmethodผ่านคลาสโดยตรง
Aleksi Torhamo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.