0

I am trying to learn metaclasses in python, from my research i found a example like follow.

i have a Base and Derived classes like follow

class Base():
    def foo(self):
        return self.bar() 

class Derived(Base):
    def foo2(self):
        return "i am foo2"

now, when i want to make sure that whoever extending Base class, must need to implement bar() method, so i created the meta class to hook the constuction of derived class,so now Base class looks like follow with BaseMeta meta class.

class BaseMeta(type):
  def __new__(cls, name, bases, body):
    if not "bar" in body:
      raise TypeError("bar not implemented")
    return super().__new__(cls, name, bases, body)

class Base(metaclass=BaseMeta):
   def foo(self):
        return self.bar() 

The problem is when i get looks into body it returns 2 records for Base and Derived class, like follow.

 {'__module__': '__main__', '__qualname__': 'Base', 'foo': <function 
 Base.foo at 0x7ffbaae436a8>}
 {'__module__': '__main__', '__qualname__': 'Derived', 'bar': <function 
 Derived.bar at 0x7ffbaae437b8>}

my code in __new__ breaks since Base not have bar, but i want to check only in the Derived class so i rewrite my metaclass like follow.

def __new__(cls, name, bases, body):
    if name !="Base" and not "bar" in body:
      raise TypeError("bar not implemented")
    return super().__new__(cls, name, bases, body)

I am checking name != Base in my __new__ method.

Is that the right way to do it or we can use some other best way?

7
  • fyi, what you are talking about is not a metaclass but a baseclass. Metaclass has a very specific meaning and refers to something completely different. Commented Jul 18, 2018 at 7:34
  • We can also use metaclass to achieve this right? Commented Jul 18, 2018 at 7:40
  • Theoretically, I am sure. But metaclasses are intended to achieve something different called class alteration. Sorry that I am so vague, but I don't understand their use very well myself and just trust the top-voted answer from the question I linked which says that 99% of the time you need class alteration, you are better off using [monkey patching or decorators]. But 98% of the time, you don't need class alteration at all and go about my day ignoring that metaclasses exist. Commented Jul 18, 2018 at 7:58
  • 1
    That looks interesting, I'll try to have a look and get back if it turns out that I misunderstood your question. Commented Jul 18, 2018 at 8:28
  • 1
    Note that you could implement __init_subclass__ to verify assertions about a child without defining a metaclass. Commented Jul 20, 2018 at 23:18

1 Answer 1

2

You can use the abc module in the stdlib, which has tools for doing exactly this. https://docs.python.org/3/library/abc.html

import abc

class Base(abc.ABC):

    @abc.abstractmethod
    def bar(self):
         pass

class Derived(Base):
    pass

# This will raise an error because foo is not implemented
# >>> Derived() 
# TypeError: Can't instantiate abstract class Derived with abstract methods bar

Another strategy would be to have a bar method on your Base class that raises a NotImplementedError. The main difference is that no error is raised until you actually call something that requires bar. e.g.

class Base():
    def foo(self):
        return self.bar() 

    def bar(self):
        raise NotImplementedError
Sign up to request clarification or add additional context in comments.

2 Comments

I want to enforce constraint for derived class without implementing bar method in my Base class, and i am confused about example 1, i think it enforce foo right? but i need to enforce bar()
To enforce bar for a derived class, declare an abstract method on your base class for that method. Edited response to reflect this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.