python - 如何对可迭代元素进行 glob

标签 python

我有一个包含可迭代对象的 python 字典,其中一些是列表,但大部分是其他字典。我想进行类似于以下的 glob 式赋值:

myiter['*']['*.txt']['name'] = 'Woot'

也就是说,对于 myiter 中的每个元素,查找所有键以“.txt”结尾的元素,然后将它们的“名称”项设置为“Woot”。

我考虑过对 dict 进行子类化并使用 fnmatch 模块。但是,我不清楚实现此目标的最佳方法是什么。

最佳答案

我认为最好的方法是这样做——'*' 是字典中完全有效的键,所以myiter[ '*'] 具有完美定义的含义和用途,颠覆肯定会导致问题。如何“全局”处理不是字符串的键,包括列表而非映射元素中的唯一整数“键”(索引),也是一个相当大的设计问题。

如果您仍然必须这样做,我建议通过子类化 abstract base class 来完全控制collections.MutableMapping,并实现所需的方法(__len____iter____getitem____setitem____delitem__,并且为了获得更好的性能,还覆盖了其他内容,例如 __contains__,ABC 确实在其他内容的基础上实现了这些内容, 但很慢)就包含的 dict 而言。相反,根据其他建议,子类化 dict 将要求您重写大量方法,以避免在您重写的方法中使用“包含通配符的键”与您重写的方法之间出现不一致的行为不要。

无论您是继承 collections.MutableMapping 还是 dict 来创建您的 Globbable 类,您都必须做出核心设计决策:什么当yourthingGlobbable 时,yourthing[somekey] 返回 吗?

据推测,当 somekey 是包含通配符的字符串时,它必须返回不同的类型,而不是其他任何类型。在后一种情况下,人们会想象,该条目实际上是什么;但在前者中,它不能只返回另一个 Globbable——否则,yourthing[somekey] = 'bah' 会做什么一般情况?对于您的单个“灵活语法”示例,您希望它在 yourthing 的每个 items 中设置一个 somekey 条目(一个 与宇宙中所有其他映射的行为的巨大语义断裂;-) - 但是,你怎么会在 yourthing 本身中设置一个条目?!

让我们看看Python之禅对这个你向往的“巧妙的语法”有什么看法......:

>>> import this
    ...
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.

暂时考虑放弃“灵活的语法”(以及它必然暗示的所有巨大语义头痛)的替代方案,以支持清晰和简单(这里使用 Python 2.7 和更好的语法) , 只是为了 dict 理解——如果你坚持使用 2.6 或更早版本,请改用显式 dict(...) 调用),例如:

def match(s, pat):
    try: return fnmatch.fnmatch(s, pat)
    except TypeError: return False

def sel(ds, pat):
    return [d[k] for d in ds for k in d if match(k, pat)]

def set(ds, k, v):
    for d in ds: d[k] = v

所以你的任务可能会变成

set(sel(sel([myiter], '*')), '*.txt'), 'name', 'Woot')

(带有 '*' 的选择如果全部都是多余的,我只是将其省略)。这是否如此可怕到值得我在上面提到的问题的泥沼来代替使用

myiter['*']['*.txt']['name'] = 'Woot'

...?当然,到目前为止,最清晰、性能最好的方法仍然是更简单的方法

def match(k, v, pat):
    try:
      if fnmatch.fnmatch(k, pat):
        return isinstance(v, dict)
    except TypeError:
        return False

for k, v in myiter.items():
  if match(k, v, '*'):
    for sk, sv in v.items():
      if match(sk, sv, '*.txt'):
        sv['name'] = 'Woot'

但是如果你绝对渴望简洁和紧凑,鄙视 Python 的禅宗“稀疏胜于密集”,你至少可以得到它们,而不需要我提到的实现你的需要的各种噩梦理想的“语法糖”。

关于python - 如何对可迭代元素进行 glob,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3601309/

相关文章:

python - 导入 keras 和 tensorflow 时出错

ping 命令的 Python 包装器在收到 pong 时停止

python - SIGKILL 在一个简单的 python 脚本中添加列

python - 如何获取异常回溯中第二个项目的文件名?

python - 为什么新行 "\n"不适用于 Jython for WAS wasadmin

Python 计时器没有按预期等待

python - 使用 python/pandas 组合值

python - python docstring中参数描述的多行描述

python - 转换小数点分隔符

python - PhantomJS 放在路径中,可以在终端执行,但在 Python 中出现 PATH 错误