Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何通过已知协议将python程序与第三方程序接口?_Python_Interface - Fatal编程技术网

如何通过已知协议将python程序与第三方程序接口?

如何通过已知协议将python程序与第三方程序接口?,python,interface,Python,Interface,我正在尝试使用Go文本协议(GTP-)与一个程序(GoGui-)接口,该协议有其文档。(链接也可以在以前的网站上找到。) 因此,我编写了一些代码,至少让GoGui确认我的程序的存在: import sys import engine import input_processing for line in sys.stdin: if line == 'name\n': sys.stdout.write(' Muizz-Bot\n\n') if line == 'p

我正在尝试使用Go文本协议(GTP-)与一个程序(GoGui-)接口,该协议有其文档。(链接也可以在以前的网站上找到。)

因此,我编写了一些代码,至少让GoGui确认我的程序的存在:

import sys
import engine
import input_processing

for line in sys.stdin:
    if line == 'name\n':
        sys.stdout.write(' Muizz-Bot\n\n')
    if line == 'protocol_version\n':
        sys.stdout.write('2\n\n')
    if line == 'version\n':
        sys.stdout.write('')
现在,这本身似乎并不不合理,但会导致GoGui给我以下错误:

这当然是个问题。因此,我认为我在编程中犯了一个错误,但当我只是通过visual studio运行程序时,一切都按预期运行:

这让我觉得问题在于如何连接这两个应用程序,也许我应该看看stdin和stdout以外的其他功能。有人知道这里可能出了什么问题吗

编辑注释:我目前正在处理的命令解析代码(全部)如下所示:

import sys

commands = ['protocol_version', 'name', 'version', 'list_commands', 'known_command', 'quit', 'boardsize', 
            'clear_board', 'komi', 'play', 'genmove']

pre_game_out = ['2','Muizz-Bot','']

# Define all output functions
def list_commands():
    out = '\n'.join(commands)
    return(out)
def known():
    return(True)
def quit():
    return(None)
def boardsize():
    return(None)
def clear_board():
    return(None)
def komi():
    return(None)
def play():
    return(None)
def genmove():
    return("A1")

# Create dictionary to point to all functions.
output = {'list_commands':list_commands, 'known_command':known, 'quit':quit, 'boardsize':boardsize, 
            'clear_board':clear_board, 'komi':komi, 'play':play, 'genmove':genmove}

# Define the function that will pass the commands and write outputs.
def parse(line):
    if line.strip() in commands:
        i = commands.index(line.strip())
        if i<3:
            sys.stdout.write('= '+ pre_game_out[i]+'\n\n')
            sys.stdout.flush()
        else:
            sys.stdout.write('= ' + output[line.strip()]() + '\n\n')
            sys.stdout.flush()

您没有刷新响应,因此不会将任何内容发送回调用方(因为命令不够大,无法触发自动缓冲区刷新)。另外,在协议文档中,它清楚地指出您的响应应该是
=response\n\n
的形式,因此即使您刷新它,它也可能不起作用

尝试以下方法:

import sys

for line in sys.stdin:
    if line.strip() == 'name':
        sys.stdout.write('= Muizz-Bot\n\n')
        sys.stdout.flush()
    elif line.strip() == 'protocol_version':
        sys.stdout.write('= 2\n\n')
        sys.stdout.flush()
    elif line.strip() == 'version':
        sys.stdout.write('=\n\n')
        sys.stdout.flush()
您可能希望创建一个简单的函数来解析命令/响应,而不是重复代码。此外,这也可能(完全)不起作用,因为协议文档指出您需要实现相当多的命令(
6.1必需的命令)
),但它应该让您开始

更新-这里有一种方法可以使它更易于管理并符合规范-您可以为每个命令创建一个函数,以便您可以轻松地添加/删除它们,例如:

def cmd_name(*args):
    return "Muizz-Bot"

def cmd_protocol_version(*args):
    return 2

def cmd_version(*args):
    return ""

def cmd_list_commands(*args):
    return " ".join(x[4:] for x in globals() if x[:4] == "cmd_")

def cmd_known_command(*args):
    commands = {x[4:] for x in globals() if x[:4] == "cmd_"}
    return "true" if args and args[0] in commands else "false"

# etc.
在这里,所有命令函数都以“cmd_u”(和
cmd_list_commands()
cmd_known_command()
使用该事实来检查全局名称空间中的命令函数),但您也可以将它们移动到其他模块,然后“扫描”该模块。使用这种结构,添加新命令非常容易,例如,要添加所需的
quit
命令,您只需定义它:

def cmd_quit(*args):
    raise EOFError()  # we'll use EOFError to denote an exit state bellow
此外,我们将在下面处理命令需要返回错误的情况—您只需从函数中执行
raisevalueerror(“错误响应”)
,它将作为错误返回

将命令集添加为函数后,只需解析输入命令,使用正确的参数调用正确的函数并打印回响应:

def call_command(command):
    command = "".join(x for x in command if 31 < ord(x) < 127 or x == "\t")  # 3.1.1
    command = command.strip()  # 3.1.4
    if not command:  # ... return if there's nothing to do
        return
    command = command.split()  # split to get the [id], cmd, [arg1, arg2, ...] structure
    try:  # try to convert to int the first slice to check for command ID
        command_id = int(command[0])
        command_args = command[2:] if len(command) > 2 else []  # args or an empty list
        command = command[1]  # command name
    except ValueError:  # failed, no command ID present
        command_id = ""  # set it to blank
        command_args = command[1:] if len(command) > 1 else []  # args or an empty list
        command = command[0]  # command name
    # now, lets try to call our command as cmd_<command name> function and get its response
    try:
        response = globals()["cmd_" + command](*command_args)
        if response != "":  # response not empty, prepend it with space as per 3.4
            response = " {}".format(response)
        sys.stdout.write("={}{}\n\n".format(command_id, response))
    except KeyError:  # unknown command, return standard error as per 3.6
        sys.stdout.write("?{} unknown command\n\n".format(command_id))
    except ValueError as e:  # the called function raised a ValueError
        sys.stdout.write("?{} {}\n\n".format(command_id, e))
    except EOFError:  # a special case when we need to quit
        sys.stdout.write("={}\n\n".format(command_id))
        sys.stdout.flush()
        sys.exit(0)
    sys.stdout.flush()  # flush the STDOUT

当然,正如我前面提到的,将命令打包到一个单独的模块中可能是一个更好的主意,但这至少可以让您了解如何进行“关注点分离”,这样您就不用担心如何响应命令,而不用担心它们如何被调用以及它们如何响应调用者了。

也许可以使用套接字??这两个程序都在同一台机器上运行,协议需要通过stdin/out进行对话,所以几乎可以肯定第三方程序就是这样做的。请注意,我对编程特别是python非常陌生,因此在试图解释事情时,我可能需要比平时更多的人手,对不起,我完全错过了=。。。(取而代之的是3.4)但它的工作原理是这样的!不过我有两个问题:在if语句中使用line.strip(),是为了增加可读性,还是它还有更重要的用途?您使用的是elif语句,而不是if语句。这可能是一个非常理论化的问题,但我使用if语句的理由是,只需要检查一个等式,而不是多个等式;这将提高效率。这个推理有什么好处吗?或者elif有什么好处?@MitchellFaas-
str.strip()
清除两端的空白。但是,如果调用方发送了如下命令:
14 name\n
(一个完全有效的命令),它将不起作用,因为它不处理存在ID的情况-请查看上面的更新,作为如何正确处理文档中描述的情况的示例。至于
if
语句,您的理解是错误的-
elif/else
语句只有在同一链中的前几条语句的计算结果不是
True
时才进行计算。您的方法将在每个循环中对所有代码进行求值,无论其中一些代码是否为
True
。您编写的代码目前超出了我的理解范围。我的计划是使用命令解析模块(所有代码都可以在原始帖子中找到),并使用字典识别需要执行的命令,然后运行该功能。今天,我将致力于设置参数,我将尝试在预处理过程中分离这些参数。
def call_command(command):
    command = "".join(x for x in command if 31 < ord(x) < 127 or x == "\t")  # 3.1.1
    command = command.strip()  # 3.1.4
    if not command:  # ... return if there's nothing to do
        return
    command = command.split()  # split to get the [id], cmd, [arg1, arg2, ...] structure
    try:  # try to convert to int the first slice to check for command ID
        command_id = int(command[0])
        command_args = command[2:] if len(command) > 2 else []  # args or an empty list
        command = command[1]  # command name
    except ValueError:  # failed, no command ID present
        command_id = ""  # set it to blank
        command_args = command[1:] if len(command) > 1 else []  # args or an empty list
        command = command[0]  # command name
    # now, lets try to call our command as cmd_<command name> function and get its response
    try:
        response = globals()["cmd_" + command](*command_args)
        if response != "":  # response not empty, prepend it with space as per 3.4
            response = " {}".format(response)
        sys.stdout.write("={}{}\n\n".format(command_id, response))
    except KeyError:  # unknown command, return standard error as per 3.6
        sys.stdout.write("?{} unknown command\n\n".format(command_id))
    except ValueError as e:  # the called function raised a ValueError
        sys.stdout.write("?{} {}\n\n".format(command_id, e))
    except EOFError:  # a special case when we need to quit
        sys.stdout.write("={}\n\n".format(command_id))
        sys.stdout.flush()
        sys.exit(0)
    sys.stdout.flush()  # flush the STDOUT
if __name__ == "__main__":  # make sure we're executing instead of importing this script
    while True:  # main loop
        try:
            line = sys.stdin.readline()  # read a line from STDIN
            if not line:  # reached the end of STDIN
                break  # exit the main loop
            call_command(line)  # call our command
        except Exception:  # too broad, but we don't care at this point as we're exiting
            break  # exit the main loop