如何在一个类中调用一个函数?

397

我有这段代码,它可以计算两个坐标之间的距离。这两个函数都在同一个类中。

但是,我该如何在函数 isNear 中调用函数 distToPoint

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

    def isNear(self, p):
        distToPoint(self, p)
        ...
3个回答

624

由于这些是成员函数,因此请在实例上将其作为成员函数调用,self

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

3
注意,self.foo()将使用方法解析顺序(MRO),这可能会解析到另一个类中的函数。 - Francis Davey
3
如果我们不使用"self",而是直接调用"distToPoint(p)"会发生什么? - Marlon Abeykoon
10
@Marlon Abeykoon,“self”参数将会缺失。 - Pitipaty
1
如果isNear和distToPoint使用不同的参数,那么我们如何调用类内部的distToPoint呢?有人可以为我解释一下吗? - Raghavendra Gupta

79

这么做是行不通的,因为 distToPoint 在你的类中,所以如果你想引用它,你需要在前面加上类名,像这样:classname.distToPoint(self, p)。不过你不应该这样做。更好的方法是直接通过类实例来引用方法(类方法的第一个参数),像这样:self.distToPoint(p)


@Aleski。如果这是一个通用方法(适用于所有实例,并且没有引用任何实例特定变量的方法),您能否解释一下为什么不应该使用classname.distToPoint(self, p)? - Yugmorf
4
只有一个情况需要使用classname.distToPoint(self, p):当你定义一个子类覆盖了distToPoint方法,但是需要调用原始方法时。如果在这种情况下尝试像正常情况一样调用self.distToPoint(p),你会调用正在定义的方法,从而导致无限递归。如果不在类内部,也只有一个情况需要使用classname.distToPoint(obj, p)而不是obj.distToPoint(p):如果obj可能是子类的实例,但你需要调用原始的distToPoint方法 *(接下来的内容)*。 - Aleksi Torhamo
1
classname中调用方法,而不是在子类中覆盖的版本 - 但请注意,这非常hacky,并且通常不应该这样做,除非有一个非常好的理由。当您通过类显式调用方法时(在上述两个示例中,您明确想要这样做),您会破坏子类型多态性。因此,简而言之:仅当您需要为某些[好的]原因规避子类型多态性时,才应通过类显式调用方法。如果方法没有被覆盖,则两种方法相等,但self.distToPoint(p)更短且更易读,*(继续)* - Aleksi Torhamo
所以你肯定仍然应该使用它。现在,回答你的问题:如果你的方法不使用任何实例变量,也许它应该是一个类方法?你可以通过在方法前添加@classmethod来创建它们,在那之后,你将不再获得一个实例(self)作为第一个参数 - 而是获得类,所以你应该将第一个参数命名为cls。之后,你可以像这样调用类方法:obj.distToPoint(p)classname.distToPoint(p)(注意没有obj)。你仍然可能需要使用*(继续)* - Aleksi Torhamo
obj.distToPoint(p),但是如果您手头有一个相关的实例,除非您有一些[好的]理由规避子类型多态性,否则最好不要这样做,因为类方法也可能在子类中被覆盖。当然,如果您没有可用的相关实例,您应该通过类直接调用classmethod - Aleksi Torhamo
@ Aleksi。感谢您的详细解释。 - Yugmorf

0
在OP中,distToPoint()isNear()都是实例方法,因此它们都需要一个实例的引用(通常命名为self)作为第一个参数。当从实例直接调用实例方法时,引用会隐式传递。
self.distToPoint(p)

工作。
如果你想从子类调用覆盖的父类方法,那么应该使用super()。在下面的例子中,greet()方法在ParentChild类中都有定义,如果你想调用Parentgreet(),推荐的方式是通过super(),即super().greet()。也可以通过类名来实现,即Parent.greet(self),但是有很多理由反对这种硬编码的方式,而支持使用super(),比如灵活性、正确使用方法解析顺序等。
class Parent:
    def greet(self):
        print("greetings from Parent!")
        
    def parent_printer(self):
        print("this is parent printer")
        
class Child(Parent):
    def greet(self, parent=False):
        if parent:
            super().greet()                 # Parent's greet is called
        else:
            print("greetings from Child!")
        
    def printer(self, greet=True):
        if greet:
            self.greet()                    # Child's greet is called
        else:
            self.parent_printer()           # Parent's parent_printer is inherited
        
        
c = Child()
c.greet()                # greetings from Child!
c.greet(parent=True)     # greetings from Parent!
c.printer()              # greetings from Child!
c.printer(greet=False)   # this is parent printer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接