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

