Skip to content

Instantly share code, notes, and snippets.

@Armen-Jean-Andreasian
Last active March 14, 2024 12:35
Show Gist options
  • Save Armen-Jean-Andreasian/f9ac8c70f35e2adef81ac3cca6268728 to your computer and use it in GitHub Desktop.
Save Armen-Jean-Andreasian/f9ac8c70f35e2adef81ac3cca6268728 to your computer and use it in GitHub Desktop.
Welcome file

Metaclasses

The metaclasses are responsible for the instantiation process.

  • By default, the metaclass of any Python class is type. same as class MyClass(metaclass=type)

Whenever, you do my_class = MyClass():

  1. MyClass.__call__() method is being called. This happens because in Python, calling an instance as a function, calls the __call__() method of the class.
  2. Inside the MyClass.__call__() method of the class:
    1. The MyClass.__new__() method is being called to create a new instance.
    2. MyClass.__new__() is a stub method calling the parent's .__new__(), in this case type.__new__()).
    3. It looks like this:
      def __new__(cls, *args, **kwargs):
      	return super().__new__(cls, *args, **kwargs)
      
  3. Then the type.__new__() method, which is the constructor, constructs the instance and returns it to interpreter.
  4. Python VM creates a __dict__ attribute if __slots__ is not present.
  5. MyClass.__init__() method receives the instace and initializes it.

Using them you canInside of them can be defined the custom class creation

  • In Python metaclsses:
    1. Control the class creation process. Using a metaclass you can redefine the __new__ method
    class MyMeta(type):
    def new(cls, name, bases, dct): print("Creating class:", name) return super().new(cls, name, bases, dct) class MyClass(metaclass=MyMeta):
    pass
     - ```python  
 class MyMeta(type):  
def __new__(cls, name, bases, dct): # Add a custom method to the class setattr(cls, 'custom_method', lambda self: print("Custom method called"))         class MyClass(metaclass=MyMeta):  
pass  

Сниглтон: Это для того чтобы подставить существующий экземпляр под __init__

__init__ в любом случае будет выполняться

No need for parent-singleton to provide *args, **kwargs to __init__

There're two ways of doing Singleton

  • Through metaclass: for one or more classes
  • In-place implementation : for one class

Singleton as metaclass

For a metaclass singleton instances = set() is recommended.

  • As the metaclass will be reused in multiple classes the set instances will hold all of them inside.

A bit about metaclasses:

class Singleton(type):  
 instances = set()     def __new__(cls, *args, **kwargs):  
 instance = super().__new__(cls, args, kwargs)         if instance not in cls.instances:  
 cls.instances.add(instance)         return instance  
  
class MyClass(metaclass=Singleton):  
 ...  

Singleton as parent

class Singleton:
	_instance = None
	def __new__(cls, *args, **kwargs): 
		if cls._instance is None: 
			cls._instance = super().__new__(cls) 
		return cls._instance  
class MyClass(Singleton):  
 ...  

Child class that's singleton

class ParentClass:  
 pass  
class ChildClass(ParentClass, metaclass=Singleton):  
 pass ...  

Standalone Singleton class

	class SingletonClass:  
		 _instance = None 
		 _initialized = False  
		
		def __new__(cls, *args, **kwargs): 
			if not cls._instance: 
				cls._instance = super().__new__(cls) 
			return cls._instance  

		def __init__(self, value): 
			if not self._initialized: 
				self.value = value 
				self._initialized = True  

Additional part

  • Using __call__ magic method
    • __call__ method is being executed upon class instantiation.
    • m = MyClass() here __call__ is being executed
      • So, the sequence is: __call__ => __new__ => __init__
        Consequently Singleton can be created using __call__ as well:
    class Singleton(type):
    _instances = set() def call(cls, *args, **kwargs):
    instance = super().call(*args, **kwargs) if cls not in cls._instances:
    cls._instances.add(instance) return instance
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment