【问题标题】:Python - short syntax and list comprehension and iterationsPython - 简短的语法和列表理解和迭代
【发布时间】:2014-09-16 22:27:45
【问题描述】:

我是 Python 列表理解的忠实粉丝,我认为它实际上比常规迭代更容易阅读。

我正在编写一个构造函数,它在**kwargs 中具有可选参数,可用于设置类的属性,我想将其写为列表理解,但拥有一个不包含的列表似乎毫无意义'实际上什么都不做。考虑一下:

class Book(object):
    attrs = ('id', 'title', 'authors',...)
    def __init__(self, *args, **kwargs):
        [setattr(self, attr, kwargs.get(attr) 
              for attr in O.attrs if kwargs.get(attr)]

虽然语法看起来不错,但我认为这是不好的编码,因为您创建了一个列表

[None, None, None...]

那只是坐在那里。是的,我知道它是在构造函数运行后收集的,但我仍然不喜欢它。如果我读了某人的代码,我会不为所动。

是否有更好的方法来完成与列表推导一样干净但不会创建无用对象的迭代

编辑:

响应使用循环

class Book(object):
    attrs = ('id', 'title', 'authors',...)
    def __init__(self, *args, **kwargs):
         for attr in attrs:
             if kwargs.get(attr):
                 setattr(self, attr, kwargs.get(attr)

这就是你们的意思吗?如果没有,还有什么更好的写法?

【问题讨论】:

  • 只需使用常规的for 循环即可。
  • 要检查密钥是否在字典中,请使用if attr in kwargs 而不是if kwargs.get(attr)

标签: python list iteration list-comprehension


【解决方案1】:

您可以使用生成器表达式代替列表推导式,直接更新instance __dict__ attribute

class Book(object):
    attrs = ('id', 'title', 'authors',...)
    def __init__(self, *args, **kwargs):
        self.__dict__.update(
            (attr, kwargs[k]) for k in kwargs.viewkeys() & self.attrs)

这也利用了dictionary views;在 Python 3 中,只需使用 kwargs.keys() 而不是 kwargs.viewkeys()。字典视图作为一个集合; & self.attrs 表达式生成 kwargs 的键和您的属性列表之间的交集。

生成器表达式生成(key, value) 对,这是dict.update() method 的两个可接受输入之一。

更新self.__dict__ 很好; Python 2.7 标准库在 7 个不同的位置使用了这种技术,另外还有大约 30 个其他突变案例。请注意,如果您使用描述符(@property 和/或其他自定义描述符),那么访问 self.__dict__ 将绕过这些。

至于副作用的列表推导:不要。您确实在浪费循环创建一个立即丢弃的列表对象,从而混淆了对列表理解用于的期望。

您还可以在常规的 for 循环中将其与显式 setattr() 调用结合起来:

for attr in kwargs.viewkeys() & self.attrs:
    setattr(self, attr, kwargs[attr])

【讨论】:

  • 我已经在多个地方(甚至在 SO 上)阅读过如何避免直接更新 __dict__
  • @SamHammamy:如果你想保持纯洁,可以使用vars()
  • @SamHammamy:值得一提的是:Python 标准库正好有 9 个 self.__dict__.update
  • Downvoted - 直接设置实例的 __dict__ 是一个糟糕的主意,因为它会绕过任何属性或自定义描述符。 Martijn 你应该更了解...
  • @martijn 更新self.__dict__ 并不常见(正如您提到的那样,stdlib 中有 9 个案例 - 我不会将其限定为“常见” - 仍然是一个不好的做法。现在它就像任何“黄金法则”:你可以打破它,但只有当你真正理解什么时候可以打破它时。鉴于你(在很大程度上应得的)声誉,我对你提出这样的解决方案感到非常惊讶。
【解决方案2】:

怎么样:

for attr in [a for a in attrs if a in kwargs]:
    setattr(self, attr, kwargs[attr])

这相当简单和甜蜜......

或者按照 Chris 的建议:

for attr in (a for a in attrs if a in kwargs):

会更好。 (生成器而不是列表)

【讨论】:

  • for attr in kwargs.viewkeys() & attrs:
  • 搭配发电机效果更好。
  • Martijn:真的很简洁。我喜欢它。我总是忘记观点。不过有点不太明显。我想如果我更多地使用视图并且可以记住像 & 一个视图和一个列表,但不是两个列表,那么它会读起来也一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 2022-01-10
  • 2016-07-09
  • 2021-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多