Abstract attributes in Python
What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?
abstract class Controller {
val path: String
}
A subclass of Controller
is enforced to define "path" by the Scala compiler. A subclass would look like this:
class MyController extends Controller {
override val path = "/home"
}
python oop scala abstract-class
add a comment |
What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?
abstract class Controller {
val path: String
}
A subclass of Controller
is enforced to define "path" by the Scala compiler. A subclass would look like this:
class MyController extends Controller {
override val path = "/home"
}
python oop scala abstract-class
1
What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54
"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38
1
I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30
Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33
Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40
add a comment |
What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?
abstract class Controller {
val path: String
}
A subclass of Controller
is enforced to define "path" by the Scala compiler. A subclass would look like this:
class MyController extends Controller {
override val path = "/home"
}
python oop scala abstract-class
What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?
abstract class Controller {
val path: String
}
A subclass of Controller
is enforced to define "path" by the Scala compiler. A subclass would look like this:
class MyController extends Controller {
override val path = "/home"
}
python oop scala abstract-class
python oop scala abstract-class
asked Apr 29 '10 at 9:47
deamon
36.7k85242369
36.7k85242369
1
What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54
"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38
1
I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30
Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33
Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40
add a comment |
1
What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54
"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38
1
I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30
Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33
Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40
1
1
What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54
What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54
"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38
"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38
1
1
I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30
I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30
Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33
Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33
Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40
Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40
add a comment |
9 Answers
9
active
oldest
votes
Python has a built-in exception for this, though you won't encounter the exception until runtime.
class Base(object):
@property
def path(self):
raise NotImplementedError
class SubClass(Base):
path = 'blah'
7
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
4
I think that raising aNotImplementedError
is more explicit and therefore probably better than leaving it to anAttributeError
.
– blokeley
Apr 29 '10 at 12:48
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
5
Not that this only works ifpath
is set directly on theSubClass
. Given an instancesc = SubClass()
, if you try to setsc.path = 'blah'
or have a method that contains something likeself.path = 'blah'
without definingpath
directly onSubClass
, you will get anAttributeError: can't set attribute
.
– erik
Mar 31 '15 at 16:59
|
show 1 more comment
Python 2.7
There is an @abstractproperty decorator for this:
from abc import ABCMeta, abstractmethod, abstractproperty
class A:
__metaclass__ = ABCMeta
def __init__(self):
# ...
pass
@abstractproperty
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Failure to declare a
or b
in the derived class B
will raise a TypeError
such as:
TypeError
: Can't instantiate abstract classB
with abstract methodsa
Python 3.3+
From the documentation:
Deprecated since version 3.3: It is now possible to use
property
,property.getter()
,property.setter()
andproperty.deleter()
withabstractmethod()
, making this decorator redundant.
The above example essentialy becomes:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass
@property
@abstractmethod
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
add a comment |
You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented
so that if the attribute is not overriden and then used, an error is shown at run time.
The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path
attribute as well.
import abc
class Controller(abc.ABC):
path = NotImplemented # type: str
class MyController(Controller):
path = '/home'
add a comment |
Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html
However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.
5
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
add a comment |
Your base class could implement a __new__
method that check for class attribute:
class Controller(object):
def __new__(cls, *args, **kargs):
if not hasattr(cls,'path'):
raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
return object.__new__(cls,*args,**kargs)
class C1(Controller):
path = 42
class C2(Controller):
pass
c1 = C1()
# ok
c2 = C2()
# NotImplementedError: 'Controller' subclasses should have a 'path' attribute
This way the error raise at instantiation
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
add a comment |
Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).
i.e.
class _Controller(object):
path = '' # There are better ways to declare attributes - see other answers
class MyController(_Controller):
path = '/Home'
1
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
Wouldn't it be better to leave out the path declaration in_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need thepath
field to be defined, there would be no error because there is already a value.
– deamon
Apr 29 '10 at 10:25
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
add a comment |
Python3.6 implementation might looks like this:
In [20]: class X:
...: def __init_subclass__(cls):
...: if not hasattr(cls, 'required'):
...: raise NotImplementedError
In [21]: class Y(X):
...: required =5
...:
In [22]: Y()
Out[22]: <__main__.Y at 0x7f08408c9a20>
add a comment |
class AbstractStuff:
@property
@abc.abstractmethod
def some_property(self):
pass
As of 3.3 abc.abstractproperty
is deprecated, I think.
add a comment |
Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.
from abc import ABC, abstractmethod
class Base(ABC):
@property
@classmethod
@abstractmethod
def CONSTANT(cls):
return NotImplementedError
def print_constant(self):
print(type(self).CONSTANT)
class Derived(Base):
CONSTANT = 42
This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT
instead of just CONSTANT
, since the value is undefined in the base class.
There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.
The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because
- The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.
- The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if
CONSTANT
is not defined. The accepted answer allows the object to be instantiated and only throws an error whenCONSTANT
is accessed, making the enforcement less strict.
This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2736255%2fabstract-attributes-in-python%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
9 Answers
9
active
oldest
votes
9 Answers
9
active
oldest
votes
active
oldest
votes
active
oldest
votes
Python has a built-in exception for this, though you won't encounter the exception until runtime.
class Base(object):
@property
def path(self):
raise NotImplementedError
class SubClass(Base):
path = 'blah'
7
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
4
I think that raising aNotImplementedError
is more explicit and therefore probably better than leaving it to anAttributeError
.
– blokeley
Apr 29 '10 at 12:48
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
5
Not that this only works ifpath
is set directly on theSubClass
. Given an instancesc = SubClass()
, if you try to setsc.path = 'blah'
or have a method that contains something likeself.path = 'blah'
without definingpath
directly onSubClass
, you will get anAttributeError: can't set attribute
.
– erik
Mar 31 '15 at 16:59
|
show 1 more comment
Python has a built-in exception for this, though you won't encounter the exception until runtime.
class Base(object):
@property
def path(self):
raise NotImplementedError
class SubClass(Base):
path = 'blah'
7
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
4
I think that raising aNotImplementedError
is more explicit and therefore probably better than leaving it to anAttributeError
.
– blokeley
Apr 29 '10 at 12:48
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
5
Not that this only works ifpath
is set directly on theSubClass
. Given an instancesc = SubClass()
, if you try to setsc.path = 'blah'
or have a method that contains something likeself.path = 'blah'
without definingpath
directly onSubClass
, you will get anAttributeError: can't set attribute
.
– erik
Mar 31 '15 at 16:59
|
show 1 more comment
Python has a built-in exception for this, though you won't encounter the exception until runtime.
class Base(object):
@property
def path(self):
raise NotImplementedError
class SubClass(Base):
path = 'blah'
Python has a built-in exception for this, though you won't encounter the exception until runtime.
class Base(object):
@property
def path(self):
raise NotImplementedError
class SubClass(Base):
path = 'blah'
answered Apr 29 '10 at 10:11
user297250
7
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
4
I think that raising aNotImplementedError
is more explicit and therefore probably better than leaving it to anAttributeError
.
– blokeley
Apr 29 '10 at 12:48
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
5
Not that this only works ifpath
is set directly on theSubClass
. Given an instancesc = SubClass()
, if you try to setsc.path = 'blah'
or have a method that contains something likeself.path = 'blah'
without definingpath
directly onSubClass
, you will get anAttributeError: can't set attribute
.
– erik
Mar 31 '15 at 16:59
|
show 1 more comment
7
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
4
I think that raising aNotImplementedError
is more explicit and therefore probably better than leaving it to anAttributeError
.
– blokeley
Apr 29 '10 at 12:48
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
5
Not that this only works ifpath
is set directly on theSubClass
. Given an instancesc = SubClass()
, if you try to setsc.path = 'blah'
or have a method that contains something likeself.path = 'blah'
without definingpath
directly onSubClass
, you will get anAttributeError: can't set attribute
.
– erik
Mar 31 '15 at 16:59
7
7
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
– Ben James
Apr 29 '10 at 10:16
4
4
I think that raising a
NotImplementedError
is more explicit and therefore probably better than leaving it to an AttributeError
.– blokeley
Apr 29 '10 at 12:48
I think that raising a
NotImplementedError
is more explicit and therefore probably better than leaving it to an AttributeError
.– blokeley
Apr 29 '10 at 12:48
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
– Bastien Léonard
Apr 29 '10 at 14:23
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
See stackoverflow.com/a/1151275/216229 too.
– Chris Withers
Apr 14 '14 at 10:26
5
5
Not that this only works if
path
is set directly on the SubClass
. Given an instance sc = SubClass()
, if you try to set sc.path = 'blah'
or have a method that contains something like self.path = 'blah'
without defining path
directly on SubClass
, you will get an AttributeError: can't set attribute
.– erik
Mar 31 '15 at 16:59
Not that this only works if
path
is set directly on the SubClass
. Given an instance sc = SubClass()
, if you try to set sc.path = 'blah'
or have a method that contains something like self.path = 'blah'
without defining path
directly on SubClass
, you will get an AttributeError: can't set attribute
.– erik
Mar 31 '15 at 16:59
|
show 1 more comment
Python 2.7
There is an @abstractproperty decorator for this:
from abc import ABCMeta, abstractmethod, abstractproperty
class A:
__metaclass__ = ABCMeta
def __init__(self):
# ...
pass
@abstractproperty
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Failure to declare a
or b
in the derived class B
will raise a TypeError
such as:
TypeError
: Can't instantiate abstract classB
with abstract methodsa
Python 3.3+
From the documentation:
Deprecated since version 3.3: It is now possible to use
property
,property.getter()
,property.setter()
andproperty.deleter()
withabstractmethod()
, making this decorator redundant.
The above example essentialy becomes:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass
@property
@abstractmethod
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
add a comment |
Python 2.7
There is an @abstractproperty decorator for this:
from abc import ABCMeta, abstractmethod, abstractproperty
class A:
__metaclass__ = ABCMeta
def __init__(self):
# ...
pass
@abstractproperty
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Failure to declare a
or b
in the derived class B
will raise a TypeError
such as:
TypeError
: Can't instantiate abstract classB
with abstract methodsa
Python 3.3+
From the documentation:
Deprecated since version 3.3: It is now possible to use
property
,property.getter()
,property.setter()
andproperty.deleter()
withabstractmethod()
, making this decorator redundant.
The above example essentialy becomes:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass
@property
@abstractmethod
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
add a comment |
Python 2.7
There is an @abstractproperty decorator for this:
from abc import ABCMeta, abstractmethod, abstractproperty
class A:
__metaclass__ = ABCMeta
def __init__(self):
# ...
pass
@abstractproperty
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Failure to declare a
or b
in the derived class B
will raise a TypeError
such as:
TypeError
: Can't instantiate abstract classB
with abstract methodsa
Python 3.3+
From the documentation:
Deprecated since version 3.3: It is now possible to use
property
,property.getter()
,property.setter()
andproperty.deleter()
withabstractmethod()
, making this decorator redundant.
The above example essentialy becomes:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass
@property
@abstractmethod
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Python 2.7
There is an @abstractproperty decorator for this:
from abc import ABCMeta, abstractmethod, abstractproperty
class A:
__metaclass__ = ABCMeta
def __init__(self):
# ...
pass
@abstractproperty
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Failure to declare a
or b
in the derived class B
will raise a TypeError
such as:
TypeError
: Can't instantiate abstract classB
with abstract methodsa
Python 3.3+
From the documentation:
Deprecated since version 3.3: It is now possible to use
property
,property.getter()
,property.setter()
andproperty.deleter()
withabstractmethod()
, making this decorator redundant.
The above example essentialy becomes:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass
@property
@abstractmethod
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
edited Jan 27 '17 at 15:59
answered Jan 27 '17 at 15:47
Wtower
10.3k97058
10.3k97058
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
add a comment |
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
My "A" class is a subclass of Exception, and this appears to break the example.
– Chris2048
Nov 13 '18 at 11:11
add a comment |
You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented
so that if the attribute is not overriden and then used, an error is shown at run time.
The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path
attribute as well.
import abc
class Controller(abc.ABC):
path = NotImplemented # type: str
class MyController(Controller):
path = '/home'
add a comment |
You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented
so that if the attribute is not overriden and then used, an error is shown at run time.
The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path
attribute as well.
import abc
class Controller(abc.ABC):
path = NotImplemented # type: str
class MyController(Controller):
path = '/home'
add a comment |
You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented
so that if the attribute is not overriden and then used, an error is shown at run time.
The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path
attribute as well.
import abc
class Controller(abc.ABC):
path = NotImplemented # type: str
class MyController(Controller):
path = '/home'
You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented
so that if the attribute is not overriden and then used, an error is shown at run time.
The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path
attribute as well.
import abc
class Controller(abc.ABC):
path = NotImplemented # type: str
class MyController(Controller):
path = '/home'
answered Aug 3 '16 at 1:16
phoenix
1,52811625
1,52811625
add a comment |
add a comment |
Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html
However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.
5
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
add a comment |
Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html
However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.
5
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
add a comment |
Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html
However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.
Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html
However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.
edited Apr 29 '10 at 10:23
Brendan
11.2k137193
11.2k137193
answered Apr 29 '10 at 10:10
Bastien Léonard
44k176889
44k176889
5
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
add a comment |
5
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
5
5
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
Please elaborate: How does abc module help in this context?
– guettli
Jun 16 '16 at 14:32
add a comment |
Your base class could implement a __new__
method that check for class attribute:
class Controller(object):
def __new__(cls, *args, **kargs):
if not hasattr(cls,'path'):
raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
return object.__new__(cls,*args,**kargs)
class C1(Controller):
path = 42
class C2(Controller):
pass
c1 = C1()
# ok
c2 = C2()
# NotImplementedError: 'Controller' subclasses should have a 'path' attribute
This way the error raise at instantiation
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
add a comment |
Your base class could implement a __new__
method that check for class attribute:
class Controller(object):
def __new__(cls, *args, **kargs):
if not hasattr(cls,'path'):
raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
return object.__new__(cls,*args,**kargs)
class C1(Controller):
path = 42
class C2(Controller):
pass
c1 = C1()
# ok
c2 = C2()
# NotImplementedError: 'Controller' subclasses should have a 'path' attribute
This way the error raise at instantiation
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
add a comment |
Your base class could implement a __new__
method that check for class attribute:
class Controller(object):
def __new__(cls, *args, **kargs):
if not hasattr(cls,'path'):
raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
return object.__new__(cls,*args,**kargs)
class C1(Controller):
path = 42
class C2(Controller):
pass
c1 = C1()
# ok
c2 = C2()
# NotImplementedError: 'Controller' subclasses should have a 'path' attribute
This way the error raise at instantiation
Your base class could implement a __new__
method that check for class attribute:
class Controller(object):
def __new__(cls, *args, **kargs):
if not hasattr(cls,'path'):
raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
return object.__new__(cls,*args,**kargs)
class C1(Controller):
path = 42
class C2(Controller):
pass
c1 = C1()
# ok
c2 = C2()
# NotImplementedError: 'Controller' subclasses should have a 'path' attribute
This way the error raise at instantiation
answered Sep 11 '14 at 11:10
Juh_
6,31432858
6,31432858
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
add a comment |
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
interestingly, this doesn't work if you need to use def __init__(self).
– szeitlin
Oct 6 '15 at 20:30
add a comment |
Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).
i.e.
class _Controller(object):
path = '' # There are better ways to declare attributes - see other answers
class MyController(_Controller):
path = '/Home'
1
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
Wouldn't it be better to leave out the path declaration in_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need thepath
field to be defined, there would be no error because there is already a value.
– deamon
Apr 29 '10 at 10:25
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
add a comment |
Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).
i.e.
class _Controller(object):
path = '' # There are better ways to declare attributes - see other answers
class MyController(_Controller):
path = '/Home'
1
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
Wouldn't it be better to leave out the path declaration in_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need thepath
field to be defined, there would be no error because there is already a value.
– deamon
Apr 29 '10 at 10:25
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
add a comment |
Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).
i.e.
class _Controller(object):
path = '' # There are better ways to declare attributes - see other answers
class MyController(_Controller):
path = '/Home'
Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).
i.e.
class _Controller(object):
path = '' # There are better ways to declare attributes - see other answers
class MyController(_Controller):
path = '/Home'
edited Apr 29 '10 at 13:13
answered Apr 29 '10 at 10:03
Brendan
11.2k137193
11.2k137193
1
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
Wouldn't it be better to leave out the path declaration in_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need thepath
field to be defined, there would be no error because there is already a value.
– deamon
Apr 29 '10 at 10:25
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
add a comment |
1
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
Wouldn't it be better to leave out the path declaration in_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need thepath
field to be defined, there would be no error because there is already a value.
– deamon
Apr 29 '10 at 10:25
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
1
1
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
– Mario F
Apr 29 '10 at 10:08
Wouldn't it be better to leave out the path declaration in
_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path
field to be defined, there would be no error because there is already a value.– deamon
Apr 29 '10 at 10:25
Wouldn't it be better to leave out the path declaration in
_Controller
class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path
field to be defined, there would be no error because there is already a value.– deamon
Apr 29 '10 at 10:25
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
@Mario - yes, Brendan Abel's answer gives a good way to do this
– Brendan
Apr 29 '10 at 13:07
add a comment |
Python3.6 implementation might looks like this:
In [20]: class X:
...: def __init_subclass__(cls):
...: if not hasattr(cls, 'required'):
...: raise NotImplementedError
In [21]: class Y(X):
...: required =5
...:
In [22]: Y()
Out[22]: <__main__.Y at 0x7f08408c9a20>
add a comment |
Python3.6 implementation might looks like this:
In [20]: class X:
...: def __init_subclass__(cls):
...: if not hasattr(cls, 'required'):
...: raise NotImplementedError
In [21]: class Y(X):
...: required =5
...:
In [22]: Y()
Out[22]: <__main__.Y at 0x7f08408c9a20>
add a comment |
Python3.6 implementation might looks like this:
In [20]: class X:
...: def __init_subclass__(cls):
...: if not hasattr(cls, 'required'):
...: raise NotImplementedError
In [21]: class Y(X):
...: required =5
...:
In [22]: Y()
Out[22]: <__main__.Y at 0x7f08408c9a20>
Python3.6 implementation might looks like this:
In [20]: class X:
...: def __init_subclass__(cls):
...: if not hasattr(cls, 'required'):
...: raise NotImplementedError
In [21]: class Y(X):
...: required =5
...:
In [22]: Y()
Out[22]: <__main__.Y at 0x7f08408c9a20>
edited Dec 3 '17 at 4:05
answered Nov 23 '17 at 5:38
Artem Zhukov
538316
538316
add a comment |
add a comment |
class AbstractStuff:
@property
@abc.abstractmethod
def some_property(self):
pass
As of 3.3 abc.abstractproperty
is deprecated, I think.
add a comment |
class AbstractStuff:
@property
@abc.abstractmethod
def some_property(self):
pass
As of 3.3 abc.abstractproperty
is deprecated, I think.
add a comment |
class AbstractStuff:
@property
@abc.abstractmethod
def some_property(self):
pass
As of 3.3 abc.abstractproperty
is deprecated, I think.
class AbstractStuff:
@property
@abc.abstractmethod
def some_property(self):
pass
As of 3.3 abc.abstractproperty
is deprecated, I think.
answered Aug 3 '18 at 4:10
grisaitis
1,09311121
1,09311121
add a comment |
add a comment |
Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.
from abc import ABC, abstractmethod
class Base(ABC):
@property
@classmethod
@abstractmethod
def CONSTANT(cls):
return NotImplementedError
def print_constant(self):
print(type(self).CONSTANT)
class Derived(Base):
CONSTANT = 42
This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT
instead of just CONSTANT
, since the value is undefined in the base class.
There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.
The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because
- The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.
- The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if
CONSTANT
is not defined. The accepted answer allows the object to be instantiated and only throws an error whenCONSTANT
is accessed, making the enforcement less strict.
This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.
add a comment |
Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.
from abc import ABC, abstractmethod
class Base(ABC):
@property
@classmethod
@abstractmethod
def CONSTANT(cls):
return NotImplementedError
def print_constant(self):
print(type(self).CONSTANT)
class Derived(Base):
CONSTANT = 42
This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT
instead of just CONSTANT
, since the value is undefined in the base class.
There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.
The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because
- The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.
- The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if
CONSTANT
is not defined. The accepted answer allows the object to be instantiated and only throws an error whenCONSTANT
is accessed, making the enforcement less strict.
This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.
add a comment |
Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.
from abc import ABC, abstractmethod
class Base(ABC):
@property
@classmethod
@abstractmethod
def CONSTANT(cls):
return NotImplementedError
def print_constant(self):
print(type(self).CONSTANT)
class Derived(Base):
CONSTANT = 42
This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT
instead of just CONSTANT
, since the value is undefined in the base class.
There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.
The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because
- The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.
- The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if
CONSTANT
is not defined. The accepted answer allows the object to be instantiated and only throws an error whenCONSTANT
is accessed, making the enforcement less strict.
This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.
Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.
from abc import ABC, abstractmethod
class Base(ABC):
@property
@classmethod
@abstractmethod
def CONSTANT(cls):
return NotImplementedError
def print_constant(self):
print(type(self).CONSTANT)
class Derived(Base):
CONSTANT = 42
This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT
instead of just CONSTANT
, since the value is undefined in the base class.
There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.
The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because
- The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.
- The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if
CONSTANT
is not defined. The accepted answer allows the object to be instantiated and only throws an error whenCONSTANT
is accessed, making the enforcement less strict.
This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.
answered Nov 21 '18 at 17:26
James
11
11
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2736255%2fabstract-attributes-in-python%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54
"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38
1
I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30
Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33
Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40