如何正确编码抽象类及其子类以具有 getter/setter 行为?

问题描述 投票:0回答:1

在Python(3.11)中我有这个抽象类:

from abc import ABCMeta, abstractmethod
from copy import deepcopy

class BookPrototype(metaclass=ABCMeta):
  
    @property
    def title(self):
        pass

    @title.setter
    @abstractmethod
    def title(self, val):
        pass

    @abstractmethod
    def clone(self):
        pass

我创建这个子类:

class ScienceFiction(BookPrototype):

    def title(self, val):
        print("this never gets called without decorator")

    def __init__(self):
        pass

    def clone(self):
        return deepcopy(self)

并以这种方式使用它:

science1 = ScienceFiction()
science1.title = "From out of nowhere"
science2 = science1.clone()
print(science2.title)
science2.title = "New title"
print(science2.title)
print(science1.title)

这段代码完全符合我的要求,即它创建

ScienceFiction
类的实例,克隆它,打印克隆对象的标题,并再次打印第一个对象的标题。所以,我这里的版画是“不知从何而来”,“新标题”,“不知从何而来”。

问题是,按照文档,我将

@BookPrototype.title.setter
装饰器添加到标题设置器,这样:

@BookPrototype.title.setter
    def title(self, val):
        print("this gets called now")
    

在这种情况下,标题方法中的 print 可以工作,但我无法分配任何值,因此代码打印三个 None。

我做错了什么?如何正确编码抽象类及其子类以具有 getter/setter 行为?

python abstract-class
1个回答
1
投票

标题值应存储在变量中。例如,它可以存储在基类的

self._title
中。 我想你正在寻找的是这样的:

from abc import ABCMeta, abstractmethod
from copy import deepcopy

class BookPrototype(metaclass=ABCMeta):

    def __init__(self):
        self._title: str = ""

    @property
    def title(self):
        return self._title

    @title.setter
    @abstractmethod
    def title(self, val):
        ...

    @abstractmethod
    def clone(self):
        ...

class ScienceFiction(BookPrototype):
    @BookPrototype.title.setter
    def title(self, val):
        self._title = val

    def clone(self):
        return deepcopy(self)

science1 = ScienceFiction()
science1.title = "From out of nowhere"
science2 = science1.clone()
print(science2.title)
science2.title = "New title"
print(science2.title)
print(science1.title)

# From out of nowhere
# New title
# From out of nowhere

当您删除装饰器时

@BookPrototype.title.setter
,如下所示:

class ScienceFiction(BookPrototype):

    def title(self, val):
        print("this never gets called without decorator")

    def __init__(self):
        pass

    def clone(self):
        return deepcopy(self)

使用字符串设置变量

title
只需使用
str
对象覆盖该方法即可。这可以通过以下内容看出:

science = ScienceFiction()
print(type(getattr(science, 'title')))
science.title = "From out of nowhere"
print(type(getattr(science, 'title')))

# <class 'method'>
# <class 'str'>  

注意,在Python中你可以动态添加/修改/删除属性。

© www.soinside.com 2019 - 2024. All rights reserved.