You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python含抽象属性与方法的抽象基类子类实例化触发AttributeError问题求助

解决抽象基类中abstractproperty导致的属性赋值错误

Hey there, let's break down why you're seeing that AttributeError: can't set attribute when trying to instantiate your Caesar class.

What's Going Wrong?

The core issue is how you're using @abstractproperty in your base Cypher class. When you decorate a method with @abstractproperty, Python treats it as a read-only abstract attribute—it only enforces that subclasses implement a getter for the property, but there's no setter defined by default.

So when your Caesar subclass tries to do self._name = name in __init__, Python tries to call a setter method for _name... which doesn't exist. Hence the error.

On top of that, you're defining both abstractproperty attributes and corresponding getXXX() abstract methods (like getName() for _name). That's redundant—you don't need both; pick one pattern and stick with it.

Fixes You Can Use

Here are a couple of straightforward solutions depending on your design preference:

Option 1: Ditch abstractproperty, Keep Getter Methods

If you prefer using explicit getter methods (like getName()) instead of Python's property syntax, just remove the abstractproperty definitions from your base class. This lets your subclass initialize regular instance attributes without restrictions.

Updated base class:

from abc import ABCMeta, abstractmethod

class Cypher(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def getName(self):
        pass

    @abstractmethod
    def getAlphabet(self):
        pass

    @abstractmethod
    def getPass(self):
        pass

    @abstractmethod
    def encryptLine(self, plain_input):
        pass

Your existing Caesar subclass code will work perfectly now—no more errors when instantiating.

Option 2: Use Pythonic Properties with Abstract Getters/Setters

If you want to use attribute access (like caesar.name instead of caesar.getName()), restructure your base class to use @property combined with @abstractmethod, and define abstract setters if you need to allow assigning values to these attributes.

Updated base class:

from abc import ABCMeta, abstractmethod

class Cypher(object):
    __metaclass__ = ABCMeta

    @property
    @abstractmethod
    def name(self):
        pass

    @name.setter
    @abstractmethod
    def name(self, value):
        pass

    @property
    @abstractmethod
    def alphabet(self):
        pass

    @alphabet.setter
    @abstractmethod
    def alphabet(self, value):
        pass

    @property
    @abstractmethod
    def password(self):
        pass

    @password.setter
    @abstractmethod
    def password(self, value):
        pass

    @abstractmethod
    def encryptLine(self, plain_input):
        pass

Then update your Caesar subclass to implement these properties:

class Caesar(Cypher):
    def __init__(self, name, alphabet, password):
        self._name = name
        self._alphabet = alphabet
        self._password = password

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def alphabet(self):
        return self._alphabet

    @alphabet.setter
    def alphabet(self, value):
        self._alphabet = value

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, value):
        self._password = value

    def encryptLine(self, plain_input):
        output = ""
        # Add your encryption logic here
        return output

Now you can instantiate and use Caesar like this:

cipher = Caesar("Caesar Cipher", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 3)
print(cipher.name)  # Output: Caesar Cipher
cipher.name = "Tweaked Caesar"
print(cipher.name)  # Output: Tweaked Caesar

Option 3: Simplify to Enforce Attribute Presence Only

If you just need to ensure subclasses have these attributes (without enforcing getter/setter methods), remove the abstractproperty and getXXX() methods entirely. You can optionally add a check in the base class __init__ to validate required attributes:

Base class:

from abc import ABCMeta, abstractmethod

class Cypher(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def encryptLine(self, plain_input):
        pass

    # Optional: Validate required attributes on initialization
    def __init__(self):
        required_attrs = ['_name', 'alphabet', 'password']
        for attr in required_attrs:
            if not hasattr(self, attr):
                raise NotImplementedError(f"Subclass must define the {attr} attribute")

Your original Caesar code will work as-is here too.

Wrapping Up

The quickest fix is removing those redundant abstractproperty decorators since you already have getter methods defined. If you want to embrace Python's property system, the second option is more idiomatic. Either way, you'll be able to instantiate your Caesar class without issues.

内容的提问来源于stack exchange,提问作者user2144930

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:54:54