Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Inheritance partial delegation #19

Open
EDEADLINK opened this issue Jul 15, 2020 · 4 comments
Open

Multiple Inheritance partial delegation #19

EDEADLINK opened this issue Jul 15, 2020 · 4 comments
Labels
enhancement New feature or request

Comments

@EDEADLINK
Copy link

First up super cool project. Takes most of the headache out of delegation.

I was wondering if in the case of multiple inheritance you could specify which class to delegate.
Say your class C inherits from A and B but only require that the delegate implements A.
Right now the only way that seems to work is to add all the methods of B to your Class C as abstract methods, or turn of validation completely.

More concretely I would like to do this:

from abc import ABCMeta, abstractmethod
from abc_delegation import delegation_metaclass

class abc_foo(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass

class abc_bar(metaclass=ABCMeta):
    @abstractmethod
    def bar(self):
        pass
    ...
   #Potentially many more

class delegate_foo(abc_foo, abc_bar, 
                   metaclass=delegation_metaclass("_foo")):
    def __init__(self, foo):
        self._foo = foo

class implement_bar(delegate_foo):
    def __init__(self, foo):
        super().__init__(foo)

    def bar(self):
        super().bar()
        return "bar"

class foo:
    def foo(self):
        return "foo"

bar = implement_bar(foo())

Without having to write:

class delegate_foo(abc_foo, abc_bar, 
                    metaclass=delegation_metaclass("_foo")):
    def __init__(self, foo):
        self._foo = foo

    @abstractmethod
    def bar(self):
        pass
   ...
   #Potentially many more

Or turn of validation.

Alternatively making this work would be equally nice

from abc import ABCMeta, abstractmethod
from abc_delegation import delegation_metaclass

class abc_foo(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass

class abc_bar(metaclass=ABCMeta):
    @abstractmethod
    def bar(self):
        pass
    ...
   #Potentially many more

class delegate_foo(abc_foo, metaclass=delegation_metaclass("_foo")):
    def __init__(self, foo):
        self._foo = foo

class implement_bar_delegate_foo(abc_bar, delegate_foo):
    def __init__(self, foo):
        super().__init__(foo)

    def bar(self):
        return "bar"

class foo:
    def foo(self):
        return "foo"

bar = implement_bar_delegate_foo(foo())
bar.bar()
bar.foo()

I don't know how difficult either thing is because metaclasses and inheritance gives me headaches, but it feels like it should be possible.

@monomonedula monomonedula added the enhancement New feature or request label Aug 20, 2020
@monomonedula
Copy link
Owner

OK, I will give it a try

@monomonedula
Copy link
Owner

@EDEADLINK you are probably misusing the library.
What is the purpose of class delegate_foo? If it is meant to be abstract, why do you use delegation metaclass in it?

@EDEADLINK
Copy link
Author

Here is a simplified example of what I ended up doing.

class Named(abc.ABC):
    @abc.abstractmethod
    def __init__(self, name="", **kwargs):
        self._name = name
        super().__init__(**kwargs)

    @property
    def name(self):
        return self._name

class Invertible(abc.ABC):
    @abc.abstractmethod
    def invert(self):
        pass

class abstract_interface(Named, Invertable):
     @abc.abstractmethod
     def some_method(self):
        pass
     def some_other_methods(self):
        pass
     ...

# interface where most of the implementation is delegated
class interface(abstract_interface, metaclass=delegation("_delegate"):
    def __init__(self, impl, **kwargs):
        self._delegate = impl
        super().__init__(**kwargs)

    @abc.abstractmethod
    def invert(self):
        pass

# implementation of interface need only implement invert,
# because some_object implements the rest
class impl(interface):
    def __init__(self, **kwargs):
        super().__init__(library.some_object())

    def invert(self):
        ...
        return self

The goal was to extend a library object.
The idea is to add some methods to the object, while leaving some of the methods to be implemented and delegating others.

@monomonedula
Copy link
Owner

@EDEADLINK You don't need to call super() if your class inherits from an abstract base class which doesn't have init method (as it should, because it is an interface)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants