如何向输入字典添加别名?

How to add aliases to an input dictionary?

最近我开始了一个项目。我的目标是拥有一个脚本,一旦启动,如果通过电子邮件发送指令,就可以控制主机上的操作。 (我想要这个,这样我就可以在出门在外时开始需要很长时间才能完成的任务)

我开始编程,不久之后我就可以发送电子邮件、接收电子邮件并分析其内容并对电子邮件中的内容采取行动。

我是通过使用输入字典来做到这一点的,它看起来像这样:

contents_of_the_email = "!screen\n!wait 5\n!hotkey alt tab"


def wait(sec):
    print(f"I did nothing for {sec} seconds!")


def no_operation():
    print("Nothing")


def screenshot():
    print("I took an image of the screen and send it to your email adress!")


def hotkey(*args):
    print(f"I pressed the keys {', '.join(args)} at the same time")


FUNCTIONS = {
    '':no_operation,
    '!screen': screenshot,
    '!hotkey': hotkey,
    '!wait': wait
}


def call_command(command):
    function, *args = command.split(' ')
    FUNCTIONS[function](*args)


for line in contents_of_the_email.split("\n"):
    call_command(line)

我总共有大约 25 个函数,每个函数都有自己的响应。我用简单的打印语句替换了命令的实际代码,因为不需要它们来理解或复制我的问题。

然后我想为命令添加别名,例如,您可以键入“!ss”而不是“!screen”。 我确实使用字典中的另一行实现了这一点:

FUNCTIONS = {
    '':no_operation,
    '!screen': screenshot,
    '!ss':screenshot,
    '!hotkey': hotkey,
    '!wait': wait
}

但我不喜欢这样。如果我为我计划添加的每个别名都这样做,它将填满整个字典,这会使我的代码非常混乱。 有什么方法可以单独为命令定义别名,并且仍然保持字典的简洁明了?我希望在单独的 aliases.txt 文件中有这样的东西:

screen: "!screen", "!ss","!screenshot","!image"
wait: "!wait","!pause","!sleep","!w"
hotkey: "!hk","!tk"

如果这在 python 中可行,我将不胜感激!

您可以使用 for 循环很容易地从可调用项字典和快捷方式列表转到可调用项快捷方式字典。

# long dict of shortcuts to callables
goal = {'A': 0, 'B': 0, 'C': 1}

# condensed dict, not in .txt, but storable in python
condensed = {0: ['A', 'B'], 1: ['C']}

# expand the condensed dict
commands = {}
for func, shortcuts in condensed.items():
    for shortcut in shortcuts:
        commands[shortcut] = func

# or with a comprehension
commands = {s: f for f, ls in condensed.items() for s in ls}

# verify expanded and goal are the same
assert commands == goal

您可以使用以下解决方案:

import json
contents_of_the_email = "!screen\n!wait 5\n!hotkey alt tab"


def wait(sec):
    print(f"I did nothing for {sec} seconds!")


def no_operation():
    print("Nothing")


def screenshot():
    print("I took an image of the screen and send it to your email address!")


def hotkey(*args):
    print(f"I pressed the keys {', '.join(args)} at the same time")


# FUNCTIONS DICT FROM JSON
with open("aliases.json") as json_file:
    aliases_json = json.load(json_file)

FUNCTIONS = {}
for func_name, aliases in aliases_json.items():
    FUNCTIONS.update({alias: globals()[func_name] for alias in aliases})


def call_command(command):
    function, *args = command.split(' ')
    FUNCTIONS[function](*args)


for line in contents_of_the_email.split("\n"):
    call_command(line)

aliases.json:

{
  "screenshot": ["!screen", "!ss","!screenshot","!image"],
  "wait": ["!wait","!pause","!sleep","!w"],
  "hotkey": ["!hk","!tk", "!hotkey"]
}

这是你要找的吗?

您可以通过首先创建一个将每个别名映射到其中一个函数的字典来做您想做的事。这将需要解析 aliases.txt 文件 — 幸运的是,这并不 困难。它使用 ast.literal_eval() function to convert the quoted literal strings in the file into Python strings, as well as the built-in globals() 函数来查找相关函数,给定它们在文件中的名称。如果有任何对未定义函数的引用,将引发 KeyError

注意 我将您的 aliases.txt 文件更改为以下内容(这更有意义):

screenshot: "!screen", "!ss","!screen","!image"
wait: "!wait","!pause","!sleep","!w"
hotkey: "!hk","!tk"

下面是一个可运行的示例:

from ast import literal_eval

ALIASES_FILENAME = 'aliases.txt'

# The functions.
def wait(sec):
    print(f"I did nothing for {sec} seconds!")

def no_operation():
    print("Nothing")

def screenshot():
    print("I took an image of the screen and send it to your email adress!")

def hotkey(*args):
    print(f"I pressed the keys {', '.join(args)} at the same time")

# Create dictionary of aliases from text file.
aliases = {}
with open(ALIASES_FILENAME) as file:
    namespace = globals()
    for line in file:
        cmd, other_names = line.rstrip().split(':')
        aliases[cmd] = namespace[cmd]  # Allows use of actual function name.
        for alias in map(literal_eval, other_names.replace(',', ' ').split()):
            aliases[alias] = namespace[cmd]

def call_command(command):
    function, *args = command.split(' ')
    if function in aliases:
        aliases[function](*args)

# Sample message.
contents_of_the_email = """\
!screen
!wait 5
!hk alt tab
"""

# Execute commands in email.
for line in contents_of_the_email.split("\n"):
    call_command(line)

输出:

I took an image of the screen and send it to your email adress!
I did nothing for 5 seconds!
I pressed the keys alt, tab at the same time