2

Suppose I need to implement an abstract Python interface which then will have many derived classes (each named equally but written in different modules), and in base class I heed to have a common method which will use a particular imported derived class' static method.

So my toy modules look like this:

abstract_class.py

 from abc import ABCMeta, abstractmethod

 from derived_class import Derived

 class Abstract:
   __metaclass__ = ABCMeta

   @abstractmethod
   def foo(self):
     pass

   def bar(self):
     Derived.foo()

derived_class.py

from abstract_class import Abstract

class Derived(Abstract):
  @staticmethod
  def foo():
    print 'Good news everyone!'

if __name__ == '__main__':
  derived_object = Derived()
  derived_object.bar()

Then of course when I'm trying to run derived_class.py, I get the Abstract name import error.

How do I properly organize this?

FrauHahnhen
  • 143
  • 2
  • 11
  • 2
    Why don't you make `Abstract.bar` just call `self.foo`? – jonrsharpe Jan 14 '15 at 14:39
  • 1
    I have a feeling you might be in an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). But regardless, you shouldn't use [circular imports](http://stackoverflow.com/questions/744373/circular-or-cyclic-imports-in-python), even though no real danger will come of it. Also - You might want to look at [Python Super and Inheritance](http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods) – Inbar Rose Jan 14 '15 at 14:41
  • @jonrsharpe because it will call Abstract.foo, which doesn't print anything – FrauHahnhen Jan 14 '15 at 14:42
  • Not in `derived_object`, it won't, because then `self` is the `Derived` instance and `foo` is the `@staticmethod`, not the `@abstractmethod`. Try it and see! – jonrsharpe Jan 14 '15 at 14:44
  • @jonrsharpe Just tried it, so `def bar(self): self.foo()`, and if I call bar() from the derived class it does not print anything – FrauHahnhen Jan 14 '15 at 14:49
  • Be aware that, when running your `derived_class.py`, `'main' != '__main__'`. Using `self.foo` in `Abstract` works fine here for me; I see `Good news everyone!` as expected. – jonrsharpe Jan 14 '15 at 14:52
  • @jonrsharpe Yep! It was my stupid mistake with 'main' that bothered, and your solution works just fine, thank you! – FrauHahnhen Jan 14 '15 at 14:55

2 Answers2

2

On the other hand, if you absolutely needed to do this without an object instance, it's possible to do with classmethods rather than staticmethods.

from abc import ABC, abstractmethod

class MyAbstractClass(ABC):

    @staticmethod
    @abstractmethod
    def foo(label: str):
        raise NotImplementedError()


    @classmethod
    def foo_agnostic(cls, label: str):
        """
        NOTE: Here, this method doesn't have a reference to an instance of the class.
        Instead, it only has a reference to the class itself; but that is enough
        to call the abstract static foo() method.
        """
        cls.foo(label)


class MyDerivedClass(MyAbstractClass):

    @staticmethod
    def foo(label: str):
        print(label)


if __name__ == "__main__":
    instance = MyDerivedClass()
    instance.foo("Test 1")                # Outputs "Test 1"
    instance.foo_agnostic("Test 2")       # Outputs "Test 2"
    MyDerivedClass.foo_agnostic("Test 3") # Outputs "Test 3"
Eric McLachlan
  • 3,132
  • 2
  • 25
  • 37
0

... in base class I heed to have a common method which will use a particular imported derived class' static method

If I understand your question correctly, I'd say that this functionality is available out of the box with one small exception: Don't use a static method; just use a regular instance method.

Defining an abstract method in the base class will ensure that derived classes contain an implementation for that method. And, out of the box, the method defined in the derived class will get called when you call derived_object.bar().

Eric McLachlan
  • 3,132
  • 2
  • 25
  • 37