为什么 sublime text 3.x 中的自定义构建 python 2.7.x 没有相应地运行 [英] why custom-build python 2.7.x in sublime text 3.x doesn't run accordingly

查看:62
本文介绍了为什么 sublime text 3.x 中的自定义构建 python 2.7.x 没有相应地运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

def a(x):
    assert x>0,'invalid argument'
    print 'wow'

a(2)
a(0)

这应该首先打印wow",然后它应该引发异常,但它会打印.wow"在assert x>0"之前和AssertionError"之后被拆分为wo",最后第三行,它在回溯"之前不断发生不可预测的变化:

this should first print "wow" and then it should raise an exception but instead it prints.The "wow" is splited as "wo" before "assert x>0" and after "AssertionError" on third last line and it keeps changing unpredictly but not once before "Traceback":

Traceback (most recent call last):
  File "E:\Books\Python\think python\assert.py", line 6, in <module>
    a(0)
  File "E:\Books\Python\think python\assert.py", line 2, in a
wo    assert x>0,'invalid argument'
AssertionErrorw
: invalid argument
[Finished in 0.1s with exit code 1]

我的崇高构建是:

{
    "cmd": ["C:\\Python27\\python", "-u", "$file"],
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
    "selector": "source.python",
    "shell": true
}

推荐答案

当 Sublime 启动一个外部程序时(例如当你运行一个构建并且它运行 python 时),它会启动两个后台线程,捕获正在运行的程序的 stdoutstderr 句柄的输出,以便它可以在构建面板中显示它.

When Sublime launches an external program (such as when you run a build and it runs python), it starts two background threads that capture the output of the stdout and stderr handles of the program that it's running so that it can display it in the build panel.

Sublime 确保这两个线程中只有一个可以在任何时候向输出面板添加数据,但是每个线程捕获的数据以任何方式都没有缓冲,因此一旦任何数据出现在输出句柄上,它就会排队用于附加到输出面板.

Sublime makes sure that only one of those two threads can add data to the output panel at any point, but the data captured by each thread is unbuffered in any way, so as soon as any data appears at the output handle it's queued up for appending to the output panel.

您看到这种情况发生的原因是因为打印语句将输出发送到 stdout,但将异常写入 stderr.由于多线程程序的性质,不确定两个线程中的哪一个可能首先捕获它的输出,这意味着两个句柄的输出以明显随机的方式混合.

The reason you see this happening is because the print statement sends output to stdout, but exceptions are written to stderr. Due to the nature of multi threaded programs, it's indeterminate which of the two threads might capture it's output first, which means that the output of the two handles mix in apparently random ways.

我认为 Sublime 是这样工作的,因为如果它默认将输出缓冲到行,一次生成部分行的程序似乎根本没有运行.

I would imagine that Sublime works this way because if it buffered output to lines by default, programs that generate partial lines at a time would appear to not be running at all.

在实践中,虽然很烦人,但这不应该对事物产生太大的有害影响,因为一般来说 stdout 用于常规输出而 stderr 用于错误消息,所以如果两者都需要使用,则已经发生了一些不愉快的事情.

In practice, while annoying this should not have too much of a deleterious effect on things since generally speaking stdout is for regular output and stderr is for error messages, so if both need to be used something untoward is already happening.

也可以创建您自己的自定义构建 target 来模仿 exec 所做的事情,除了行缓冲,以防这种事情是一个可靠的要求.

It's also possible to create your own custom build target that mimics what exec does except with line buffering, in case such a thing is a solid requirement.

作为对上述内容的进一步解释(以及运行带有行缓冲的程序的示例),这里有一个 Python 程序示例,它更清楚地演示了此处发生的情况.每秒一次,持续 10 秒,这会生成一个 .stdout 和一个 -stderr,然后一旦10 秒过去了,它依次向每个句柄发送一个换行符.

As further explanation for the above (and an example of running a program with line buffering), here is an example Python program that demonstrates more clearly what's happening here. Once a second for 10 seconds this generates a . to stdout and a - to stderr, and then once the 10 seconds has elapsed, it sends a newline to each handle in turn.

import sys
import time

for _ in range(0,10):
    sys.stdout.write(".")
    sys.stderr.write("-")
    sys.stdout.flush()
    sys.stderr.flush()
    time.sleep(1)

sys.stdout.write("\n")
sys.stderr.write("\n")

当我使用默认的 Python.sublime-build 运行程序时,我得到了这个:

When I run the program with the default Python.sublime-build, I end up with this:

.--.-..-.--.-.-.-.-.

[Finished in 10.1s]

这表明,stderrstdout 的输出不仅混合在一起,而且由于捕获的多线程性质,它还以奇怪的不确定方式进行.

This demonstrates that not only does the output of stderr and stdout blend together, it also does it in weirdly indeterminate ways caused by the multi-threaded nature of the capture.

例如,您可能希望输出像 .-.-.-.-.-.-.-.-.-.- 这样的交替序列,但它不会't;虽然每个项目有 10 个,但它们的显示顺序与我们打印出来的顺序不同,因为每个线程被安排运行并注意到有输出添加到面板的顺序是不确定的.

For example you might expect the output to come out as an alternating series like .-.-.-.-.-.-.-.-.-.-, but it doesn't; although there are 10 of each item, they don't appear in the same order that we printed them out because the order that each thread gets scheduled to run and notices that there is output to add to the panel is indeterminate.

正如我上面提到的,您可以创建自己的自定义构建目标,该目标执行 exec 命令所做的工作,但将数据保存在中间缓冲区中并仅将其释放到输出面板行一个时间而不是它出现的时间,这将阻止这种情况发生.

As I mentioned above, you can create your own custom build target that does what the exec command does with the exception of holding data in an intermediate buffer and only releasing it to the output panel lines at a time instead of as it appears, which will stop this from happening.

重要提示:像这样进行行缓冲不会停止来自 stderrstdout 的数据交错,它只是确保数据一次交错整行,而不是在彼此中线上进行所有外星人胸部爆破".要真正停止交错,您需要将每个句柄发送到不同的位置(例如两个面板或将 stderr 发送到控制台).

Important Note: Doing line buffering like this doesn't stop the data from stderr and stdout from interleaving, it just ensures that the data interleaves whole lines at a time instead of going all "alien chest burster" on each other mid-line. To truly stop the interleave you need to send each handle to a different location (like two panels or sending stderr to the console).

像这样的完整代码太长而无法添加到 SO 答案中,因此出于演示目的,我将代码放在 这个要点.修订版 1 是文件的基本版本,修订版 2 是缓冲的修改版本,因此您可以看到 两者之间的差异以更好地了解变化.

The full code for something like this is too lengthy to add to an SO answer, so for demonstration purposes I've put the code in this gist. Revision 1 is the base version of the files and revision 2 is the modified versions for buffering, so you can see the differences between the two to better understand the change.

默认的 exec 命令捕获来自 stderrstdout 的输出,并在收到后直接将其发送到输出面板;当数据到达输出面板时,该命令会将行尾字符标准化为 Sublime 期望看到的内容(对于 Windows/Mac 计算机),然后将其添加到面板中.

The default exec command captures output from stderr and stdout and sends it directly to the output panel once it's received; as the data arrives at the output panel the command normalizes the line end characters to what Sublime expects to see (for Windows/Mac computers), then adds it to the panel.

修改后的版本将数据读入临时缓冲区并立即进行换行规范化,然后仅沿其累积的任何整行转发,将其余数据留给下一次.输出完成后,任何剩余的数据都会发送到缓冲区,以便显示所有内容.

The modified version reads the data into a temporary buffer and does the newline normalization right away, then only forwards along any whole lines that it has accumulated, leaving the rest of the data for the next time around. Once the output is finished, any remaining data is sent to the buffer so that everything gets displayed.

为了使用新目标,sublime-build 文件必须添加一个 target 参数来告诉 Sublime 使用除 exec 之外的命令.Gist 有一个用于默认 Python.sublime-build 的示例,以及一个额外的键添加以允许 Cancel Build 功能与自定义目标一起使用.

In order to use the new target, the sublime-build file has to have a target argument added to tell Sublime to use a command other than exec. The Gist has an example of that for the default Python.sublime-build, along with an extra key to add to allow the Cancel Build functionality to work with the custom target.

修改后的构建到位,程序的输出变成这样:

With the modified build in place, the output of the program becomes this:

----------
..........
[Finished in 10.1s]

请注意,这样做的副作用是,现在 10 秒内您在构建面板中什么也看不到,然后所有输出都会同时出现,因为它在完成之前不会出现;这种事情很可能是 Sublime 默认不这样做的原因.

Note that a side effect of this is that now you see nothing at all in the build panel for 10 seconds and then all of the output appears all at once, since it can't appear until it's complete; this sort of thing is likely the reason why Sublime doesn't do this by default.

如上所述,这不会阻止数据交错,它只是控制它的发生方式,因此一次只发生一行.仍然不确定 stdoutstderr 哪一行最先出现.

As mentioned above, this doesn't stop the data from interleaving, it just controls how it happens so it happens a line at a time. It's still indeterminate which of the stdout and stderr lines appears first.

如果您愿意,可以修改从第 169 行开始的代码:

If you like, you can modify the code starting at line 169 from this:

# Accumulate data into our buffer and only let full lines
# through to the output panel.
if self.listener:
    pBuffer += data
    nPos = pBuffer.rfind("\n")
    if nPos >= 0:
        self.listener.on_data(self, pBuffer[:nPos+1])
        pBuffer = pBuffer[nPos+1:]

为此:

# Accumulate data into our buffer and only let full lines
# through to the output panel; stderr data is held until the
# handle is closed below.
if self.listener:
    pBuffer += data
    if execute_finished:
        nPos = pBuffer.rfind("\n")
        if nPos >= 0:
            self.listener.on_data(self, pBuffer[:nPos+1])
            pBuffer = pBuffer[nPos+1:]

这会修改一些东西,以便 stderr 的数据存储在缓冲区中,但在程序终止之前不会释放到输出面板.

That modifies things so that the data for stderr is stored in a buffer but not released to the output panel until after the program terminates.

这样做将确保没有交错,但也会阻止您在错误发生的时候看到错误.如果您的程序长时间运行,也无法看到错误,如果有大量错误输出被缓冲但未显示,则会导致内存使用量增加.

Doing that will ensure that there's no interleave, but it also stops you from seeing errors at the point at which they occurred. It also makes it impossible to see errors as they happen if your program is long running and can cause memory usage to increase if there is a lot of error output being buffered but not displayed.

因此,我不建议这样做,除非您正在执行诸如运行短期程序之类的事情,在这种情况下,错误出现在最后的干扰较小.

As such I wouldn't recommend this unless you're doing something like running short lived programs where it's less intrusive to have the errors appear at the end.

这篇关于为什么 sublime text 3.x 中的自定义构建 python 2.7.x 没有相应地运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆