首页 > 解决方案 > 如何在 Python 的抽象类实现中使用 self?

问题描述

我正在开发一个使用 Python 中的抽象类(特别是 abc 模块)的项目。

我有这个抽象类的一些实现,它们有自己的构造函数,需要使用self.

这是我的代码的样子,但经过简化:

from abc import ABC, abstractmethod

class BaseClass(ABC):
    def __init__(self):
        self.sublinks = [] # not meant to be passed in, that's why it isn't an argument in __init__
    
    @classmethod
    def display(cls):
        print(cls.get_contents())
    
    @abstractmethod
    def get_contents():
        pass

class ImplementationOne(Base):
    def __init__(self, url):
        self.url = url

    def get_contents(self):
        return "The url was: " + url

class ImplementationTwo(Base):
    def get_contents():
        return "This does not need a url"

test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()

test_one.display()

但是,当我运行它时,我得到了错误TypeError: get_contents() missing 1 required positional argument: 'self'

我认为这是因为get_contents()在 ImplementationOne 中需要self,但未在抽象方法中指定。

所以,如果我改变:

@abstractmethod
def get_contents():
    pass

@abstractmethod
def get_contents(self):
    pass

但我得到同样的错误。

我尝试了很多组合,包括将self每个出现的或作为参数get_contents,并在抽象类中传递clsget_contents- 但没有运气。

所以,几乎,我如何才能self在抽象方法的某些实现中使用关键字(也称为访问属性),这在抽象类本身的类方法中调用。

另外,附带说明一下,如何self.sublinks从 BaseClass 的所有实现中访问,同时在实现的每个实例中具有不同的值?

标签: pythonpython-3.xclassabcpython-class

解决方案


这里有一些问题。一个是@classmethod装饰器应该只在你需要在类上调用它时使用。

例子:

class ImplementationOne:
    @classmethod
    def display(cls):
        print(f'The class name is {cls.__name__}.')

ImplementationOne.display()

这个名字没有什么特别之处self。这只是大家用来指代实例的东西。在 python 中,除非你有@classmethod装饰器,否则实例会隐式传递给类的第一个参数。在这种情况下,类作为第一个参数传递。

这就是为什么你得到TypeError. 由于您在实例上调用该方法,因此test_one.display()您实际上是将其作为实例方法调用。由于您需要从其中访问实例方法get_contents,这就是您想要的。作为一个classmethod你将无法访问get_contents.

这意味着您需要 ABC 并将ImplementationOne这些方法实现为实例方法。

由于它现在是 ABC 中的实例方法,因此它也应该是ImplementationTwo.

您的另一个问题是如何self.sublinks在两个子类中获取属性。由于您是压倒一切__init__的,因此ImplementationOne您还需要调用父类__init__。您可以通过super()调用 Super 或 Base 类的方法来做到这一点。

class ImplementationOne(BaseClass):
    def __init__(self, url):
        self.url = url
        super().__init__()

完整的工作代码:

from abc import ABC, abstractmethod

class BaseClass(ABC):
    def __init__(self):
        self.sublinks = []
    
    def display(self):
        print(self.get_contents())
    
    @abstractmethod
    def get_contents(self):
        pass

class ImplementationOne(BaseClass):
    def __init__(self, url):
        self.url = url
        super().__init__()

    def get_contents(self):
        return "The url was: " + self.url

class ImplementationTwo(BaseClass):
    def get_contents(self):
        return "This does not need a url"

test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()

test_one.display()
test_two.display()
print(test_one.sublinks)

推荐阅读