简体   繁体   English

有没有更好的方法来组织Python(3.6.2)文件?

[英]Is there a better way to organize a Python (3.6.2) files?

Abstract. 抽象。

I have two python files. 我有两个python文件。 The first one reads some inputs (texts) and the second one stores some functions. 第一个读取一些输入(文本),第二个读取一些函数。 The problem here is the method I'm using to look for the function that I need. 这里的问题是我用来寻找我需要的功能的方法。 Now I'm using a If / Elif method to compare the input and the functions but this method needs to compare all the functions stored in the second file with the input and I was thinking if "this is the best way to do it?" 现在我使用If / Elif方法来比较输入和函数,但是这个方法需要比较存储在第二个文件中的所有函数和输入,我在想“这是最好的方法吗?” .

Full explanation. 完整的解释。

I'm trying to build a Telegram chat bot, just to practice some Python. 我正在尝试构建一个Telegram聊天机器人,只是为了练习一些Python。 Before anything I drew a mental map to know what I want this scripts will do. 在我做任何事情之前,我画了一张心理地图,知道我希望这个脚本会做什么。 Because of that mental map, I came with the idea of spliting the code in different files in order organize everything better and to do the debugging process a little bit easier. 由于这个心理地图,我想到了将代码分割到不同文件中的想法,以便更好地组织所有内容并使调试过程更容易一些。 So, I did that. 所以,我做到了。 I store the credentials (for the api's) in one file, the mainframe in other file and the functions in other file. 我将凭证(用于api)存储在一个文件中,将主机存储在其他文件中,将函数存储在其他文件中。 I import in the files into the mainframe with From Credentials import * and From Comands import * . 我使用From Credentials import *From Comands import *将文件导入大型机。 When any text come to the bot it first checks how it starts, if it starts with "/" then it stores whatever comes after the slash in a variable and send it as a parameter to the functions file. 当任何文本进入机器人时,它首先检查它是如何开始的,如果它以“/”开头,那么它将存储在变量中的斜杠之后的任何内容并将其作为参数发送到函数文件。 When is there it starts to look for the exact command required and execute it. 什么时候它开始寻找所需的确切命令并执行它。 And it works but I guessing if there is a better way to do it. 它有效,但我猜测是否有更好的方法来做到这一点。 I hope I explained well the problem and you can help me. 我希望我能很好地解释这个问题,你可以帮助我。 Here's the extract of code that I'm talking. 这是我正在谈论的代码摘录。

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)

First, I'll start with 2 recommendations: 首先,我将从2条建议开始:

  • Don't use stars in imports (it is hard to tell where functions are declared later) 不要在导入中使用星号(以后很难分辨函数的位置)
  • Try to avoid cycle imports (import Command in mainframe.py and import mainframe in command.py) 尽量避免循环导入(在mainframe.py中导入命令并在command.py中导入主机)

mainframe.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)

command.py command.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)  

some notes about your comand.py: 关于你的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)

modified comand.py to return callable function (to address questions in comments): 修改了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

modified fragment mainframe.py to use returned values: 修改了片段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

Here it is. 这里是。

mainframe.py (it is actually called Prubeas.py) mainframe.py(实际上称为Prubeas.py)

#PYTHON 3.6.2
#LGsus

import json
import requests
import time
import urllib
from dbhelper import DBHelper
from credentials import *
from message_dictionary import *
import Comands

db = DBHelper()

#DECLARAR ID DEL BOT Y URL DE TELEGRAM
URL = "https://api.telegram.org/bot{}/".format(telegram_token)

#CONSULTAR ESTADO
def get_url(url):
    response = requests.get(url)
    content = response.content.decode("utf8")
    return content

#CAMBIAR DE JSON A PYTHON (PARSE)
def get_json_from_url(url):
    content = get_url(url)
    js = json.loads(content)
    return js

#SOLICITAR LISTA DE MENSAJES
def get_updates(offset=None):
    url = URL + "getUpdates?timeout=100"
    if offset:
        url += "&offset={}".format(offset)
    js = get_json_from_url(url)
    return js

#DETERMINAR MENSAJES NO  LEÍDOS
def get_last_update_id(updates):
    update_ids = []
    for update in updates["result"]:
        update_ids.append(int(update["update_id"]))
    return max(update_ids)

#RESPONDER A TODOS LOS NO LEIDOS
def handle_updates(updates):
    for update in updates["result"]:
        text = update["message"]["text"]
        chat = update["message"]["chat"]["id"]
        items = db.get_items(chat)
        if text.startswith("/"):
            comando = text[1:]
            print(comando)
            Comands.search(comando)
            #fin = text.find(" ")
            #print(fin)

            #if text == "/done":
            #    keyboard = build_keyboard(items)
            #    send_message("select an item to delete", chat, keyboard)
            #elif text == "/start":
            #    keyboard = build_keyboard(acuerdo)
            #    send_message(mensajes["start"], chat, keyboard)
            #elif text.startswith("/"):
            #    continue
        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)

#SOLICITAR ULTIMO MENSAJE Y ID DEL CHAT
def get_last_chat_id_and_text(updates):
    global Texto
    global full_last
    num_updates = len(updates["result"])
    lista = updates["result"]
    data = json.dumps(lista)
    last_update = num_updates - 1
    full_last = updates["result"][last_update]
    Texto = "text" in full_last["message"]
    if Texto == True:
        text = updates["result"][last_update]["message"]["text"]
    else:
        text = "Entrada invalida"
    chat_id = updates["result"][last_update]["message"]["chat"]["id"]
    return (text, chat_id)

#CREAR EL TECLADO
def build_keyboard(items):
    keyboard = [[item] for item in items]
    reply_markup = {"keyboard":keyboard, "one_time_keyboard":True}
    return json.dumps(reply_markup)

#ENVIAR MENSAJE
def send_message(text, chat_id, reply_markup=None):
    text = text.encode(encoding='utf-8')
    text = urllib.parse.quote_plus(text)
    url = URL + "sendMessage?text={}&chat_id={}&parse_mode=Markdown".format(text, chat_id)
    if reply_markup:
        url += "&reply_markup={}".format(reply_markup)
    get_url(url)
    print (text)

text, chat = get_last_chat_id_and_text(get_updates())
send_message(text, chat)

##EJECUTAR
def main():
    db.setup()
    last_update_id = None
    while True:
        updates = get_updates(last_update_id)
        if len(updates["result"]) > 0:
            last_update_id = get_last_update_id(updates) + 1
            handle_updates(updates)
        time.sleep(0.5)

#CONDICION PARA EJECUTAR
if __name__ == '__main__':
    main()





#import ccxt

#b = ccxt.bitso({
#    'apiKey': "XXXXXX",
#    'secret': "XXXXXX",
#    'verbose': False,
#    })
#
#print(b.fetchBalance())

Whats it commented at the end of this code is for an API i'll try to use later, once I done with the telegram api. 它在这段代码结尾处评论的是一个API,我将在稍后尝试使用,一旦我完成了电报api。

Comands.py Comands.py

#Lista de comandos

from message_dictionary import *
from Prubebas import *

def search(comando):
    if comando == "start":

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

    def done():
        keyboard = build_kerboard(items)
        send_message("Select an item to delete", chat, keyboard)

I apologies for mixing the languages. 我为混合语言道歉。 I really appreciate your help, thanks. 非常感谢你的帮助,谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM