【问题标题】:Python line continuation results in DeprecationWarningPython 行继续导致 DeprecationWarning
【发布时间】:2019-01-02 17:48:58
【问题描述】:

在 Python 3.6.5 中,这可以正常工作:

command = "ffmpeg -i {0} -vsync 0 -q:v 2 -vf select=\"eq(pict_type\,PICT_TYPE_I)\" -r 30 {1}/frame%03d.jpg".format(file_path, output_path)

这显然是一个很长的行,所以我使用了一个续行:

command = "ffmpeg -i {0} -vsync 0 -q:v 2 -vf select=\"eq(pict_type\,PICT_TYPE_I)\" -r 30 {1}/frame%03d.jpg"\
    .format(file_path, output_path)

但是,在启动时,这会生成一个DeprecationWarning

 DeprecationWarning: invalid escape sequence \,
  command = "ffmpeg -i {0} -vsync 0 -q:v 2 -vf select=\"eq(pict_type\,PICT_TYPE_I)\" -r 30 {1}/frame%03d.jpg"\

不是,但是:

command = "foo {0} bar {1}"\
    .format(file_path, output_path)

我在项目的其余部分都使用续行;没有一个导致DeprecationWarning。像this one 这样的其他问题提到了这个警告,但没有关于我能找到的连续字符的问题。

是什么导致了这个警告,为什么它只出现在这种非常狭窄的情况下?

编辑:这与续行无关。仅在某些时候出现错误的原因与 Django 的runserver 有关。第一次运行runserver,没有报错。但是如果更改导致重新加载,则在重新加载器运行时会报告错误。

【问题讨论】:

    标签: python django python-3.x


    【解决方案1】:

    这与您的行继续无关,它与使用 \, 作为字符串中的转义序列有关。

    警告明确包括\,

    DeprecationWarning: invalid escape sequence \,
    

    这就是您后面的示例没有发出警告的原因:因为字符串中没有\, 或其他无法识别的转义序列。

    String and Byte literals 的文档中所述:

    在 3.6 版中更改:无法识别的转义序列产生 DeprecationWarning。在 Python 的某些未来版本中,它们将是 SyntaxError

    What's New in Python 3.6 中提到了此更改,并带有指向 issue #27364 的链接,该链接指向 an earlier discussion on the -dev mailing list

    传统上,Python 允许在字符串文字中出现无法识别的转义序列,并且只是将它们当作不是转义符来处理,因此\, 的字面意思是反斜杠和逗号,因为这样可以更容易地在打印时查看出了什么问题在调试器中取出字符串。

    但这会导致各种混乱,尤其是对于 Windows 用户(他们使用 'C:\Spam''C:\spam''C:\Vikings',但使用 'C:\vikings' 时出错),以及来自任何大量语言遵循 C 风格的转义规则(其中\, 仅表示逗号,尽管大多数 C 编译器会为此生成警告),这大概就是您现在收到警告的原因。

    【讨论】:

    • 这就解释了;我想是这样的。但是为什么行继续字符的存在会影响是否输出呢?
    • @Ares 我不这么认为。我无法重现这种行为;任何我收到第二个警告的情况,如果我将其更改为第一个,我都会收到警告。您能否提供一个显示差异的可重现测试用例?如果是这样,这可能是一个应该报告的错误。
    • @Ares:是否存在续行字符都没有关系(只要启用DeprecationWarnings,我就可以复制任何一种方式)。如果您以不同的方式启动或使用代码,您可能会设置不同的警告级别(默认情况下,DeprecationWarnings 不会发出,但您的一项测试可能会启用它)。
    • @abarnert 等人;我想到了;该问题与 Django 的重新加载行为有关。第一次执行runserver,没有出现警告,但是当reloader运行时,出现了警告。我错误地将行为归因于我的代码中所做的更改,而不是 Django 的重新加载器。
    • @Ares:他们可能将DeprecationWarning 的处理行为设置为module(在给定模块中首次引发时打印,然后保持沉默)或once(打印每一类警告第一次发生在程序范围内,然后再也不会发生)。无论哪种方式都会得到你描述的行为。
    【解决方案2】:

    尝试使用命令列表:

    command = [
        "ffmpeg",
        "-i", file_path,
        "-vsync", "0", 
        "-q:v", "2",
        "-vf", 'select="eq(pict_type,PICT_TYPE_I)"',
        "-r", "30", 
        os.path.join(output_path, "frame%03d.jpg"),
    ]
    

    然后在不使用shell=True的情况下调用它:

    subprocess.run(command)
    

    通过这样做,您可以获得多种优势:

    1. 摆脱了引用并逃脱了地狱 - 您不必添加引号或逃避任何事情。空格不再是分隔符,参数将按列表传递。
    2. 您不必使用字符串插值 (.format),因为您可以将参数单独传递给列表。
    3. 通过不使用 shell,您可以避免执行一个额外的进程 - 当您可以直接运行命令时,为什么还要执行一个 shell 来运行它?

    【讨论】:

    • 虽然这是 100% 正确的,但它并不能解释问题的原因,也不一定是正确的答案(例如,如果没有直接使用 subprocess,它们可能出于某种原因重新打印此内容,或将其传递给某些第三方 API)。
    • @ShadowRanger 同意,但我认为这个答案真的会帮助 OP,大多数人使用带有 subprocess 和 (argh) os.system 的命令。
    • @nosklo 我建议在 3.0 中将 os.system 移至 subprocess.system。 Guido 的回答是这样的:好主意,但人类不可能阻止人们找到该函数,调用它,然后询问他们为什么无法捕获输出。这是自然规律。
    猜你喜欢
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 2011-06-19
    相关资源
    最近更新 更多