Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating dynamic ABC class based on user defined class

I'm writing an plugin framework and I want to be able to write a decorator interface, which will convert user class to ABC class and substitute all methods with abstractmethods. I cannot get it working and I suppose the problem is connected with wrong mro, but I can be wrong.

I basically need to be albe to write:

@interface
class X:
    def test(self):
        pass

x = X() # should fail, because test will be abstract method.

substituting methods with their abstract versions is straightforward (you have to iterate over func's and replace them with abc.abstractmethod(func)), but I've got problem with creating dynamic type, which will be an ABCmeta metaclass.

Right now I've got something like:

from abc import ABCMeta

class Interface(metaclass=ABCMeta):
    pass

def interface(cls):
    newcls = type(cls.__name__, (Interface, cls), {})
    # substitute all methods with abstract ones
    for name, func in inspect.getmembers(newcls, predicate=inspect.isfunction):
        setattr(newcls, name, abstractmethod(func))
    return newcls

but it doesnot work - Ican initialize class X without errors.

With standard usage of ABC in Python, we can write:

class X(metaclass=ABCMeta):
    @abstractmethod
    def test(self):
        pass

x = X() # it will fail

How can I create dynamic type in Python3, which will behave like it will have metaclass ABCmeta and will substitute all functions with abstract ones?

like image 491
Wojciech Danilo Avatar asked Jan 08 '13 15:01

Wojciech Danilo


People also ask

How do you create a class object dynamically in Python?

Python Code can be dynamically imported and classes can be dynamically created at run-time. Classes can be dynamically created using the type() function in Python. The type() function is used to return the type of the object. The above syntax returns the type of object.

What does ABC Abstractmethod do?

@abc. abstractmethod prevents any attempt to instantiate a subclass that doesn't override a particular method in the superclass.

What is ABCMeta?

The abc module defines ABCMeta class which is a metaclass for defining abstract base class. Following example defines Shape class as an abstract base class using ABCMeta. The shape class has area() method decorated by abstractmethod.

What is @abstractmethod in Python?

An abstract method is a method that is declared, but contains no implementation. Abstract classes cannot be instantiated, and require subclasses to provide implementations for the abstract methods.


1 Answers

The trick is not to use setattr to reset each of the attributes, but instead to pass those modified attributes to the type function as a dictionary:

import inspect
from abc import ABCMeta, abstractmethod

class Interface(metaclass=ABCMeta):
    pass

def interface(cls):
    attrs = {n: abstractmethod(f)
             for n, f in inspect.getmembers(cls, predicate=inspect.isfunction)}

    return type(cls.__name__, (Interface, cls), attrs)

@interface
class X(metaclass=ABCMeta):
    def test(self):
        pass

x = X()
# does fail:
# Traceback (most recent call last):
#   File "test.py", line 19, in <module>
#     x = X() # should fail, because test will be abstract method.
# TypeError: Can't instantiate abstract class X with abstract methods test
like image 61
David Robinson Avatar answered Sep 29 '22 08:09

David Robinson