Reputation: 347
I have the following snippet:
from abc import abstractproperty
class Base(object):
@abstractproperty
def foo(self):
print 'wat'
class C(Base):
def __init__(self):
self.foo = 'test'
self.bar = 'test2'
c = C()
When I execute it, it gives the stacktrace:
in __init__ AttributeError: can't set attribute
on the line self.foo = 'test'
.
Anyone know why this is happening?
Upvotes: 1
Views: 2524
Reputation: 17761
First of all, note that you forgot to use ABCMeta
as your metaclass. Change your code to:
from abc import ABCMeta
class Base(object):
__metaclass__ = ABCMeta
...
For Python 3.x, any of the following:
from abc import ABC, ABCMeta
class Base(ABC):
...
class Base(metaclass=ABCMeta):
...
And you'll see this nice error:
Traceback (most recent call last):
File "a.py", line 14, in <module>
c = C()
TypeError: Can't instantiate abstract class C with abstract methods foo
It's telling you that you need a concrete implementation for your abstract property.
But that's not enough: to properly have self.foo = 'test'
working, you need to implement a concrete setter for your property.
In the end, your code should look like this:
from abc import ABCMeta, abstractproperty
class Base(object):
__metaclass__ = ABCMeta
@abstractproperty
def foo(self):
print 'wat'
class C(Base):
@property
def foo(self):
# do something
@foo.setter
def foo(self, value):
# do something else
def __init__(self):
self.foo = 'test'
self.bar = 'test2'
c = C()
Remember that you can use super()
in your concrete property code to use the code from the abstract property.
Note: that since Python 3.3, @abstractproperty
has been deprecated. Instead, you should use a combination of @property
and @abstractmethod
:
class Base(ABC):
@property
@abstractmethod
def foo(self):
...
Upvotes: 4
Reputation: 5210
Your code defines a read-only abstractproperty
. See docs on ABC. In addition, you did not set ABCMeta
as meta class, which is obligatory. Furthermore, an abstractproperty
is abstract which means that it has to be overwritten in the child class.
If you want to create a read-write abstractproperty
, go with something like this:
from abc import ABCMeta, abstractproperty
class Base(object):
__metaclass__ = ABCMeta # This is required.
def getfoo(self):
pass # Getter for preprocessing when property 'foo' is requested
def setfoo(self, thefoo):
pass # Setter for preprocessing when property 'foo' is set
foo = abstractproperty(getfoo, setfoo)
class C(Base):
foo = '' # Overwrite abstract property
def __init__(self):
self.foo = 'test'
self.bar = 'test2'
Using the code above, you can instantiate your class C
and set its property foo
:
c = C()
print(c.foo)
>>> test
Upvotes: 1