首页 > 解决方案 > 有没有更好的方法来组织 Python (3.6.2) 文件?

问题描述

抽象的。

我有两个 python 文件。第一个读取一些输入(文本),第二个存储一些功能。这里的问题是我用来寻找我需要的功能的方法。现在我使用 If / Elif 方法来比较输入和函数,但是这种方法需要将存储在第二个文件中的所有函数与输入进行比较,我在想“这是不是最好的方法?” .

完整的解释。

我正在尝试构建一个 Telegram 聊天机器人,只是为了练习一些 Python。在做任何事情之前,我画了一张思维导图来知道我想要这个脚本会做什么。由于这个思维导图,我产生了将代码拆分到不同文件中的想法,以便更好地组织所有内容并使调试过程更容易一些。所以,我做到了。我将凭据(用于 api 的)存储在一个文件中,将大型机存储在另一个文件中,将功能存储在另一个文件中。From Credentials import *我使用和将文件导入大型机From Comands import *. 当任何文本到达机器人时,它首先检查它是如何开始的,如果它以“/”开头,那么它将斜杠之后的任何内容存储在一个变量中,并将其作为参数发送到函数文件。它何时开始寻找所需的确切命令并执行它。它有效,但我猜是否有更好的方法来做到这一点。我希望我能很好地解释这个问题,你可以帮助我。这是我正在谈论的代码摘录。

mainframe.py

from Comands import *
from credentials import *

...

if text.startswith("/"):
            comando = text[1:]
            print(comando)
            Comands.search(comando)
elif text in items:
            db.delete_item(text, chat)
            items = db.get_items(chat)
            keyboard = build_keyboard(items)
            send_message("Select an item to delete", chat, keyboard)
else:
            db.add_item(text, chat)
            items = db.get_items(chat)
            message = "\n".join(items)
            send_message(message, chat)
...

Comands.py

from message_dictionary import *
from mainframe import *

def search(comando):
    if comando == "start":
        def start():
            keyboard = build_keyboard(acuerdo)
            send_message(mensaje["start"], chat, keyboard)
    elif comando == "done":
        def done():
            keyboard = build_kerboard(items)
            send_message("Select an item to delete", chat, keyboard)

标签: python

解决方案


首先,我将从 2 条建议开始:

  • 不要在导入中使用星号(很难判断函数在以后声明的位置)
  • 尽量避免循环导入(在mainframe.py中导入Command,在command.py中导入mainframe)

大型机.py

import command

comando_str = 'str_command'

# at this stage we want to call command.str_command(), but we have a string, not a function
if hasattr(command, comando_str):  # let's check if such command exist in `command` module
    comando_function = getattr(command, comando_str)  # now let's get a reference to that function

    # we can now call comando_function()!
    # but maybe you have some parameters to call (like passing in `keyboard`)
    arg_count = comando_function.__code__.co_argcount  # total number of arguments to the function
    # co_varnames has all the variables that function would use, but arguments come firs
    arg_names = comando_function.__code__.co_varnames[:arg_count]  

    if arg_count >= 1 and arg_names[0] == 'keyboard':
         comando_function(keyboard)
    elif arg_count == 0:  # function require no arguments
         comando_function()
    else:
        raise Exception('Function %s could not be called', comando_str)
else:
    raise Exception('Function command.%s is not declared', comando_str)

命令.py

import message_dictionary as md  # no *!

def str_command(keyboard):
    md.send_message(mensaje["start"], chat, keyboard)  # now I know that send_message is in md (message_dictionary)

def start():
    keyboard = build_keyboard(acuerdo)  
    send_message(mensaje["start"], chat, keyboard)  

关于你的comand.py的一些注释:

def search(comando):  # ok
    if comando == "start":  # ok
        # here you define function `start`
        # yet, you have not called `start` function 
        # so, when you exit `search` function, this function is gone!
        def start():
            keyboard = build_keyboard(acuerdo)  # where is acuerdo is declared?
            send_message(mensaje["start"], chat, keyboard)  # where mensaje and chat are declared?
    elif comando == "done":
        # same problem as with `start` function above
        def done():
            keyboard = build_kerboard(items)
            send_message("Select an item to delete", chat, keyboard)

修改 comand.py 以返回可调用函数(以解决评论中的问题):

def search(comando): 
    if comando == "start":
        def start(): 
            keyboard = build_keyboard(acuerdo)  
            send_message(mensaje["start"], chat, keyboard)  
        return start
    elif comando == "done":
        # same problem as with `start` function above
        def done():
            keyboard = build_kerboard(items)
            send_message("Select an item to delete", chat, keyboard)
        return done

修改片段 mainframe.py 以使用返回值:

if text.startswith("/"):
    comando = text[1:]
    print(comando)  # look at the logging as a fancy replacing for print
    call_me = Comands.search(comando)
    if call_me:  # checking that something is returned (not None)
        call_me()  # example of calling it

推荐阅读