【问题标题】:How to break a line of chained methods in Python?如何在 Python 中打破一行链式方法?
【发布时间】:2011-06-13 17:26:47
【问题描述】:

我有以下一行代码(不要责怪命名约定,它们不是我的):

subkeyword = Session.query(
    Subkeyword.subkeyword_id, Subkeyword.subkeyword_word
).filter_by(
    subkeyword_company_id=self.e_company_id
).filter_by(
    subkeyword_word=subkeyword_word
).filter_by(
    subkeyword_active=True
).one()

我不喜欢它的样子(不太可读),但在这种情况下我没有更好的办法将行数限制为 79 个字符。有没有更好的方法来打破它(最好没有反斜杠)?

【问题讨论】:

    标签: python coding-style pep8


    【解决方案1】:

    您可以使用额外的括号:

    subkeyword = (
        Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word)
        .filter_by(subkeyword_company_id=self.e_company_id)
        .filter_by(subkeyword_word=subkeyword_word)
        .filter_by(subkeyword_active=True)
        .one()
    )
    

    【讨论】:

    • 我也最喜欢它。不添加更多代码,并且没有反斜杠。
    • 不确定这里额外缩进的合理性;我认为这个解决方案与仅缩进一次的悬挂线和尾随括号根本不一样。
    • 在我看来,双缩进在这里很有用,因为它在视觉上与普通缩进块不同。当被其他代码包围时,这更明显地表明它是一个包裹的单行。
    • 最佳答案,就使用括号而言。正如 Shanimal 在另一个答案中的评论中提到的,通过括号使用隐含的行继续实际上是 PEP 8 preferred 与继续字符 ``
    • 我更喜欢反斜杠。括号并不是所有情况的提示。例如,它不适用于赋值运算符。想象一下,你想在这个链中换行:foo.set_default('bar', {}).set_default('spam', {}).set_default('eggs', {})['lol'] = 'yeah'
    【解决方案2】:

    在这种情况下,换行符优先于开括号。随着方法名称变长以及方法开始接受参数,对这种风格的需求变得更加明显:

    subkeyword = Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word) \
                        .filter_by(subkeyword_company_id=self.e_company_id)          \
                        .filter_by(subkeyword_word=subkeyword_word)                  \
                        .filter_by(subkeyword_active=True)                           \
                        .one()
    

    PEP 8 旨在以一定程度的常识和对实用和美观的眼光来解释。愉快地违反任何导致丑陋或难以阅读的代码的 PEP 8 准则。

    话虽如此,如果您经常发现自己与 PEP 8 不一致,这可能表明存在超出您选择的空白的可读性问题 :-)

    【讨论】:

    • +1 反斜杠和在这种特殊情况下对齐链式过滤器。这种情况也出现在 Django 中,并且以这种方式最易读——但在 any 其他情况下,我觉得带括号的短语更好(不要遭受“我的反斜杠后面有空格吗?”问题)。也就是说,用括号括起来可以达到相同的效果——但它会让你在阅读 Python 的过程中进入 Lisp 阅读模式,我觉得这很不和谐。
    • 我看不出这个解决方案如何能够更好地应对“随着方法名称变得更长并且随着方法开始接受参数”而不是“包装在外部括号中”或“每个之后的换行符”打开paren和每个close paren之前”的解决方案。事实上,处理它更糟糕,因为(至少如此处所示)它需要对每条悬挂线进行更深的缩进。
    • 过滤器调用的缩进太多。一个制表符或 4 个空格在这里就足够了。还对齐了``...你按住那个空格键多少秒了?一般来说,我反对所有方式,这需要你像没有明天一样敲击那个空格键。
    • fwiw,PEP8 读到“包装长行的首选方法是在括号、方括号和大括号内使用 Python 隐含的行延续。长行可以通过将表达式包装在括号中来分隔多行。这些应该优先使用反斜杠来续行。” —Python.org 继续讨论反斜杠何时合适
    • 对 PEP8 的很好参考!对齐所有 .filter 调用的一个烦人问题是,如果您将 subkeyword 更改为 sub_keyword,您现在必须修复 每一行 的缩进,因为您更改了变量名.当样式实际上阻碍了可维护性时就不好了......
    【解决方案3】:

    我个人的选择是:

    子关键字 = Session.query( Subkeyword.subkeyword_id, subkeyword.subkeyword_word, )。过滤( subkeyword_company_id=self.e_company_id, subkeyword_word=subkeyword_word, subkeyword_active=真, )。一()

    【讨论】:

    【解决方案4】:

    只需存储中间结果/对象并在其上调用下一个方法, 例如

    q = Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word)
    q = q.filter_by(subkeyword_company_id=self.e_company_id)
    q = q.filter_by(subkeyword_word=subkeyword_word)
    q = q.filter_by(subkeyword_active=True)
    subkeyword = q.one()
    

    【讨论】:

    • 这适用于查询之类的东西,但作为一般模式,我不太确定。例如,当像 team_members = soup.find(class_='section team').find_all('ul').find_all('li') 这样在 Beautiful Soup 中进行链接时,每个 .find(...) 调用的返回值还不符合 team_members 的含义。
    • @TaylorEdmiston 当然,您可以为部分结果使用不同的名称。 section = soup.find(class_='section team')team_members = section.find_all('ul').find_all('li') 之类的东西。
    【解决方案5】:

    这与其他人提供的解决方案有点不同,但我最喜欢它,因为它有时会导致漂亮的元编程。

    base = [Subkeyword.subkeyword_id, Subkeyword_word]
    search = {
        'subkeyword_company_id':self.e_company_id,
        'subkeyword_word':subkeyword_word,
        'subkeyword_active':True,
        }
    subkeyword = Session.query(*base).filter_by(**search).one()
    

    这是构建搜索的好方法。浏览一个条件列表以从您的复杂查询表单(或基于字符串的关于用户正在查找的内容的推断)中挖掘,然后将字典分解到过滤器中。

    【讨论】:

    • 很好的解决方案。 ?️ 虽然没有明确回答这个问题,但它揭示了程序员有时如何尝试解决他们不需要的痛苦和问题(这里:不可读的过滤器链)。这种痛苦是更深层次原因的症状信号(通常在概念上、结构上、设计问题,甚至命名上)。例如。你的字典search 具有predicatematcher 的意义,在概念上类似于QBE:它匹配所有属性)就像在SQL WHERE .. AND .. 中一样。
    【解决方案6】:

    根据Python Language Reference
    您可以使用反斜杠。
    或者干脆打破它。如果括号未配对,python 不会将其视为一行。在这种情况下,以下行的缩进无关紧要。

    【讨论】:

      【解决方案7】:

      你似乎在使用 SQLAlchemy,如果是这样,sqlalchemy.orm.query.Query.filter_by() 方法需要多个关键字参数,所以你可以这样写:

      subkeyword = Session.query(Subkeyword.subkeyword_id,
                                 Subkeyword.subkeyword_word) \
                          .filter_by(subkeyword_company_id=self.e_company_id,
                                     subkeyword_word=subkeyword_word,
                                     subkeyword_active=True) \
                          .one()
      

      但这样会更好:

      subkeyword = Session.query(Subkeyword.subkeyword_id,
                                 Subkeyword.subkeyword_word)
      subkeyword = subkeyword.filter_by(subkeyword_company_id=self.e_company_id,
                                        subkeyword_word=subkeyword_word,
                                        subkeyword_active=True)
      subkeuword = subkeyword.one()
      

      【讨论】:

      • +1 用于 SQLAlchemy filter_by() 提示。这个例子很好,但我经常使用 filter() 代替它只接受 1 个条件。
      【解决方案8】:

      我喜欢将参数缩进两个块,语句缩进一个块,如下所示:

      for image_pathname in image_directory.iterdir():
          image = cv2.imread(str(image_pathname))
          input_image = np.resize(
                  image, (height, width, 3)
              ).transpose((2,0,1)).reshape(1, 3, height, width)
          net.forward_all(data=input_image)
          segmentation_index = net.blobs[
                  'argmax'
              ].data.squeeze().transpose(1,2,0).astype(np.uint8)
          segmentation = np.empty(segmentation_index.shape, dtype=np.uint8)
          cv2.LUT(segmentation_index, label_colours, segmentation)
          prediction_pathname = prediction_directory / image_pathname.name
          cv2.imwrite(str(prediction_pathname), segmentation)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-10
        • 2017-06-20
        • 2022-11-16
        • 1970-01-01
        • 2015-08-07
        相关资源
        最近更新 更多