Вызов функции по псевдониму в декораторе

#python #function #decorator

#python #функция #декоратор

Вопрос:

Текущий код, который у меня есть, позволяет функции вызывать декоратор оболочки и использует имя функции в своем коде. Тем не менее, я ищу способ присвоить функции «псевдоним» в некотором роде в качестве аргумента. Вот текущий код:

 import os, sys

# Take user input
message = input('type command: ')

# Command wrapper
ALLCOMMANDS = {}
def command(function):
    ALLCOMMANDS[function.__name__] = function
    return function 

# Commands  
@command
def foo():
    print("bar")

@command
def goo():
    print('ber')

# Run appropriate command
if message in ALLCOMMANDS:
    ALLCOMMANDS[message]()
  

Например, я хотел бы иметь возможность вызывать функцию по имени, такому как ‘!foo’, из пользовательского ввода, поэтому, возможно, аргумент будет выглядеть как @command(name='!foo') , я просто не знаю, куда идти дальше, чтобы использовать этот аргумент в декораторе, поскольку у него уже есть аргумент.

Я попытался

 # Command wrapper
ALLCOMMANDS = {}
def command(name):
    ALLCOMMANDS[name] = name
    return name
  

но продолжаю получать ошибки, и я предполагаю, что мне чего-то не хватает

Комментарии:

1. Если вы будете следовать этому, вы сможете передать аргумент name: python-3-patterns-idioms-test.readthedocs.io/en/latest /…

Ответ №1:

Вам следует почитать немного больше о декораторах python. Вы получаете ошибку с:

 def command(name):
    ALLCOMMANDS[name] = name
    return name
  

Из-за return name .

Декораторы — это просто синтаксический сахар. Это:

 @command
def foo():
    print('bar')
  

Эквивалентно:

 def foo():
    print('bar')

foo = command(foo)
  

Из этого вы можете понять, почему работает ваш оригинальный декоратор. В конце вы return function .

Все становится немного сложнее, когда у вас есть декоратор, который принимает аргументы. Было предложено следующее:

 @command('nickname')
def foo():
    print('bar')
  

Выглядит так:

 def foo():
    print('bar')

foo = command('nickname')(foo)
  

Итак, чтобы написать декоратор, который принимает аргументы, декоратору необходимо вернуть функцию, которая принимает функцию для оформления в качестве аргумента:

 def command(nickname):
    def wrapped(f):
        ALLCOMMANDS[nickname] = f
        return f
    return wrapped
  

Также рассмотрите возможность создания ALLCOMMANDS атрибута в вашей команде вместо глобального ( UPPER_SNAKE обычно зарезервирован для констант):

 def command(nickname):
    def wrapped(f):
        command._functions[nickname] = f
        return f
    return wrapped

command._functions = {}
  

Комментарии:

1. Ах, имеет смысл. Ценю подробную справку, и я выполню эти рекомендации