复杂的理解os.步行表达能力的极限?

2024-04-19 05:15:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我想做点什么os.步行完全控制的基于列表的理解(后者被转换为生成器表达式),但找不到方法。我是否已经达到了Python的表达能力的极限,或者我的技巧词汇表还不够?:-)

这是我得到的,甚至为此我不得不修改一点(短路逻辑表达式和强制真),因为我可以找到一种方法来注入任何赋值运算符。不管我多么努力地隐藏它,解析器都会发现我:-)也不能在任何地方注入print(作为调试辅助工具)。你知道吗

[( s, re.sub(r"^.*?FStar\.(.*)\.fs(.*)", dest_dir + r"Fstar.\1.fst\2", s) )
     for s in ( x[0].replace('\\', '/') + "/" + f
        for x in os.walk(".")
            if (skip_dir in x[1] and x[1].remove(skip_dir) or True)
            for f in x[2] if fnmatch(f ,patt))
]

我想要的是完全控制dir,包括:

x[1][:]=[d for d in x[1] if d not in skip_list]

这让我想到了Python表达能力的极限。你知道吗

对于这种特殊情况的任何想法都是值得赞赏的,但是如果有人知道/有一个构造的例子,它提供了比os.步行只会面临理解的局限性嵌套/组合。你知道吗

我也开始希望管道或其他形式的发电机组合而写这篇文章。你知道吗

在理解结构中(通常在句法结构中)表达能力的极限是这里更大的问题。你知道吗

对于那些要求澄清的人来说,第一个问题是如何控制os.步行在理解中,为了能够删除多个项目(来自跳过列表),而不仅仅是一个项目,第二个是Python表达能力的极限-还有什么,可以在嵌套的理解结构中完成。例如作业。你知道吗


Tags: 词汇表项目方法in列表for技巧if
1条回答
网友
1楼 · 发布于 2024-04-19 05:15:15

所有Python用户都应该熟悉Zen。你知道吗

在这种情况下,我可以看到违反下一个规则

  • Readability counts.

    举个例子太难推理了。

  • Simple is better than complex.

    Sparse is better than dense.

    一个理解中有太多陈述。

  • Flat is better than nested.

    我们这里有嵌套的理解。

概述

  • 理解的副作用不是一个好主意

    x[1].remove(skip_dir)
    

    见讨论here

  • 而不是字符串串联

    x[0].replace('\\', '/') + "/" + f
    

    我们使用os.path.join

    os.path.join(x[0].replace('\\', '/'), f)
    
  • 关于声明

    for x in os.walk(".") 
    

    os.walk产生具有根目录、子目录和文件名的元组,因此最好将元组解包,而不是通过索引访问坐标

    for root, directories_names, files_names in os.walk('.')
    
  • 如果我们多次使用同一个正则表达式,那么它应该在使用前进行编译,所以

    ... re.sub(r"^.*?FStar\.(.*)\.fs(.*)", dest_dir + r"Fstar.\1.fst\2", s) ...
    

    可分为

    TARGET_FILES_NAMES_RE = re.compile(r"^.*?FStar\.(.*)\.fs(.*)")
    
    ... TARGET_FILES_NAMES_RE.sub(dest_dir + r"Fstar.\1.fst\2", s) ...
    

    另外,dest_dir + r"Fstar.\1.fst\2"应该做什么也是不清楚的:我认为它应该将dest_dir加入到简化的文件名中。

主旨

当理解变得复杂(或特别复杂)时,最好把它改写成生成函数。你知道吗

例如,它可能是

TARGET_FILES_NAMES_RE = re.compile(r"^.*?FStar\.(.*)\.fs(.*)")


def modify_paths(top, dest_dir, skip_dir, pattern):
    replacement = os.path.join(dest_dir, r"Fstar.\1.fst\2")
    for root, directories_names, files_names in os.walk(top):
        try:
            # we are removing `skip_dir` from all subdirectories,
            # is it a desired behavior?
            directories_names.remove(skip_dir)
        except ValueError:
            # not in list
            pass

        for file_name in files_names:
            if not fnmatch(file_name, pattern):
                continue
            s = os.path.join(root.replace('\\', '/'), file_name)
            yield (s,
                   TARGET_FILES_NAMES_RE.sub(replacement, s))

但它仍然是原始的,应该被重构。你知道吗

试验

我已经创建了目录

/
    doc.txt
    FStar.anotherfs
    FStar.other.fS
    FStar.some.fs90
    FStar.text..fs
    test.py

    skip_me/
            FStar.file.fs
            FStar.sample.fs
            FStar.skipped.fs

其中test.py内容:

import os
import re
from fnmatch import fnmatch

TARGET_FILES_NAMES_RE = re.compile(r"^.*?FStar\.(.*)\.fs(.*)")


def modify_paths(top, dest_dir, skip_dir, pattern):
    replacement = os.path.join(dest_dir, r"Fstar.\1.fst\2")
    for root, directories_names, files_names in os.walk(top):
        try:
            # we are removing `skip_dir` from all subdirectories,
            # is it a desired behavior?
            directories_names.remove(skip_dir)
        except ValueError:
            # not in list
            pass

        for file_name in files_names:
            if not fnmatch(file_name, pattern):
                continue
            s = os.path.join(root.replace('\\', '/'), file_name)
            yield (s,
                   TARGET_FILES_NAMES_RE.sub(replacement, s))


if __name__ == '__main__':
    top = '.'
    skip_dir = 'skip_me'
    patt = '*'
    # slash is required for version with list comprehension
    dest_dir = 'dest_dir/'
    before = [
        (s,
         re.sub(r"^.*?FStar\.(.*)\.fs(.*)", dest_dir + r"Fstar.\1.fst\2", s))
        for s in (os.path.join(x[0].replace('\\', '/'), f)
                  for x in os.walk(top)
                  if (skip_dir in x[1] and
                      x[1].remove(skip_dir) or True)
                  for f in x[2] if fnmatch(f, patt))]
    after = list(
        modify_paths(top=top, dest_dir=dest_dir, skip_dir=skip_dir,
                     pattern=patt))
    assert after == before

断言是成功的。你知道吗

附言

跳过异常不是一个好主意,但是如果您知道期望什么,它可以成为一个强大的工具。你知道吗

也可以使用contextlib.suppress上下文管理器从

try:
    directories_names.remove(skip_dir)
except ValueError:
    pass

with suppress(ValueError):
    directories_names.remove(skip_dir)

相关问题 更多 >