【问题标题】:Python syntax explanation:Python语法解释:
【发布时间】:2023-05-11 01:45:02
【问题描述】:

您能解释一下为什么这个 Python 代码对 C 程序员有效吗?

这个习语用于递归检索文件列表

[os.path.join(dp, f) for dp, dn, fn in os.walk(os.path.expanduser(dir)) for f in fn]

我在Recursive os.listdir? 找到了这种风格。它没有标点符号或嵌套。我不明白为什么它会起作用。你能不能用我能理解的更乏味的风格写同样的东西,这样我就不会感到那么无助? :)

人们通常会说“举个例子说明你为什么要使用它”,然后我会向你展示整个程序。我惊呆了,我在博客上写了一张照片http://pj.freefaculty.org/blog/?p=285

这适用于带有 XFCE4 桌面和 Compiz 窗口管理器/合成器的 Ubuntu 14.10。它将通过 gsettings 与 Dconf 交互来替换视口上的背景壁纸。

我不明白的用法在下面的random.choice()里面:

#!/usr/bin/env python3

import argparse
import subprocess
import sys
import os
import random

parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dir",  help = "directory path", 
                default = "/usr/local/share/Backgrounds")
parser.add_argument("-w", "--workspace", 
                help = "workspace number, 0, 1-n, or > n", default = "-1", 
                type = int)
parser.add_argument("-schema", help = "gsettings shema", 
                metavar = "SCHEMA", default = "org.compiz.wallpaper:/org/compiz/profiles/Default/plugins/wallpaper/")
parser.add_argument("-key", help = "gsettings key", metavar = "KEY", default = "bg-image")
args = parser.parse_args()

array = eval(subprocess.check_output(["gsettings", "get", args.schema, args.key]))

## print(array)
arraylen = len(array)

filename = random.choice([os.path.join(dp, f) for dp, dn, fn in os.walk(os.path.expanduser(args.dir)) for f in fn])
print("The newly found filename is:")
print(filename)

ws = args.workspace - 1

## If ws 0 or smaller, we are going to reset whole collection back to
## just one image. if ws > N of images, then add a new image.
if ws < 0:
    array=[str(filename)]
    subprocess.call(["gsettings", "set", args.schema, args.key, str(array)])
    subprocess.call(["gsettings", "set", args.schema, "bg-fill-type", str("[0]")])
    subprocess.call(["gsettings", "set", args.schema, "bg-image-pos", str("[0]")])
    subprocess.call(["gsettings", "set", args.schema, "bg-color1", str("['#000000ff']")])
    subprocess.call(["gsettings", "set", args.schema, "bg-color2", str("['#000000ff']")])
elif ws < arraylen:
    array[ws]=str(filename)
    subprocess.call(["gsettings", "set", args.schema, args.key, str(array)])
else:
    array.append(str(filename))
    subprocess.call(["gsettings", "set", args.schema, args.key, str(array)])
    arraylen = len(array)
    subprocess.call(["gsettings", "set", args.schema, "bg-fill-type", str([0]*arraylen)])
    subprocess.call(["gsettings", "set", args.schema, "bg-image-pos", str([0]*arraylen)])
    subprocess.call(["gsettings", "set", args.schema, "bg-color1", str(['#000000ff']*arraylen)])
    subprocess.call(["gsettings", "set", args.schema, "bg-color2", str(['#000000ff']*arraylen)])

subprocess.call(["gsettings", "set", args.schema, args.key, str(array)])

print("HELLO, corrected image array is:")               
print('\n '.join(array))

如果你说“我们不理解你不理解的东西”,我明白了。以下是我想问的一些具体问题

  1. 为什么dp、dn、fn周围没有括号
  2. “for f in fn”末尾的 for 语句“内部”没有语句。
  3. 当 dp 和 f 在该语句之前不存在时,os.path.join(dp, f) 如何工作?

当人们将 if 语句放在行尾而不是放在开头时,我在 Perl 中也有同样的过敏感觉。

【问题讨论】:

  • 这叫做列表推导。

标签: python-3.x syntax os.walk


【解决方案1】:

当你运行时:

a=[[1,2],[3,4]]
[x for y in a for x in y]

你得到:

[1,2,3,4]

也就是说,它为a 中的每个条目运行y,而不是将x 设置为y 的每个条目,所以它相当于:

for y in a:
    for x in y:
        code with x

您可以将代码重写为:

result=[]
for dp, dn, fn in os.walk(os.path.expanduser(args.dir)):
   for f in fn:
       result.append(os.path.join(dp, f))

重要的是,第一个始终是循环的左侧,因此可以以这种方式使用变量。

至于方括号,可以写在那里,但隐含明确一定是元组,所以没必要写。

【讨论】: