394

I have this code which calculates the distance between two coordinates. The two functions are both within the same class.

However, how do I call the function distToPoint in the function 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)
        ...
cottontail
  • 10,268
  • 18
  • 50
  • 51
Steven
  • 4,193
  • 3
  • 17
  • 11

3 Answers3

620

Since these are member functions, call it as a member function on the instance, self.

def isNear(self, p):
    self.distToPoint(p)
    ...
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
79

That doesn't work because distToPoint is inside your class, so you need to prefix it with the classname if you want to refer to it, like this: classname.distToPoint(self, p). You shouldn't do it like that, though. A better way to do it is to refer to the method directly through the class instance (which is the first argument of a class method), like so: self.distToPoint(p).

Aleksi Torhamo
  • 6,452
  • 2
  • 34
  • 44
  • @Aleski. If it's a generic method (common to all instances and without any instance specific variables referenced in the method), could you please explain why one shouldn't use classname.distToPoint(self, p)? – Yugmorf Oct 10 '18 at 04:04
  • 4
    @Yugmorf: There's only one situation where one should use `classname.distToPoint(self, p)`: when you're defining a subclass that overrides `distToPoint`, but needs to call the original. If you tried to call `self.distToPoint(p)` like normal in that case, you'd end up calling the method that you're just defining, and get into an infinite recursion. If not inside a class, there's also only one situation where you'd use `classname.distToPoint(obj, p)` instead of `obj.distToPoint(p)`: if obj might be an instance of the subclass, but you need to call the original `distToPoint` defined *(continued)* – Aleksi Torhamo Oct 10 '18 at 13:30
  • 1
    in `classname` instead of the overridden version in the subclass - but note that this is very hacky and shouldn't be done in general without a *very* good reason. Note that you break subtype polymorphism when you call a method explicitly through a class (in both of the examples above, you specifically *want* to do that). So in short: you should only call a method explicitly through a class when you *need* to circumvent subtype polymorphism for some [good] reason. If the method hasn't been overridden, the two ways are equal, but `self.distToPoint(p)` is shorter and more readable, *(continued)* – Aleksi Torhamo Oct 10 '18 at 13:30
  • so you should definitely still use it. Now, getting to the specifics of your question: if your method doesn't use any instance variables, maybe it should be a classmethod instead? You make those by adding `@classmethod` before the method, and after that you won't get an instance (`self`) as the first argument anymore - instead you get the class, so you should name the first argument eg. `cls` instead. After that, you can call the classmethod either like `obj.distToPoint(p)` or `classname.distToPoint(p)` (note the lack of `obj`). You should *still* probably use *(continued)* – Aleksi Torhamo Oct 10 '18 at 13:31
  • `obj.distToPoint(p)`, though, if you just have a relevant instance on your hands, unless - again - you have some [good] reason to circumvent subtype polymorphism, since the classmethod could've been overridden in a subclass too, in general. Of course, if you don't have a *relevant* instance available, you should by all means call a *classmethod* directly through a class. – Aleksi Torhamo Oct 10 '18 at 13:31
0

In the OP, distToPoint() and isNear() are both instance methods and as such, both take a reference to an instance (usually named self) as its first argument. When an instance method called directly from the instance, the reference is passed implicitly, so

self.distToPoint(p)

works.


If you want to call an overridden parent method from the child class, then super() could/should be used. In the following example, greet() method is defined in both Parent and Child classes and if you want to call Parent's greet(), the prescribed way is via super(), i.e. super().greet(). It's also possible to do it via the class name, i.e. Parent.greet(self) but there are many arguments against such hard-coding in favor of super() such as flexibility, the ability to use method resolution order correctly etc.

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
cottontail
  • 10,268
  • 18
  • 50
  • 51