简体   繁体   中英

Python subclass overridden method with different signature, so base class method is not called. Why is that?

class UnionFind:

    def __init__(self, n):
        self.parents = list(range(n))
        self.ranks = [0]*n

    def _find(self, x):  # _find -> find

        if self.parents[x] != x:
            self.parents[x] = self._find(self.parents[x])  # _find -> find

        return self.parents[x]

    def _union(self, x, y):

        px = self._find(x)  # _find -> find
        py = self._find(y)  # _find -> find

        if px == py: return False

        if self.ranks[px] < self.ranks[py]:
            py, px = px, py

        self.parents[py] = px
        if self.ranks[px] == self.ranks[py]:
            self.ranks[px] += 1
        return True

class Island(UnionFind):
    
    def __init__(self, m, n):
        super().__init__(m*n+1)
        self.m = m
        self.n = n
        self.islands = 0
        self.occupied = set()
        
    def _coordToIdx(self, i, j):
        return i*self.n+j+1;
    
    def addIsland(self, i, j):
        if (i,j) in self.occupied: return
        self.islands += 1
        self.occupied.add((i,j))
        for di, dj in [(0,1),(1,0),(0,-1),(-1,0)]:
            ni, nj = i+di, j+dj
            if 0<=ni<self.m and 0<=nj<self.n and (ni,nj) in self.occupied:
                self.union(i,j,ni,nj)
                
    def getIslands(self):
        return self.islands
    
    def find(self, i, j):
        return super().find(self._coordToIdx(i,j))
    
    def union(self, i1,j1, i2,j2):
        x, y = self._coordToIdx(i1,j1), self._coordToIdx(i2,j2)
        if super()._union(x, y):
            self.islands -= 1

class Solution:
    def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]:
        ans = []
        island = Island(m,n)
        for i, j in positions:
            island.addIsland(i,j)
            ans.append(island.getIslands())
        return ans

I have a subclass called Island inherited from UnionFind . Both classes have method called find and union . In order to make it work here, I have to change the method in class UnionFind to be a different name ( _find and _union ). I have added a few comments in the code showing that if I replace _find with find I will get a runtime error.

It appears to me that the problem is subclass Island has the same method find as the superclass UnionFind , but with a different number of parameters. When super()._union is called from the subclass, it is trying to call Island::find instead of UnionFind::find . Here is what I don't understand why that would happen.

self.find() always uses the find method of whatever type self is. If you call self.find(..) inside a UnionFind method, but self is an Island , it will call Island.find() . That's the way it works in most object-oriented languages.

If you want to specifically call UnionFind.find , your are doing the right thing in creating a _find that isn't inherited. I'd probably even call it __find so it can't even be inherited by accident.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM