Call child functions from parent property with same abstract functions - python

I need the settings in the parent to contain the functions from the child. (Every child of this parent will use that settings, but the way the functions are defined will change)
Is this possible? Currently it appears to read in the undefined functions from the parent class (and thus breaks)
class Mine(object):
__metaclass__ = ABCMeta
#abstractmethod
def _get_stuff(self):
raise NotImplementedError()
#abstractmethod
def _set_stuff(self, value):
raise NotImplementedError()
settings = property(_get_stuff, _set_stuff)
def do_stuff_with_settings(self):
return settings
class Child(Mine):
def _get_stuff(self):
return {"a": 2}
def _set_stuff(self):
pass
def do_stuff(self):
self.a = do_stuff_with_settings.a

From the docs
a metaclass derived from ABCMeta cannot be instantiated unless all of
its abstract methods and properties are overridden.
I changed how you created the base class to class Mine(metaclass=ABCMeta):
and received the error
Traceback (most recent call last):
File "g.py", line 24, in <module>
Child().settings
TypeError: Can't instantiate abstract class Child with abstract methods settings
So that makes the problem more explicit. To fix the problem, just have the child classes create their own settings property. Now they are bound to the concrete methods instead of the abstract methods.
from abc import ABCMeta,abstractmethod
class Mine(object):
__metaclass__ = ABCMeta
#abstractmethod
def _get_stuff(self):
raise NotImplementedError()
#abstractmethod
def _set_stuff(self, value):
raise NotImplementedError()
settings = property(_get_stuff, _set_stuff)
def do_stuff_with_settings(self):
return settings
class Child(Mine):
def _get_stuff(self):
return 1
def _set_stuff(self):
pass
settings = property(_get_stuff, _set_stuff)
Child().settings
UPDATE
This isn't just an ABC issue. You have this problem with any subclass that overrides a property method. Here, I try to override a getter but find that I still get the parent's view:
>>> class Foo:
... def __init__(self, val):
... self._val = val
... def _get_val(self):
... return self._val
... def _set_val(self, val):
... self._val = val
... val = property(_get_val, _set_val)
...
>>> class Bar(Foo):
... def _get_val(self):
... return self._val + 2
...
>>> print('want 3, got', Bar(1).val)
want 3, got 1
UPDATE 2
The problem is that property binds the class method when it is defined. If you don't mind implementing intermediate functions, then you can let them resolve the target method at runtime after the child has overriden them. Here, _get_stuff calls _get_stuff_impl at runtime and you get the child version.
from abc import ABCMeta,abstractmethod
class Mine(metaclass=ABCMeta):
def _get_stuff(self):
return self._get_stuff_impl()
#abstractmethod
def _get_stuff_impl(self):
raise NotImplementedError()
def _set_stuff(self, value):
return self._set_stuff_impl(value)
#abstractmethod
def _set_stuff_impl(self, value):
raise NotImplementedError()
settings = property(_get_stuff, _set_stuff)
def do_stuff_with_settings(self):
return settings
class Child(Mine):
def _get_stuff_impl(self):
return 1
def _set_stuff_impl(self):
pass
# settings = property(_get_stuff, _set_stuff)
Child().settings

Related

How to declare instance variables in abstract class?

class ILinkedListElem:
#property
def value(self):
raise NotImplementedError
#property
def next(self):
raise NotImplementedError
class ListElem(ILinkedListElem):
def __init__(self, value, next_node=None):
self.value = value
self.next = next_node
I wanna something like this. This abstract variables definition works for class vars, but not for instance
I want to all instances of ILinkedListElem subclass must has "value" and "next" attributes
If you want to force/require all instances of any subclass of ILinkedListElem to have the attributes "value" and "nxt", the following standard implementation with abstractmethod seems to do what you're after:
from abc import ABC, abstractmethod
class ILinkedListElem (ABC):
#property
#abstractmethod
def value(self):
raise NotImplementedError
#property
#abstractmethod
def nxt(self):
raise NotImplementedError
This is the abstract class, from which we create a compliant subclass:
class ListElem_good (ILinkedListElem):
def __init__(self, value, next_node=None):
self._value = value
self._nxt = next_node
#property
def value(self):
return self._value
#property
def nxt(self):
return self._nxt
We create an instance of this compliant subclass and test it:
x = ListElem_good('foo', 'bar')
print (x.value)
print (x.nxt)
#result:
# foo
# bar
If we create a non-compliant subclass that omits an implementation of nxt, like so:
class ListElem_bad (ILinkedListElem):
def __init__(self, value):
self._value = value
#property
def value(self):
return self._value
when we try to create an instance of this non-compliant subclass:
y = ListElem_bad('foo')
print (y.value)
it fails:
y = ListElem_bad('foo')
TypeError: Can't instantiate abstract class ListElem_bad with abstract methods nxt
This relies on essentially the same solution offered here, which you suggested in a comment-exchange does not meet your requirements. But when applied to your specific use-case above, it appears to precisely address the issue you've raised - or have I misunderstood?

Python abstract setters and getters

I want to write abstract class that will force inheriting classes to implement all methods AND properties in my abstract class.
Additionally I want to use of setters and getters for my abstract property to make my code uncluttered and looking nicely
However, current implementation:
import abc
class Component(metaclass=abc.ABCMeta):
#property
#abc.abstractmethod
def status(self):
pass
#property
#status.setter
#abc.abstractmethod
def status(self, value):
pass
does enforce inheriting class to implement getter for my abstract property getter, but does not enforce creating a property setter (what is exactly what I want)
How can I achieve this behavior without loosing all benefits from application of further mentioned method (aka writing new methods and executing them in my abstract class setter) ?
from abc import ABCMeta, abstractmethod
class Base(object):
__metaclass__ = ABCMeta
def __init__(self, val):
self._foo = val
#abstractmethod
def _doStuff(self, signals):
print ('Base does stuff')
#abstractmethod
def _get_foo(self):
return self._foo
#abstractmethod
def _set_foo(self, val):
self._foo = val + 'r'
foo = property(_get_foo, _set_foo)
class floor_1(Base):
__metaclass__ = ABCMeta
def __init__(self, val):
self._foo = val
super(floor_1, self).__init__(val)
def _doStuff(self, signals):
print ('floor_1 does stuff')
def _get_foo(self):
return self._foo
def _set_foo(self, val):
#self._foo = val + 'r'
super()._set_foo(val + 'r')
foo = property(_get_foo, _set_foo)
class floor_2(floor_1):
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, val):
self._foo = val + 'r'
#super()._set_foo(val + 'r')
b1 = floor_1('bar')
# b1 = floor_2('bar')
print(b1.foo)
b1.foo = 'bar'
print(b1.foo)
The problem is that neither the getter nor the setter is a method of your abstract class; they are attributes of the property, which is a (non-callable) class attribute. Consider this equivalent definition:
def status_getter(self):
pass
def status_setter(self, value):
pass
class Component(metaclass=abc.ABCMeta):
# status = property(...)
# status.__isabstractmethod__ = True
status = abstractmethod(property(status_getter, status_setter))
Inheriting a property is quite different from inheriting a method. You are basically replacing the property, because your class itself does not have a reference to either the getter or the setter. Despite the name, abstractmethod does not actually make the property a method; it really does nothing more than add an attribute to whatever it is applied to and return the original value.
So, to ensure that a subclass provides a read/write property, what are you to do? Skip the decorator syntax, define the getter and setter as explicit abstract methods, then define the property explicitly in terms of those private methods.
class Component(metaclass=abc.ABCMeta):
#abstractmethod
def _get_status(self):
pass
#abstractmethod
def _set_status(self, v):
pass
status = property(lambda self: self._get_status(), lambda self, v: self._set_status(self, v))
Or, you can make use of __init_subclass__ (which postdates abc; its purpose is to allow class initialization that is otherwise only possible via a metaclass).
class Component:
def __init_subclass(cls, **kwargs):
super().__init_subclass__(**kwargs)
try:
p = cls.status
except AttributeError:
raise ValueError("Class does not define 'status' attribute")
if not isinstance(p, property):
raise ValueError("'status' is not a property")
if p.fget is None:
raise ValueError("'status' has no getter")
if p.fset is None:
raise ValueError("'status' has no setter")
This is actually an improvement over abc, in my opinion. If a subclass fails to define a read/write status property, an exception will be raised when the class is defined, not just when you attempt to instantiate the class.

Delegation design pattern with abstract methods in python

I have the following classes implementing a "Delegation Design Pattern" with an additional DelegatorParent class:
class DelegatorParent():
def __init__(self):
self.a = 'whatever'
class ConcreteDelegatee():
def myMethod(self):
return 'myMethod'
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
def __getattr__(self, attrname):
return getattr(self.delegatee, attrname)
a = Delegator()
result = a.myMethod()
Everything looks fine.
Now I would like to put an abstract method in DelegatorParent, to ensure that "myMethod" is always defined.
from abc import ABCMeta, abstractmethod
class DelegatorParent():
__metaclass__ = ABCMeta
#abstractmethod
def myMethod(self):
pass
def __init__(self):
self.a = 'whatever'
class ConcreteDelegatee():
def myMethod(self):
return 'myMethod'
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
def __getattr__(self, attrname):
return getattr(self.delegatee, attrname)
# This method seems unnecessary, but if I erase it an exception is
# raised because the abstract method's restriction is violated
def myMethod(self):
return self.delegatee.myMethod()
a = Delegator()
result = a.myMethod()
Can you help me find an "elegant" way to remove "myMethod" from "Delegator"... Intuition tells me that it is somehow redundant (considering that a custom getattr method is defined).
And more importantly, notice that with this implementation, if I forget to define myMethod in ConcreteDelegatee the program compiles, but it may crash in runtime if I call Delegator.myMethod(), which is exactly what I wanted to avoid by using abstract methods in DelegatorParent.
Obviously a simple solution would be to move #abstractmethod to the Delegator class, but I want to avoid doing that because in my program DelegatorParent is a very important class (and Delegator is just an auxiliary class).
You can decide to automatically implement abstract methods delegared to ConcreteDelegatee.
For each abstract method, check if it's name exist in the ConcreteDelegatee class and implement this method as a delegate to this class method.
from abc import ABCMeta, abstractmethod
class DelegatorParent(object):
__metaclass__ = ABCMeta
def __init__(self):
self.a = 'whatever'
#abstractmethod
def myMethod(self):
pass
class Delegatee(object):
pass
class ConcreteDelegatee(Delegatee):
def myMethod(self):
return 'myMethod'
def myMethod2(self):
return 'myMethod2'
class Delegator(DelegatorParent):
def __new__(cls, *args, **kwargs):
implemented = set()
for name in cls.__abstractmethods__:
if hasattr(ConcreteDelegatee, name):
def delegated(this, *a, **kw):
meth = getattr(this.delegatee, name)
return meth(*a, **kw)
setattr(cls, name, delegated)
implemented.add(name)
cls.__abstractmethods__ = frozenset(cls.__abstractmethods__ - implemented)
obj = super(Delegator, cls).__new__(cls, *args, **kwargs)
obj.delegatee = ConcreteDelegatee()
return obj
def __getattr__(self, attrname):
# Called only for attributes not defined by this class (or its bases).
# Retrieve attribute from current behavior delegate class instance.
return getattr(self.delegatee, attrname)
# All abstract methods are delegared to ConcreteDelegatee
a = Delegator()
print(a.myMethod()) # correctly prints 'myMethod'
print(a.myMethod2()) #correctly prints 'myMethod2'
This solves the main problem (prevent ConcreteDelegatee from forgetting to define myMethod). Other abstract methods are still checked if you forgot to implement them.
The __new__ method is in charge of the delegation, that frees your __init__ to do it.
Since you use ABCMeta, you must defined the abstract methods. One could remove your method from the __abstractmethods__ set, but it is a frozenset. Anyway, it involves listing all abstract methods.
So, instead of playing with __getattr__, you can use a simple descriptor.
For instance:
class Delegated(object):
def __init__(self, attrname=None):
self.attrname = attrname
def __get__(self, instance, owner):
if instance is None:
return self
delegatee = instance.delegatee
return getattr(delegatee, self.attrname)
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
myMethod = Delegated('myMethod')
An advantage here: the developer has the explicit information that "myMethod" is delegated.
If you try:
a = Delegator()
result = a.myMethod()
It works! But if you forget to implement myMethod in Delegator class, you have the classic error:
Traceback (most recent call last):
File "script.py", line 40, in <module>
a = Delegator()
TypeError: Can't instantiate abstract class Delegator with abstract methods myMethod
Edit
This implementation can be generalized as follow:
class DelegatorParent():
__metaclass__ = ABCMeta
#abstractmethod
def myMethod1(self):
pass
#abstractmethod
def myMethod2(self):
pass
def __init__(self):
self.a = 'whatever'
class ConcreteDelegatee1():
def myMethod1(self):
return 'myMethod1'
class ConcreteDelegatee2():
def myMethod2(self):
return 'myMethod2'
class DelegatedTo(object):
def __init__(self, attrname):
self.delegatee_name, self.attrname = attrname.split('.')
def __get__(self, instance, owner):
if instance is None:
return self
delegatee = getattr(instance, self.delegatee_name)
return getattr(delegatee, self.attrname)
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee1 = ConcreteDelegatee1()
self.delegatee2 = ConcreteDelegatee2()
DelegatorParent.__init__(self)
myMethod1 = DelegatedTo('delegatee1.myMethod1')
myMethod2 = DelegatedTo('delegatee2.myMethod2')
a = Delegator()
result = a.myMethod2()
Here, we can specify the delegatee name and delegatee method.
Here is my current solution. It solves the main problem (prevent ConcreteDelegatee from forgetting to define myMethod), but I'm still not convinced because I still need to define myMethod inside Delegator, which seems redundant
from abc import ABCMeta, abstractmethod
class DelegatorParent(object):
__metaclass__ = ABCMeta
def __init__(self):
self.a = 'whatever'
#abstractmethod
def myMethod(self):
pass
class Delegatee(object):
def checkExistence(self, attrname):
if not callable(getattr(self, attrname, None)):
error_msg = "Can't instantiate " + str(self.__class__.__name__) + " without abstract method " + attrname
raise NotImplementedError(error_msg)
class ConcreteDelegatee(Delegatee):
def myMethod(self):
return 'myMethod'
def myMethod2(self):
return 'myMethod2'
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
for method in DelegatorParent.__abstractmethods__:
self.delegatee.checkExistence(method)
def myMethod(self, *args, **kw):
return self.delegatee.myMethod(*args, **kw)
def __getattr__(self, attrname):
# Called only for attributes not defined by this class (or its bases).
# Retrieve attribute from current behavior delegate class instance.
return getattr(self.delegatee, attrname)
# if I forget to implement myMethod inside ConcreteDelegatee,
# the following line will correctly raise an exception saying
# that 'myMethod' is missing inside 'ConcreteDelegatee'.
a = Delegator()
print a.myMethod() # correctly prints 'myMethod'
print a.myMethod2() #correctly prints 'myMethod2'

Python base class that makes abstract methods definition mandatory at instantiation

I have a base class that define a couple of empty methods. I would like to enforce/make mandatory the definition of these methods in the subclass AND make it crash at init in case they are not overriden.
Ex:
class Shape:
def __init__(self, name):
self.name = name
def number_of_edges(self):
pass # method HAS TO be overloaded in subclass
class Triangle(Shape):
def __init__(self, name):
super(Triangle, self).__init__()
def number_of_edges(self):
return 3
It seems like the Python way is to raise a NotImplementedError:
def number_of_edges(self):
raise(NotImplementedError)
But it could be beneficial to crash early and detect the lack of implementation during the class instantiation. Why is this not the default, and can it be done?
Use the abc module to create an Abstract Base Class.
import abc
class Shape(object):
__metaclass__ = abc.ABCMeta
def __init__(self, name):
self.name = name
#abc.abstractmethod
def number_of_edges(self):
pass
Any method decorated with the #abc.abstractmethod decorator will trigger a TypeError exception:
>>> import abc
>>> class Shape(object):
... __metaclass__ = abc.ABCMeta
... def __init__(self, name):
... self.name = name
... #abc.abstractmethod
... def number_of_edges(self):
... pass
...
>>>
>>> class Triangle(Shape):
... pass
...
>>> Triangle('t3')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Triangle with abstract methods number_of_edges
>>> class Triangle(Shape):
... def number_of_edges(self):
... return 3
...
>>> Triangle('t3')
<__main__.Triangle object at 0x105f3b8d0>
You can be use Abstact Base Class;
import abc
class Shape:
__metaclass__ = abc.ABCMeta
def __init__(self, name):
self.name = name
#abc.abstractmethod
def number_of_edges(self):
pass # method HAS TO be overloaded in subclass
Now, if Triangle class doesn't override the number_of_edges method, it will raise exception.

Is it possible to make abstract classes?

How can I make a class or method abstract in Python?
I tried redefining __new__() like so:
class F:
def __new__(cls):
raise Exception("Unable to create an instance of abstract class %s" %cls)
But now, if I create a class G that inherits from F like so:
class G(F):
pass
Then, I can't instantiate G either, since it calls its super class's __new__ method.
Is there a better way to define an abstract class?
Use the abc module to create abstract classes. Use the abstractmethod decorator to declare a method abstract, and declare a class abstract using one of three ways, depending upon your Python version.
In Python 3.4 and above, you can inherit from ABC. In earlier versions of Python, you need to specify your class's metaclass as ABCMeta. Specifying the metaclass has different syntax in Python 3 and Python 2. The three possibilities are shown below:
# Python 3.4+
from abc import ABC, abstractmethod
class Abstract(ABC):
#abstractmethod
def foo(self):
pass
# Python 3.0+
from abc import ABCMeta, abstractmethod
class Abstract(metaclass=ABCMeta):
#abstractmethod
def foo(self):
pass
# Python 2
from abc import ABCMeta, abstractmethod
class Abstract:
__metaclass__ = ABCMeta
#abstractmethod
def foo(self):
pass
Whichever way you use, you won't be able to instantiate an abstract class that has abstract methods, but will be able to instantiate a subclass that provides concrete definitions of those methods:
>>> Abstract()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Abstract with abstract methods foo
>>> class StillAbstract(Abstract):
... pass
...
>>> StillAbstract()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class StillAbstract with abstract methods foo
>>> class Concrete(Abstract):
... def foo(self):
... print('Hello, World')
...
>>> Concrete()
<__main__.Concrete object at 0x7fc935d28898>
The old-school (pre-PEP 3119) way to do this is just to raise NotImplementedError in the abstract class when an abstract method is called.
class Abstract(object):
def foo(self):
raise NotImplementedError('subclasses must override foo()!')
class Derived(Abstract):
def foo(self):
print 'Hooray!'
>>> d = Derived()
>>> d.foo()
Hooray!
>>> a = Abstract()
>>> a.foo()
Traceback (most recent call last): [...]
This doesn't have the same nice properties as using the abc module does. You can still instantiate the abstract base class itself, and you won't find your mistake until you call the abstract method at runtime.
But if you're dealing with a small set of simple classes, maybe with just a few abstract methods, this approach is a little easier than trying to wade through the abc documentation.
Here's a very easy way without having to deal with the ABC module.
In the __init__ method of the class that you want to be an abstract class, you can check the "type" of self. If the type of self is the base class, then the caller is trying to instantiate the base class, so raise an exception. Here's a simple example:
class Base():
def __init__(self):
if type(self) is Base:
raise Exception('Base is an abstract class and cannot be instantiated directly')
# Any initialization code
print('In the __init__ method of the Base class')
class Sub(Base):
def __init__(self):
print('In the __init__ method of the Sub class before calling __init__ of the Base class')
super().__init__()
print('In the __init__ method of the Sub class after calling __init__ of the Base class')
subObj = Sub()
baseObj = Base()
When run, it produces:
In the __init__ method of the Sub class before calling __init__ of the Base class
In the __init__ method of the Base class
In the __init__ method of the Sub class after calling __init__ of the Base class
Traceback (most recent call last):
File "/Users/irvkalb/Desktop/Demo files/Abstract.py", line 16, in <module>
baseObj = Base()
File "/Users/irvkalb/Desktop/Demo files/Abstract.py", line 4, in __init__
raise Exception('Base is an abstract class and cannot be instantiated directly')
Exception: Base is an abstract class and cannot be instantiated directly
This shows that you can instantiate a subclass that inherits from a base class, but you cannot instantiate the base class directly.
Most Previous answers were correct but here is the answer and example for Python 3.7. Yes, you can create an abstract class and method. Just as a reminder sometimes a class should define a method which logically belongs to a class, but that class cannot specify how to implement the method. For example, in the below Parents and Babies classes they both eat but the implementation will be different for each because babies and parents eat a different kind of food and the number of times they eat is different. So, eat method subclasses overrides AbstractClass.eat.
from abc import ABC, abstractmethod
class AbstractClass(ABC):
def __init__(self, value):
self.value = value
super().__init__()
#abstractmethod
def eat(self):
pass
class Parents(AbstractClass):
def eat(self):
return "eat solid food "+ str(self.value) + " times each day"
class Babies(AbstractClass):
def eat(self):
return "Milk only "+ str(self.value) + " times or more each day"
food = 3
mom = Parents(food)
print("moms ----------")
print(mom.eat())
infant = Babies(food)
print("infants ----------")
print(infant.eat())
OUTPUT:
moms ----------
eat solid food 3 times each day
infants ----------
Milk only 3 times or more each day
As explained in the other answers, yes you can use abstract classes in Python using the abc module. Below I give an actual example using abstract #classmethod, #property and #abstractmethod (using Python 3.6+). For me it is usually easier to start off with examples I can easily copy&paste; I hope this answer is also useful for others.
Let's first create a base class called Base:
from abc import ABC, abstractmethod
class Base(ABC):
#classmethod
#abstractmethod
def from_dict(cls, d):
pass
#property
#abstractmethod
def prop1(self):
pass
#property
#abstractmethod
def prop2(self):
pass
#prop2.setter
#abstractmethod
def prop2(self, val):
pass
#abstractmethod
def do_stuff(self):
pass
Our Base class will always have a from_dict classmethod, a property prop1 (which is read-only) and a property prop2 (which can also be set) as well as a function called do_stuff. Whatever class is now built based on Base will have to implement all of these four methods/properties. Please note that for a method to be abstract, two decorators are required - classmethod and abstract property.
Now we could create a class A like this:
class A(Base):
def __init__(self, name, val1, val2):
self.name = name
self.__val1 = val1
self._val2 = val2
#classmethod
def from_dict(cls, d):
name = d['name']
val1 = d['val1']
val2 = d['val2']
return cls(name, val1, val2)
#property
def prop1(self):
return self.__val1
#property
def prop2(self):
return self._val2
#prop2.setter
def prop2(self, value):
self._val2 = value
def do_stuff(self):
print('juhu!')
def i_am_not_abstract(self):
print('I can be customized')
All required methods/properties are implemented and we can - of course - also add additional functions that are not part of Base (here: i_am_not_abstract).
Now we can do:
a1 = A('dummy', 10, 'stuff')
a2 = A.from_dict({'name': 'from_d', 'val1': 20, 'val2': 'stuff'})
a1.prop1
# prints 10
a1.prop2
# prints 'stuff'
As desired, we cannot set prop1:
a.prop1 = 100
will return
AttributeError: can't set attribute
Also our from_dict method works fine:
a2.prop1
# prints 20
If we now defined a second class B like this:
class B(Base):
def __init__(self, name):
self.name = name
#property
def prop1(self):
return self.name
and tried to instantiate an object like this:
b = B('iwillfail')
we will get an error
TypeError: Can't instantiate abstract class B with abstract methods
do_stuff, from_dict, prop2
listing all the things defined in Base which we did not implement in B.
This one will be working in python 3
from abc import ABCMeta, abstractmethod
class Abstract(metaclass=ABCMeta):
#abstractmethod
def foo(self):
pass
Abstract()
>>> TypeError: Can not instantiate abstract class Abstract with abstract methods foo
also this works and is simple:
class A_abstract(object):
def __init__(self):
# quite simple, old-school way.
if self.__class__.__name__ == "A_abstract":
raise NotImplementedError("You can't instantiate this abstract class. Derive it, please.")
class B(A_abstract):
pass
b = B()
# here an exception is raised:
a = A_abstract()
You can also harness the __new__ method to your advantage. You just forgot something.
The __new__ method always returns the new object so you must return its superclass' new method. Do as follows.
class F:
def __new__(cls):
if cls is F:
raise TypeError("Cannot create an instance of abstract class '{}'".format(cls.__name__))
return super().__new__(cls)
When using the new method, you have to return the object, not the None keyword. That's all you missed.
I find the accepted answer, and all the others strange, since they pass self to an abstract class. An abstract class is not instantiated so can't have a self.
So try this, it works.
from abc import ABCMeta, abstractmethod
class Abstract(metaclass=ABCMeta):
#staticmethod
#abstractmethod
def foo():
"""An abstract method. No need to write pass"""
class Derived(Abstract):
def foo(self):
print('Hooray!')
FOO = Derived()
FOO.foo()
from abc import ABCMeta, abstractmethod
#Abstract class and abstract method declaration
class Jungle(metaclass=ABCMeta):
#constructor with default values
def __init__(self, name="Unknown"):
self.visitorName = name
def welcomeMessage(self):
print("Hello %s , Welcome to the Jungle" % self.visitorName)
# abstract method is compulsory to defined in child-class
#abstractmethod
def scarySound(self):
pass
Late to answer here, but to answer the other question "How to make abstract methods" which points here, I offer the following.
# decorators.py
def abstract(f):
def _decorator(*_):
raise NotImplementedError(f"Method '{f.__name__}' is abstract")
return _decorator
# yourclass.py
class Vehicle:
def add_energy():
print("Energy added!")
#abstract
def get_make(): ...
#abstract
def get_model(): ...
The class base Vehicle class can still be instantiated for unit testing (unlike with ABC), and the Pythonic raising of an exception is present. Oh yes, you also get the method name that is abstract in the exception with this method for convenience.
You can create an abstract class by extending ABC which stands for "Abstract Base Classes" and can create the abstract method with #abstractmethod in the abstract class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
And, to use an abstract class, it should be extended by a child class and the child class should override the abstract method of the abstract class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
class Cat(Animal): # Extends "Animal" abstract class
def sound(self): # Overrides "sound()" abstract method
print("Meow!!")
obj = Cat()
obj.sound()
Output:
Meow!!
And, an abstract method can have code rather than pass and can be called by a child class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!") # Here
class Cat(Animal):
def sound(self):
super().sound() # Here
obj = Cat()
obj.sound()
Output:
Wow!!
And, an abstract class can have the variables and non-abstract methods which can be called by a child class and non-abstract methods don't need to be overridden by a child class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
def __init__(self): # Here
self.name = "John" # Here
x = "Hello" # Here
def test1(self): # Here
print("Test1")
#classmethod # Here
def test2(cls):
print("Test2")
#staticmethod # Here
def test3():
print("Test3")
class Cat(Animal):
def sound(self):
print(self.name) # Here
print(super().x) # Here
super().test1() # Here
super().test2() # Here
super().test3() # Here
obj = Cat()
obj.sound()
Output:
John
Hello
Test1
Test2
Test3
And, you can define an abstract class and static methods and an abstract getter, setter and deleter in an abstract class as shown below. *#abstractmethod must be the innermost decorator otherwise error occurs and you can see my answer which explains more about an abstract getter, setter and deleter:
from abc import ABC, abstractmethod
class Person(ABC):
#classmethod
#abstractmethod # The innermost decorator
def test1(cls):
pass
#staticmethod
#abstractmethod # The innermost decorator
def test2():
pass
#property
#abstractmethod # The innermost decorator
def name(self):
pass
#name.setter
#abstractmethod # The innermost decorator
def name(self, name):
pass
#name.deleter
#abstractmethod # The innermost decorator
def name(self):
pass
Then, you need to override them in a child class as shown below:
class Student(Person):
def __init__(self, name):
self._name = name
#classmethod
def test1(cls): # Overrides abstract class method
print("Test1")
#staticmethod
def test2(): # Overrides abstract static method
print("Test2")
#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 the child class and call them as shown below:
obj = Student("John") # Instantiates "Student" class
obj.test1() # Class method
obj.test2() # Static method
print(obj.name) # Getter
obj.name = "Tom" # Setter
print(obj.name) # Getter
del obj.name # Deleter
print(hasattr(obj, "name"))
Output:
Test1
Test2
John
Tom
False
And, if you try to instantiate an abstract class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
obj = Animal()
The error below occurs:
TypeError: Can't instantiate abstract class Animal with abstract methods sound
And, if you don't override the abstract method of an abstract class in a child class and you instantiate the child class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
class Cat(Animal):
pass # Doesn't override "sound()" abstract method
obj = Cat() # Here
The error below occurs:
TypeError: Can't instantiate abstract class Cat with abstract methods sound
And, if you define an abstract method in the non-abstract class which doesn't extend ABC, the abstract method is a normal instance method so there are no errors even if the non-abstract class is instantiated and even if a child class doesn't override the abstract method of the non-abstract class as shown below:
from abc import ABC, abstractmethod
class Animal: # Doesn't extend "ABC"
#abstractmethod # Here
def sound(self):
print("Wow!!")
class Cat(Animal):
pass # Doesn't override "sound()" abstract method
obj1 = Animal() # Here
obj1.sound()
obj2 = Cat() # Here
obj2.sound()
Output:
Wow!!
Wow!!
In addition, you can replace Cat class extending Animal class below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
# ↓↓↓ Here ↓↓↓
class Cat(Animal):
def sound(self):
print("Meow!!")
# ↑↑↑ Here ↑↑↑
print(issubclass(Cat, Animal))
With this code having register() below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
pass
# ↓↓↓ Here ↓↓↓
class Cat:
def sound(self):
print("Meow!!")
Animal.register(Cat)
# ↑↑↑ Here ↑↑↑
print(issubclass(Cat, Animal))
Then, both of the code above outputs the same result below showing Cat class is the subclass of Animal class:
True
In your code snippet, you could also resolve this by providing an implementation for the __new__ method in the subclass, likewise:
def G(F):
def __new__(cls):
# do something here
But this is a hack and I advise you against it, unless you know what you are doing. For nearly all cases I advise you to use the abc module, that others before me have suggested.
Also when you create a new (base) class, make it subclass object, like this: class MyBaseClass(object):. I don't know if it is that much significant anymore, but it helps retain style consistency on your code
Just a quick addition to #TimGilbert's old-school answer...you can make your abstract base class's init() method throw an exception and that would prevent it from being instantiated, no?
>>> class Abstract(object):
... def __init__(self):
... raise NotImplementedError("You can't instantiate this class!")
...
>>> a = Abstract()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
NotImplementedError: You can't instantiate this class!

Categories

Resources