3.5. Class Decorator with Functions

3.5.1. Syntax

  • decorator is a decorator name

  • MyClass is a class name

Syntax:
@Decorator
def my_function(*args, **kwargs):
    pass
Is equivalent to:
my_function = Decorator(my_function)

3.5.2. Definition

class Decorator:
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        return self._func(*args, **kwargs)

3.5.3. Usage

class Decorator:
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        return self._func(*args, **kwargs)


@Decorator
def echo(name):
    print(name)


echo('Mark Watney')
# Mark Watney

3.5.4. Examples

3.5.4.1. Login Check

class User:
    def __init__(self):
        self.is_authenticated = False

    def login(self, username, password):
        self.is_authenticated = True


class LoginCheck:
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        if user.is_authenticated:
            return self._func(*args, **kwargs)
        else:
            print('Permission Denied')


@LoginCheck
def edit_profile():
    print('Editing profile...')


user = User()

edit_profile()
# Permission Denied

user.login('admin', 'MyVoiceIsMyPassword')

edit_profile()
# Editing profile...

3.5.4.2. Dict Cache

class Cache(dict):
    def __init__(self, func):
        self._func = func

    def __call__(self, *args):
        return self[args]

    def __missing__(self, key):
        self[key] = self._func(*key)
        return self[key]


@Cache
def my_function(a, b):
    return a * b


my_function(2, 4)           # 8         # Computed
my_function('hi', 3)        # 'hihihi'  # Computed
my_function('ha', 3)        # 'hahaha'  # Computed

my_function('ha', 3)        # 'hahaha'  # Fetched from cache
my_function('hi', 3)        # 'hihihi'  # Fetched from cache
my_function(2, 4)           # 8         # Fetched from cache
my_function(4, 2)           # 8         # Computed


my_function
# {
#   (2, 4): 8,
#   ('hi ', 3): 'hihihi',
#   ('ha', 3): 'hahaha',
#   (4, 2): 8,
# }

3.5.5. Assignments

3.5.5.1. Simple decorator

English
  1. Create function print_file(filename: str) -> str which prints file content (filename given as an argument)

  2. Create decorator to_absolute_path

  3. Decorator converts to absolute path (path + filename), if filename given as an argument is a relative path

Polish
  1. Stwórz funkcję print_file(filename: str) -> str która wyświetla zawartość pliku (nazwa pliku podana jako argument)

  2. Stwórz dekorator to_absolute_path

  3. Dekorator zamienia ścieżkę na bezwzględną (path + filename), jeżeli nazwa pliku podana jako argument jest względna

Hint
  • __file__

  • os.path.dirname()

  • os.path.basename()

  • os.path.join()