Примеры декораторов с аргументами#
В Flask декораторы используются для сопоставления функция с ссылками на сайте:
url_function_map = {}
def register(route):
def decorator(func):
url_function_map[route] = func
return func
return decorator
@register('/')
def func(a,b):
return a+b
@register('/scripts')
def func2(a,b):
return a+b
In [3]: url_function_map
Out[3]: {'/': <function __main__.func>, '/scripts': <function __main__.func2>}
А также для ограничения доступа к определенным ссылкам:
from functools import wraps
class User:
def __init__(self, username, permissions=None):
self.username = username
self.permissions = permissions
def has_permission(self, permission):
return permission in self.permissions
natasha = User('nata', ['admin', 'user'])
oleg = User('oleg', ['user'])
current_user = natasha
class AccessDenied(Exception):
pass
def permission_required(permission):
def decorator(func):
@wraps(func)
def decorated_function(*args, **kwargs):
if not current_user.has_permission(permission):
raise AccessDenied('You shall not pass!')
return func(*args, **kwargs)
return decorated_function
return decorator
@permission_required('admin')
def secret_func():
return 42
In [77]: secret_func()
Out[77]: 42
In [78]: current_user = oleg
In [79]: secret_func()
---------------------------------------------------------------------------
AccessDenied Traceback (most recent call last)
<ipython-input-79-23f2f66c4b3b> in <module>()
----> 1 secret_func()
<ipython-input-75-240afbb2dcfe> in decorated_function(*args, **kwargs)
4 def decorated_function(*args, **kwargs):
5 if not current_user.has_permission(permission):
----> 6 raise AccessDenied('You shall not pass!')
7 return func(*args, **kwargs)
8 return decorated_function
AccessDenied: You shall not pass!
Иногда в зависимости от типа аргумента надо вызываться разные функции:
from netmiko import ConnectHandler
import yaml
from pprint import pprint
def send_show_command(device, show_command):
with ConnectHandler(**device) as ssh:
ssh.enable()
result = ssh.send_command(show_command)
return result
def send_config_commands(device, config_commands):
with ConnectHandler(**device) as ssh:
ssh.enable()
result = ssh.send_config_set(config_commands)
return result
def send_commands(device_list, config=None, show=None):
if show:
return send_show_command(device_list, show)
elif config:
return send_config_commands(device_list, config)
if __name__ == "__main__":
commands = [ 'logging 10.255.255.1',
'logging buffered 20010',
'no logging console' ]
show_command = "sh ip int br"
with open('devices.yaml') as f:
dev_list = yaml.safe_load(f)
send_commands(dev_list, config=commands)
send_commands(dev_list, show=show_command)
В стандартной библиотеке есть интересный декоратор singledispatch:
from netmiko import ConnectHandler
import yaml
from pprint import pprint
from functools import singledispatch
from collections.abc import Iterable, Sequence
@singledispatch
def send_commands(command, device):
print('original func')
raise NotImplementedError('Поддерживается только список или строка')
@send_commands.register(str)
def _(show_command, device):
print('Выполняем show')
with ConnectHandler(**device) as ssh:
ssh.enable()
result = ssh.send_command(show_command)
return result
@send_commands.register(Iterable)
def _(config_commands, device):
print('Выполняем config')
with ConnectHandler(**device) as ssh:
ssh.enable()
result = ssh.send_config_set(config_commands)
return result
if __name__ == "__main__":
commands = ['logging 10.255.255.1',
'logging buffered 20010',
'no logging console' ]
show_command = "sh ip int br"
with open('devices.yaml') as f:
r1 = yaml.safe_load(f)[0]
print(send_commands(tuple(commands), r1))
print(send_commands(show_command, r1))