Skip to content

Instantly share code, notes, and snippets.

@diegoquintanav
Last active March 25, 2020 09:26
Show Gist options
  • Save diegoquintanav/4c9b5eccfacaaa7548f60b9d2875c38f to your computer and use it in GitHub Desktop.
Save diegoquintanav/4c9b5eccfacaaa7548f60b9d2875c38f to your computer and use it in GitHub Desktop.
metaclasses

Some examples of metaclasses definitions

Raw, implicit definition

class MetaClass(type): 

    def get_foo(self):
        return self._foo
    
    def set_foo(self, value):
        self._foo = value
    
    foo = property(get_foo)

    @property
    def bar(self):
        return self._bar

class MyClass(object, metaclass=MetaClass):
    # not defining raises an AttributeError
    
    # _foo = 'abc' 
    # _bar = 'def'

    @classmethod
    def print_meta(cls):
        print(cls.foo)
        print(cls.bar)

someclass = MyClass()

someclass.print_meta()

Raw, explicit definition

# hello_metaclass.py
# A simple metaclass
# This metaclass adds a 'hello' method to classes that use the metaclass
# meaning, those classes get a 'hello' method with no extra effort
# the metaclass takes care of the code generation for us
class HelloMeta(type):  
    # A hello method

    @property
    def _bye(self):
        raise NotImplementedError('duh')

    def _hello(cls):
        print("greetings from %s, a HelloMeta type class" % (type(cls())))

    # Call the metaclass
    def __call__(self, *args, **kwargs):
        # create the new class as normal
        cls = type.__call__(self, *args)

        setattr(cls, "bye", self._bye)

        # define a new hello method for each of these classes
        setattr(cls, "hello", self._hello)

        # return the class
        return cls

# Try out the metaclass
class TryHello(object, metaclass=HelloMeta):  

    HelloMeta._bye = 'abc'

    def greet(self):
        print(self.bye)
        self.hello()


# Create an instance of the metaclass. It should automatically have a hello method
# even though one is not defined manually in the class
# in other words, it is added for us by the metaclass
greeter = TryHello()  
greeter.greet()  

Using abc

import abc

class HelloMeta(abc.ABC):  
# A hello method

    @property
    @abc.abstractmethod
    def bye(self):
        raise NotImplementedError

    @classmethod
    def hello(cls):
        print("greetings from %s, a HelloMeta type class" % (type(cls())))

    # Call the metaclass
    def __call__(self, *args, **kwargs):
        # create the new class as normal
        cls = type.__call__(self, *args)

        # define a new hello method for each of these classes
        setattr(cls, "hello", self.hello)

        # return the class
        return cls

class Hello(HelloMeta):

    bye = "I'm an abstract property" # if not defined, raises a TypeError

    def greet(self):
        self.hello()


greeter = Hello()  
greeter.hello()  
greeter.greet()  
print(greeter.bye)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment