简体   繁体   English

如何在 Python 的抽象 class 实现中使用 self?

[英]How to use self in an abstract class implementation in Python?

I'm working on a project using abstract classes in Python (specifically, the abc module).我正在使用 Python (特别是 abc 模块)中的抽象类来开发一个项目。

I have a few implementations of this abstract class, which have their own constructors and need to use self .我有这个抽象 class 的一些实现,它们有自己的构造函数,需要使用self

This is what my code looks like, but simplified:这是我的代码的样子,但经过简化:

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()

When I run this, however, I get the error TypeError: get_contents() missing 1 required positional argument: 'self' .但是,当我运行它时,我收到错误TypeError: get_contents() missing 1 required positional argument: 'self'

I figured that this is because get_contents() in ImplementationOne takes self , but it's not specified in the abstract method.我认为这是因为 ImplementationOne 中的get_contents()采用self ,但未在抽象方法中指定。

So, if I changed:所以,如果我改变:

@abstractmethod
def get_contents():
    pass

to

@abstractmethod
def get_contents(self):
    pass

But I get the same error.但我得到同样的错误。

I've tried many combinations, including putting self as an argument to every occurrence or get_contents , and passing in cls to get_contents in the abstract class - but no luck.我尝试了许多组合,包括将self作为每次出现或get_contents的参数,并将cls传递给抽象get_contents中的 get_contents - 但没有运气。

So, pretty much, how can I use the self keyword (aka access attributes) in only some implementations of an abstract method, that's called within a class method in the abstract class itself.所以,几乎,我如何才能在抽象方法的某些实现中使用self关键字(又名访问属性),这在抽象 class 本身的 class 方法中调用。

Also, on a side note, how can I access self.sublinks from within all implementations of BaseClass, while having its values different in each instance of an implementation?另外,附带说明一下,如何从 BaseClass 的所有实现中访问self.sublinks ,同时在实现的每个实例中具有不同的值?

There are a few things wrong here.这里有一些问题。 One is that the @classmethod decorator should only be used when you need it to be called on a class.一个是@classmethod装饰器应该只在你需要在 class 上调用它时使用。

Example:例子:

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

ImplementationOne.display()

There is nothing special about the name self . self这个名字没有什么特别之处。 It's just what is used by everyone to refer to the instance.这只是大家用来指代实例的东西。 In python the instance is implicitly handed to the first argument of the class unless you have a @classmethod decorator.在 python 中,实例隐式传递给 class 的第一个参数,除非您有@classmethod装饰器。 In that case the class is handed as the first argument.在这种情况下, class 作为第一个参数传递。

That is why you are getting the TypeError .这就是你得到TypeError的原因。 Since you are calling the method on the instance test_one.display() you are essentially calling it as an instance method.由于您在实例test_one.display()上调用该方法,因此您实际上是在将其作为实例方法调用。 Since you need to access the instance method get_contents from within it that is what you want.由于您需要从其中访问实例方法get_contents ,这就是您想要的。 As a classmethod you wouldn't have access to get_contents .作为一个类方法,您将get_contents classmethod

That means you need both the ABC and ImplementationOne to have those methods implemented as instance methods.这意味着您需要 ABC 和ImplementationOne才能将这些方法实现为实例方法。

Since it is now an instance method on the ABC it also should be an instance method in ImplementationTwo .由于它现在是 ABC 上的实例方法,因此它也应该是ImplementationTwo中的实例方法。

Your other question was how to get self.sublinks as an attribute in both subclasses.您的另一个问题是如何将self.sublinks作为两个子类中的属性。 Since your are overriding __init__ in ImplementationOne you need to call the parent class's __init__ as well.由于您在ImplementationOne中覆盖了__init__ ,因此您还需要调用父类的__init__ You can do this by using super() to call the Super or Base class's methods.您可以通过使用super()调用 Super 或 Base 类的方法来做到这一点。

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

Full working code:完整的工作代码:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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