4.4. Decorator Function with Cls

4.4.1. Rationale

  • mydecorator is a decorator name

  • MyClass is a class name

Syntax:

>>> @mydecorator  
... class MyClass:
...     ...

Is equivalent to:

>>> MyClass = mydecorator(MyClass)  

4.4.2. Syntax

  • mydecorator is a decorator name

  • MyClass is a class name

>>> def decorator(cls):
...     class Wrapper(cls):
...         def __new__(cls, *args, **kwargs):
...             ...
...     return Wrapper
>>>
>>>
>>> def decorator(cls):
...     def wrapper(*args, **kwargs):
...         instance = cls.__new__(cls, *args, **kwargs)
...         return instance
...     return wrapper
>>>
>>>
>>> @decorator
... class MyClass:
...     ...
>>>
>>>
>>> my = MyClass()

4.4.3. Example

>>> def run(cls):
...     def wrapper(*args, **kwargs):
...         instance = cls.__new__(cls, *args, **kwargs)
...         return instance
...     return wrapper
>>>
>>>
>>> @run
... class Astronaut:
...     def hello(self, name):
...         return f'My name... {name}'
>>>
>>>
>>> astro = Astronaut()
>>> astro.hello('José Jiménez')
'My name... José Jiménez'

4.4.4. Use Case - Logger

>>> import logging
>>>
>>>
>>> def logger(cls):
...     class Wrapper(cls):
...         logger = logging.getLogger(cls.__name__)
...     return Wrapper
>>>
>>>
>>> @logger
... class Astronaut:
...     pass
>>>
>>>
>>> print(Astronaut.logger)
<Logger Astronaut (WARNING)>

4.4.5. Use Case - Since

>>> from datetime import datetime
>>>
>>>
>>> def since(cls):
...     class Wrapper(cls):
...         _instance_created = datetime.now()
...     return Wrapper
>>>
>>>
>>> @since
... class Astronaut:
...     pass
>>>
>>>
>>> print(Astronaut._instance_created)  #   
datetime.datetime(1969, 7, 21, 2, 56, 15)

4.4.6. Use Case - Singleton Func

>>> def singleton(cls):
...     def wrapper(*args, **kwargs):
...         if not hasattr(cls, '_instance'):
...             instance = object.__new__(cls, *args, **kwargs)
...             setattr(cls, '_instance', instance)
...         return getattr(cls, '_instance')
...     return wrapper
>>>
>>>
>>> @singleton
... class DatabaseConnection:
...     def connect(self):
...         print(f'Connecting...')
>>>
>>>
>>> a = DatabaseConnection()  # Will create instance
>>> a.connect()  
Connecting...
>>>
>>> b = DatabaseConnection()  # Will reuse instance
>>> b.connect()  
Connecting...

4.4.7. Use Case - Singleton Cls

>>> def singleton(cls):
...     class Wrapper(cls):
...         def __new__(cls, *args, **kwargs):
...             if not hasattr(cls, '_instance'):
...                 instance = object.__new__(cls, *args, **kwargs)
...                 setattr(cls, '_instance', instance)
...             return getattr(cls, '_instance')
...     return Wrapper
>>>
>>>
>>> @singleton
... class DatabaseConnection:
...     def connect(self):
...         print(f'Connecting...')
>>>
>>>
>>> a = DatabaseConnection()  # Will create instance
>>> a.connect()  
Connecting...
>>>
>>> b = DatabaseConnection()  # Will reuse instance
>>> b.connect()  
Connecting...

4.4.8. Assignments