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
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
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
python - I used `__metaclass__` to set up `abc.ABCMeta` as the metaclass, but unimplemented `@abstractmethod`s still fail to raise an exception. Why? - Stack Overflow
Abstract class methods?
Why does using property and abstractmethod not enforce properties in child?
Python override abstractmethod property setter and getter using decorators only - Stack Overflow
Videos
I have the class inheritance going on like this...
Base
|
Sub
|
---------
| |
TaskA TaskBBase implements some loggers and Sub implements the config and Tasks implements the run methods. I wanted to catch all the exceptions raised by the tasks and handle them and return False.
I was hoping I would decorate the abstractmethod with a custom decorator so that I don't need all the inheriting Tasks to decorate them. But it is not working as expected.
from abc import ABC, abstractmethod
from functools import wraps
def catch_exceptions_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
self = args[0]
self.log_error("Error running the task.", e)
return False
return wrapper
class Base(ABC):
def log_error(self, message, exception):
"""Log error."""
print(f"ERROR: {message} {exception}")
@abstractmethod
def configure(self):
"""Configure."""
pass
class Sub(Base):
def configure(self):
"""Configure."""
print("Configuring.")
@abstractmethod
@catch_exceptions_decorator
def run(self):
"""Run."""
pass
class TaskA(Sub):
def run(self):
"""Run."""
raise KeyError
print("Running.")
return True
task = TaskA()
assert not taskA.run()I was expecting the KeyError to be caught by the catch_exceptions_decorator and return False insted of raising the exception as shown below.
Traceback (most recent call last):
File "/Users/X/Desktop/abc_decorator.py", line 47, in <module>
assert not task.run()
^^^^^^^^^^
File "/Users/X/Desktop/abc_decorator.py", line 43, in run
raise KeyError
KeyErrorWhat am I doing wrong here ?
EDIT: Ended up using a metaclass and here is the final code if that's helpful to anyone.
from abc import ABC, ABCMeta, abstractmethod
from functools import wraps
from operator import call
from textwrap import wrap
class TaskMeta(type):
def __new__(cls, name, bases, attrs):
"""Metaclass for tasks."""
for attr_name, attr_value in attrs.items():
if attr_name == "run" and callable(attr_value):
attrs[attr_name] = cls.catch_exceptions_decorator(attr_value)
return super().__new__(cls, name, bases, attrs)
@staticmethod
def catch_exceptions_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
self = args[0]
self.log_error("Error running the task.", e)
return False
return wrapper
class BaseMeta(ABCMeta, TaskMeta):
pass
class Base(metaclass=BaseMeta):
def log_error(self, message, exception):
"""Log error."""
print(f"ERROR: {message} {exception}")
@abstractmethod
def configure(self):
"""Configure."""
pass
class Sub(Base):
def configure(self):
"""Configure."""
print("Configuring.")
@abstractmethod
def run(self):
"""Run."""
pass
class Task(Sub):
def run(self):
"""Run."""
raise KeyError
print("Running.")
return True
task = Task()
assert not task.run()Prints the error instead of raising exception.
ERROR: Error running the task.
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
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
I would code it as two different methods just like in standard method factory pattern description.
https://www.oodesign.com/factory-method-pattern.html
class Foo(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
@some_decorator
def my_method(self, x):
self.child_method()
class SubFoo(Foo):
def child_method(self, x):
print x
This is, of course, possible. There is very little that can't be done in Python haha! I'll leave whether it's a good idea up to you...
class MyClass:
def myfunc():
raise NotImplemented()
def __getattribute__(self, name):
if name == "myfunc":
func = getattr(type(self), "myfunc")
return mydecorator(func)
return object.__getattribute__(self, name)
(Not tested for syntax yet, but should give you the idea)