120

I have read python docs about abstract base classes:

From here:

abc.abstractmethod(function) A decorator indicating abstract methods.

Using this decorator requires that the class’s metaclass is ABCMeta or is derived from it. A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.

And here

You can apply the @abstractmethod decorator to methods such as draw() that must be implemented; Python will then raise an exception for classes that don’t define the method. Note that the exception is only raised when you actually try to create an instance of a subclass lacking the method.

I've used this code to test that out:

import abc

class AbstractClass(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def abstractMethod(self):
    return

class ConcreteClass(AbstractClass):
  def __init__(self):
    self.me = "me"

c = ConcreteClass()
c.abstractMethod()

The code goes fine, so I don't get it. If I type c.abstractMethod I get:

<bound method ConcreteClass.abstractMethod of <__main__.ConcreteClass object at 0x7f694da1c3d0>>

What I'm missing here? ConcreteClass must implement the abstract methods, but I get no exception.

2
  • 4
    Which Python? It reports the error just fine for me. Also, you can always raise NotImplementedError instead of using abc. Commented Aug 25, 2011 at 19:58
  • I post a comment on mouad answer, the link from python was set as default to python3. I'll keep in mind raising the exception, as writting portable code with that changes on python seems far away from my python knowledge. Commented Aug 25, 2011 at 20:12

2 Answers 2

126

Are you using python3 to run that code? If yes, you should know that declaring metaclass in python3 have changes you should do it like this instead:

import abc

class AbstractClass(metaclass=abc.ABCMeta):

  @abc.abstractmethod
  def abstractMethod(self):
      return

The full code and the explanation behind the answer is:

import abc

class AbstractClass(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def abstractMethod(self):
        return

class ConcreteClass(AbstractClass):

    def __init__(self):
        self.me = "me"

# Will get a TypeError without the following two lines:
#   def abstractMethod(self):
#       return 0

c = ConcreteClass()
c.abstractMethod()

If abstractMethod is not defined for ConcreteClass, the following exception will be raised when running the above code: TypeError: Can't instantiate abstract class ConcreteClass with abstract methods abstractMethod

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, that seems a huge change between versions (my distro was pointing python to default as python3). How to write that for backward compatibility? I guess this could be another question...
@Sebastian : python3 was designed with less backward compatibility with it's precedent python2 (python.org/dev/peps/pep-3000/#compatibility-and-transition) but to solve backward incompatibilities between the two version you should use 2to3.py script (docs.python.org/library/2to3.html).
nice, I had test it out. I can continue using the __metaclass__ syntax and use that script to convert to python3 syntax. It just did what you stated in the example. Thanks.
Instead of 2to3 you can also use six: python-future.org/compatible_idioms.html#metaclasses
If you want to understand more conceptually. Please refer this video by Raymond Hettinger. youtube.com/watch?v=S_ipdVNSFlo
|
32

Import ABC from abc and make your own abstract class a child of ABC can help make the code look cleaner.

from abc import ABC, abstractmethod

class AbstractClass(ABC):

  @abstractmethod
  def abstractMethod(self):
    return

class ConcreteClass(AbstractClass):
  def __init__(self):
    self.me = "me"

# The following would raise a TypeError complaining 
# abstractMethod is not implemented
c = ConcreteClass()  

Tested with Python 3.6

2 Comments

I have run your solution and it works like expected, giving TypeError: Can't instantiate abstract class ConcreteClass with abstract method abstractMethod. Now, compared to the answer by @mouad there is no usage of metaclass=abc.ABCMeta in the base classes' definition. Is it really the same, do you know? If yes, then I like your solution a little more, because of less text, but maybe this is just a matter of taste.
It's the same. ABC declares it also like so class ABC(metaclass=ABCMeta):

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.