Let's take:
class A:
pass
class A2(A):
#property
def f(self):
return None
class B:
def __init__(el: A)
self._a = el
class B2(B):
def __init__(el: A2)
super().__init__(el)
def m():
self._a.f()
I have now a typing error on the last line when calling self._a.f() saying "cannot access member f for type A" even though it's declared at A2 in B, and it has the member.
What is the correct way to declare this snippet for typing to work?
A has no member f, so trying to access _a.f where _a: A is, correctly, an error. To achieve what you want, you should define f as an unimplemented function on A that its subclasses should implement:
class A:
#property
def f(self):
raise NotImplementedError
or make it an abstract base class with an abstract method:
from abc import ABC, abstractmethod
class A(ABC):
#property
#abstractmethod
def f(self): ...
This will inform the type checker that A and all of its subclasses have a member f, and your code should typecheck correctly.
If you want to narrow the type only for B2._a, this should be enough:
class B2(B):
_a: A2
# rest of class definition
...
An upstream interface was given to me with all of its functions defined as non-abstract when in reality they should be decorated with #abstractmethods. I want to receive an error when I did not implement one of its functions when it's called. To do this, I would create a wrapper class and manually go through each of its defined functions and do something like this:
from abc import ABC, abstractmethod
class Foo(object):
def foo(self):
print("Foo")
class AbstractFoo(Foo, ABC):
#abstractmethod
def foo(self):
return super().foo()
class ConcreteFoo(AbstractFoo):
def foo(self):
print("Concrete Foo")
super().foo()
f = ConcreteFoo()
f.foo()
Which outputs:
Concrete Foo
Foo
I would like some way of just doing this to all functions defined by Foo. Obviously, inherited magic functions like __str__ and __repr__ should be forwarded appropriately.
Does anyone know a nice, pythonic way of doing this?
def validate_base_class_implemntation(cls):
base_cls_funcs = []
for attr in cls.__bases__[0].__dict__:
if callable(getattr(cls, attr)):
base_cls_funcs.append(attr)
cls_funcs = []
for attr in cls.__dict__:
if callable(getattr(cls, attr)):
cls_funcs.append(attr)
missing_funcs = [x for x in base_cls_funcs if x not in cls_funcs]
if len(missing_funcs) > 0:
print("Not implemented functions are: {}".format(','.join(missing_funcs)))
raise Exception("Not implement function exception!")
return cls
class Foo(object):
def foo(self):
print("Foo")
def boo(self):
print("Wow")
#validate_base_class_implemntation
class ConcreteFoo(Foo):
def foo(self):
print("Concrete Foo")
super().foo()
f = ConcreteFoo()
f.foo()
Not sure in 100% if that what you meant.
this decorator checks that the class decorated implements all the base class function(in your case, they are not decorated with abstract). if there is a function that your decorated class does not implement, it raises exception.
You can modify the original class Foo and turn all its methods into abstract methods and then define a blank subclass of Foo with metaclass=ABCMeta in order to handle the checks:
from abc import ABCMeta, abstractmethod
from types import FunctionType
class AbstractFoo(Foo, metaclass=ABCMeta):
pass
names = set()
for k, v in vars(Foo).items():
if k.startswith('__') and k.endswith('__'):
continue
elif isinstance(v, FunctionType):
names.add(k)
v.__isabstractmethod__ = True
AbstractFoo.__abstractmethods__ = frozenset(names)
Side note: This approach relies on dunder attributes being used by abc and as such can break without deprecation.
In Python 3, I have class Animal as an abstract base class, with abstract method give_name(self). Derived classes include Dog and Cat.
The start of the contents of give_name() method can can differ across subclasses. For example, in the Dog subclass, there might be print("bark") while in the Cat subclass, there may be print("meow").
However, I want to make sure that in all derived classes, give_name() ends with return self.__class__.__name__. How can I enforce this constraint (as elegantly as possible)?
Current Code:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def give_name(self):
pass
class Dog(Animal):
def give_name(self):
print("bark")
return self.__class__.__name__
class Cat(Animal):
def give_name(self):
print("meow")
return self.__class__.__name__
You could implement give_name() in the superclass, but delegate the print part to subclasses, e.g.
from abc import ABC, abstractmethod
class Animal(ABC):
def give_name(self):
self.print()
return self.__class__.__name__
#abstractmethod
def print(self):
pass
class Dog(Animal):
def print(self):
print("bark")
class Cat(Animal):
def print(self):
print("meow")
parent.py:
class A(object):
def methodA(self):
print("in methodA")
child.py:
from parent import A
class B(A):
def methodb(self):
print("am in methodb")
Is there anyway to call methodb() in parent.py?
Doing this would only make sense if A is an abstract base class, meaning that A is only meant to be used as a base for other classes, not instantiated directly. If that were the case, you would define methodB on class A, but leave it unimplemented:
class A(object):
def methodA(self):
print("in methodA")
def methodB(self):
raise NotImplementedError("Must override methodB")
from parent import A
class B(A):
def methodB(self):
print("am in methodB")
This isn't strictly necessary. If you don't declare methodB anywhere in A, and instantiate B, you'd still be able to call methodB from the body of methodA, but it's a bad practice; it's not clear where methodA is supposed to come from, or that child classes need to override it.
If you want to be more formal, you can use the Python abc module to declare A as an abstract base class.
from abc import ABC, abstractmethod
class A(ABC):
def methodA(self):
print("in methodA")
#abstractmethod
def methodB(self):
raise NotImplementedError("Must override methodB")
Or if using Python 2.x:
from abc import ABCMeta, abstractmethod
class A(object):
__metaclass__ = ABCMeta
def methodA(self):
print("in methodA")
#abstractmethod
def methodB(self):
raise NotImplementedError("Must override methodB")
Using this will actually prevent you from instantiating A or any class that inherits from A without overriding methodB. For example, if B looked like this:
class B(A):
pass
You'd get an error trying to instantiate it:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class B with abstract methods methodB
The same would happen if you tried instantiating A.
You can do something like this:
class A():
def foo(self):
self.testb()
class B(A):
def testb(self):
print('lol, it works')
b = B()
b.foo()
Which would return this of course:
lol, it works
Note, that in fact there is no call from parent, there is just call of function foo from instance of child class, this instance has inherited foo from parent, i.e. this is impossible:
a=A()
a.foo()
will produce:
AttributeError: A instance has no attribute 'testb'
because
>>> dir(A)
['__doc__', '__module__', 'foo']
>>> dir(B)
['__doc__', '__module__', 'foo', 'testb']
What I've wanted to show that you can create instance of child class, and it will have all methods and parameters from both parent and it's own classes.
There are three approaches/ways to do this ! but I highly recommend to use the approach #3 because composition/decoupling has certain benefits in terms of design pattern. (GOF)
## approach 1 inheritance
class A():
def methodA(self):
print("in methodA")
def call_mehtodB(self):
self.methodb()
class B(A):
def methodb(self):
print("am in methodb")
b=B()
b.call_mehtodB()
## approach 2 using abstract method still class highly coupled
from abc import ABC, abstractmethod
class A(ABC):
def methodA(self):
print("in methodA")
#abstractmethod
def methodb(self):
pass
class B(A):
def methodb(self):
print("am in methodb")
b=B()
b.methodb()
#approach 3 the recommended way ! Composition
class A():
def __init__(self, message):
self.message=message
def methodA(self):
print(self.message)
class B():
def __init__(self,messageB, messageA):
self.message=messageB
self.a=A(messageA)
def methodb(self):
print(self.message)
def methodA(self):
print(self.a.message)
b=B("am in methodb", "am in methodA")
b.methodb()
b.methodA()
You could use the function anywhere so long as it was attached to an object, which it appears to be from your sample. If you have a B object, then you can use its methodb() function from absolutely anywhere.
parent.py:
class A(object):
def methoda(self):
print("in methoda")
def aFoo(obj):
obj.methodb()
child.py
from parent import A
class B(A):
def methodb(self):
print("am in methodb")
You can see how this works after you import:
>>> from parent import aFoo
>>> from child import B
>>> obj = B()
>>> aFoo(obj)
am in methodb
Granted, you will not be able to create a new B object from inside parent.py, but you will still be able to use its methods if it's passed in to a function in parent.py somehow.
If the both class in same .py file then you can directly call child class method from parents class.
It gave me warning but it run well.
class A(object):
def methodA(self):
print("in methodA")
Self.methodb()
class B(A):
def methodb(self):
print("am in methodb")
You can certainly do this -
parent.py
class A(object):
def __init__(self,obj):
self.obj_B = obj
def test(self):
self.obj_B.methodb()
child.py
from parent import A
class B(A):
def __init__(self,id):
self.id = id
super().__init__(self)
def methodb(self):
print("in method b with id:",self.id)
Now if you want to call it from class B object
b1 = B(1)
b1.test()
>>> in method b with id: 1
Or if you want to call it from class A object
b2 = B(2)
a = A(b2)
a.test()
>>> in method b with id: 2
You can even make new objects in super class by invoking class dict objects of the object passed to super class from child class.
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!