【问题标题】:Python: How do you specify the parameter type of a Class function to the current class?Python:如何为当前类指定一个Class函数的参数类型?
【发布时间】:2022-01-11 08:59:20
【问题描述】:

我正在使用 Python 编写一组具有继承的自定义类。这是简化的代码:

class Parent(object):
    __slots__ = ['a','b']

    def __init__(self, a:int, b:int):
        self.a = a
        self.b = b
    
    def myfunc(self,s)->int:
        return self.a + s.a

class Child(Parent):
    __slots__ = ['c']

    def __init__(self, a:int, b:int, c:int):
        super().__init__(a,b)
        self.c = c

    def myfunc(self,s)->int:
        return self.a + s.a + s.c

def main():
    dad = Parent(1,2)
    son = Child(4,8,16)

    print(dad.myfunc(son))
    print(son.myfunc(son))
    print(son.myfunc(dad))

if __name__ == "__main__":
    main()

在运行该函数时,我得到了这个输出(我理解):

5
24
Error: Parent has no attribute 'c'

Child 中的 myfunc() 定义要求 self 和 s 都是 Child 的实例。

我对这段代码的理想功能是我想实现方法重载。当son.myfunc(dad) 被调用时,我想让它检查爸爸的类型。如果dad也是Child,则应该使用Childmyfunc()的定义。否则,如果爸爸不是Child,儿子应该回退到使用Parent 中的myfunc() 的定义。所以,对于上面的代码,我想要:

5
24
5

本以为可以如下实现这个功能,指定myfunc()的参数类型:

class Parent(object):
    __slots__ = ['a','b']

    def __init__(self, a:int, b:int):
        self.a = a
        self.b = b
    
    def myfunc(self, s:Parent)->int:
        return self.a + s.a

class Child(Parent):
    __slots__ = ['c']

    def __init__(self, a:int, b:int, c:int):
        super().__init__(a,b)
        self.c = c

    def myfunc(self,s:Child)->int:
        return self.a + s.a + s.c

def main():
    dad = Parent(1,2)
    son = Child(4,8,16)

    print(dad.myfunc(son))
    print(son.myfunc(son))
    print(son.myfunc(dad))

if __name__ == "__main__":
    main()

但是,这不起作用。 Python 和我的 IDE 告诉我 "Parent is not defined" 在我使用它来指定 Parent's myfunc() 的输入类型时,Child 也是如此。我想我明白它在说什么('Parent' 在编译器完成读取 Parent 之前没有任何意义,因此不能将其指定为参数类型),但我不知道如何解决这个问题。

如何实现我的预期功能?是否有像'this''self' 这样的关键字可用于引用这些规范的当前类的类型?即使方法重载不能以这种方式工作——有没有办法让单个类 (Parent) 将自己指定为其函数之一的参数类型?

编辑:我知道 Python 参数类型是可读性和错误检查的注释,如果使用不同的类型调用它们实际上不会导致错误/失败。创建第二个代码段是为了帮助传达我想要发生的事情。我知道我可能必须在 myfunc 的开头添加一个类似 isinstance() 的检查,但是 (a) 如果有其他选择,我想避免它 (b) 如果我确实在 Child 的 myfunc() 的主体中发现我想调用 Parent 的,我不确定该怎么做。

【问题讨论】:

    标签: python class inheritance types overloading


    【解决方案1】:

    您有两个不同的问题:

    1. 为了对返回自己的类 (forward reference) 的方法进行类型提示,您应该使用字符串:

      def myfunc(self, s: "Parent") -> int:
      
    2. 您可以使用isinstance 来检查类型,即

      def myfunc(self, s: "Child") -> int:
          return (self.a + s.a + s.c) if isinstance(s, Child) else (self.a + s.a)
      

    作为旁注,您的Child.myfunc 中的s 类型可能应该是Parent

    更新:根据您的评论,以下应该是可能的:

    class Parent(object):
        # ...
    
        def _myfunc(self, s: "Parent") -> int:
            return self.a + s.a
    
        def myfunc(self, s: "Parent") -> int:
            return type(s)._myfunc(self, s)
    
    class Child(Parent):
        # ...
    
        def _myfunc(self, s: "Parent") -> int:
            return self.a + s.a + s.c
    

    【讨论】:

    • 1.感谢您向我推荐前向引用!那是我一直在寻找很长时间的东西,但不知道如何表达它来搜索它。 2. 我曾考虑过使用 isinstance(),但犹豫不决。在我的真实代码中,每个版本的 myfunc() 大约有 50 行长。有没有办法我可以从 Child 的 myfunc() 中调用 Child 上的 Parent 版本的 myfunc() (而不是像你所做的那样再次复制所有代码)?
    • 这听起来像是 xy 问题。您的简化示例对我来说太简单了,闻起来像是糟糕的设计。有关滥用 Python 灵活性的方法,请参阅我的更新答案。
    猜你喜欢
    • 2017-04-16
    • 2020-11-09
    • 2022-06-18
    • 2014-12-03
    • 2023-01-10
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多