Вызов функции по псевдониму в декораторе - PullRequest
0 голосов
/ 15 марта 2019

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

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 Ответ

2 голосов
/ 15 марта 2019

Вы должны прочитать немного больше о 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.

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

@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 = {}
...