重写python中的抽象方法

2024-10-01 11:37:45 发布

您现在位置:Python中文网/ 问答频道 /正文

重写python抽象方法时,是否有方法在方法签名中使用额外的参数重写该方法?在

例如

抽象类=

Agent(ABC):

    @abstractmethod
    def perceive_world(self, observation):
        pass

继承类:

^{pr2}$

继承方法签名中带有额外参数的类:

Clever_Agent(Agent):

    def perceive_world(self, observation, prediction):
        print('I see %s' % observation)
        print('I think I am going to see %s happen next' % prediction)

Tags: 方法selfworld参数def抽象类passagent
3条回答

您可以简单地按照您的建议来做:您可以在子类中添加一个额外的参数。在

但是这样做很可能会违反substitution principle,并可能导致错误和设计问题。一般来说,每次超类可用时,子类都是可用的。 也就是说,每当一个方法或函数需要一个Agent,您应该能够传入一个CleverAgent。 不幸的是,如果CleverAgent使用其他参数,那么在Agent上调用perceive_world的任何代码在给定CleverAgent时都将失败。在

有时需要在子类中添加一个可选的paremeter(具有默认值的paremeter)。如果某些代码要知道子类的特殊行为,并且该代码希望在与方法交互时利用这些知识,那么这可能是正确的方法。在

此外,在某些情况下,您正在使用子类化,而Liskov替换原则实际上并不是理想的属性。这种情况通常意味着,除了简单的子类型化之外,您还将语言的对象继承机制用于其他目的。如果你发现自己处在这样的情况下,这是一个很好的提示,你应该仔细检查你的设计,看看是否有一种方法可以更好地协调一致。在

在许多方面,从父类重写抽象方法并添加或更改方法签名在技术上不称为方法重写,您可能有效地做的是方法隐藏。方法重写始终重写父类中特定的现有方法签名。在

您可以通过在父类中定义一个变量抽象方法,并在必要时在子类中重写它来解决这个问题。在

你想做的只是起作用,但这不是个好主意。在

一般来说,重写时不希望以不兼容的方式更改方法的签名。这是Liskov Substitution Principle的一部分。在

在Python中,经常有很好的理由来违反继承并不总是关于子类型的。在

但是当你使用abc来定义一个接口时,这是关于子类型化的。这是ABC子类和abstractmethod修饰符的唯一目的,因此使用它们来表示其他任何东西充其量是高度误导的。在


更详细地说:

通过从Agent继承,可以声明Clever_Agent的任何实例都可以像Agent一样使用。这包括能够调用my_clever_agent.perceive_world(my_observation)。事实上,它不仅仅包括那些,这就是它的全部含义!如果这个调用总是失败的,那么no Clever_Agent是一个Agent,因此它不应该声明是。在

在某些语言中,您有时需要在接口检查时假装自己的方式,以便以后可以进行类型切换和/或“动态强制转换”回到实际类型。在Python中,这是不必要的。没有所谓的“列表Agents”,只是任何东西的列表。(除非您使用可选的静态类型检查,但是在这种情况下,如果您需要绕过静态类型检查,不要声明一个静态类型只是为了给自己一个可以绕过的障碍。)


在Python中,可以通过添加可选参数将方法扩展到超类方法之外,这是完全有效的,因为它仍然与显式声明的类型兼容。例如,这是一件非常合理的事情:

class Clever_Agent(Agent):
    def perceive_world(self, observation, prediction=None):
        print('I see %s' % observation)
        if prediction is None:
            print('I have no predictions about what will happen next')
        else:
            print('I think I am going to see %s happen next' % prediction)

甚至这可能是合理的:

^{pr2}$

相关问题 更多 >