How to write to an abstract property in Python 3.4+
Question:
In Python 3.6, Let’s say I have an abstract class MyAbstractClass
from abc import ABC, abstractmethod
class MyAbstractClass(ABC):
@property
@abstractmethod
def myProperty(self):
pass
and a class MyInstantiatableClass
inherit from it. So how do I write to the property myProperty
on instantiation of an object from this class? I’d like to be able to both set and get myProperty
. Below doesn’t work.
from MyAbstractClass import MyAbstractClass
class MyInstantiatableClass(MyAbstractClass):
def __init__(self, desiredValueOfMyProperty):
????
@myProperty.setter
def myProperty(self, desiredValueOfMyProperty): # value coming from __init__
self._myProperty = desiredValueOfMyProperty
And a main function, say,
from MyInstantiatableClass import MyInstantiatableClass
def main():
MyInstantiatableClass(3) # 3 is the desiredValueOfMyProperty for this instantiation
MyInstantiatableClass(5) # 5 is the desiredValueOfMyProperty for this instantiation
Answers:
It seems there’s a discrepancy here; using @property
along with @abstractmethod
doesn’t seem to enforce classes that inherit from your abc to need to define both setter
and getter
. Using this:
@property
@abstractmethod
def myProperty(self):
pass
@myProperty.setter
@abstractmethod
def myProperty(self):
pass
and then providing an implementation only for the getter
in the class works and allows for instantiation:
@property
def myProperty(self):
return self._myProperty
This is due to the fact that only one name (myProperty
) appears in the namespace of the ABC, when you override in the base class, you only need to define this one name.
There’s a way around that enforces it. You can create separate abstract methods and pass them on to property
directly:
class MyAbstractClass(ABC):
@abstractmethod
def getProperty(self):
pass
@abstractmethod
def setProperty(self, val):
pass
myAbstractProperty = property(getProperty, setProperty)
Providing an implementation for this abc now requires both getter
and setter
to have an implementation (both names that have been listed as abstractmethod
s in MyAbstractClass
namespace need to have an implementation):
class MyInstantiatableClass(MyAbstractClass):
def getProperty(self):
return self._Property
def setProperty(self, val):
self._Property = val
myAbstractProperty = property(getProperty, setProperty)
Implementing them is exactly the same as any old property. There’s no difference there.
For example, you can define the abstract getter, setter and deleter in Person
abstract class, override them in Student
class which extends Person
abstract class as shown below. *@abstractmethod
must be the innermost decorator otherwise error occurs:
from abc import ABC, abstractmethod
class Person(ABC):
@property
@abstractmethod # The innermost decorator
def name(self): # Abstract getter
pass
@name.setter
@abstractmethod # The innermost decorator
def name(self, name): # Abstract setter
pass
@name.deleter
@abstractmethod # The innermost decorator
def name(self): # Abstract deleter
pass
class Student(Person):
def __init__(self, name):
self._name = name
@property
def name(self): # Overrides abstract getter
return self._name
@name.setter
def name(self, name): # Overrides abstract setter
self._name = name
@name.deleter
def name(self): # Overrides abstract deleter
del self._name
Then, you can instantiate Student
class and call the getter, setter and deleter as shown below:
obj = Student("John") # Instantiates "Student" class
print(obj.name) # Getter
obj.name = "Tom" # Setter
print(obj.name) # Getter
del obj.name # Deleter
print(hasattr(obj, "name"))
Output:
John
Tom
False
You can see my answer which explains more about abstract property.
In Python 3.6, Let’s say I have an abstract class MyAbstractClass
from abc import ABC, abstractmethod
class MyAbstractClass(ABC):
@property
@abstractmethod
def myProperty(self):
pass
and a class MyInstantiatableClass
inherit from it. So how do I write to the property myProperty
on instantiation of an object from this class? I’d like to be able to both set and get myProperty
. Below doesn’t work.
from MyAbstractClass import MyAbstractClass
class MyInstantiatableClass(MyAbstractClass):
def __init__(self, desiredValueOfMyProperty):
????
@myProperty.setter
def myProperty(self, desiredValueOfMyProperty): # value coming from __init__
self._myProperty = desiredValueOfMyProperty
And a main function, say,
from MyInstantiatableClass import MyInstantiatableClass
def main():
MyInstantiatableClass(3) # 3 is the desiredValueOfMyProperty for this instantiation
MyInstantiatableClass(5) # 5 is the desiredValueOfMyProperty for this instantiation
It seems there’s a discrepancy here; using @property
along with @abstractmethod
doesn’t seem to enforce classes that inherit from your abc to need to define both setter
and getter
. Using this:
@property
@abstractmethod
def myProperty(self):
pass
@myProperty.setter
@abstractmethod
def myProperty(self):
pass
and then providing an implementation only for the getter
in the class works and allows for instantiation:
@property
def myProperty(self):
return self._myProperty
This is due to the fact that only one name (myProperty
) appears in the namespace of the ABC, when you override in the base class, you only need to define this one name.
There’s a way around that enforces it. You can create separate abstract methods and pass them on to property
directly:
class MyAbstractClass(ABC):
@abstractmethod
def getProperty(self):
pass
@abstractmethod
def setProperty(self, val):
pass
myAbstractProperty = property(getProperty, setProperty)
Providing an implementation for this abc now requires both getter
and setter
to have an implementation (both names that have been listed as abstractmethod
s in MyAbstractClass
namespace need to have an implementation):
class MyInstantiatableClass(MyAbstractClass):
def getProperty(self):
return self._Property
def setProperty(self, val):
self._Property = val
myAbstractProperty = property(getProperty, setProperty)
Implementing them is exactly the same as any old property. There’s no difference there.
For example, you can define the abstract getter, setter and deleter in Person
abstract class, override them in Student
class which extends Person
abstract class as shown below. *@abstractmethod
must be the innermost decorator otherwise error occurs:
from abc import ABC, abstractmethod
class Person(ABC):
@property
@abstractmethod # The innermost decorator
def name(self): # Abstract getter
pass
@name.setter
@abstractmethod # The innermost decorator
def name(self, name): # Abstract setter
pass
@name.deleter
@abstractmethod # The innermost decorator
def name(self): # Abstract deleter
pass
class Student(Person):
def __init__(self, name):
self._name = name
@property
def name(self): # Overrides abstract getter
return self._name
@name.setter
def name(self, name): # Overrides abstract setter
self._name = name
@name.deleter
def name(self): # Overrides abstract deleter
del self._name
Then, you can instantiate Student
class and call the getter, setter and deleter as shown below:
obj = Student("John") # Instantiates "Student" class
print(obj.name) # Getter
obj.name = "Tom" # Setter
print(obj.name) # Getter
del obj.name # Deleter
print(hasattr(obj, "name"))
Output:
John
Tom
False
You can see my answer which explains more about abstract property.