Pythonで連鎖メソッドの行を分割する方法は?


137

私は次のコードの行を持っています(命名規則を非難しないでください、それらは私のものではありません):

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文字に制限するためのより良い考えはありません。それを壊すより良い方法はありますか(できればバックスラッシュなし)?

回答:


255

追加の括弧を使用できます:

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()
    )

私も一番好きです。コードを追加せず、バックスラッシュなし。
Juliusz Gonera、2011年

22
ここで余分なインデントを正当化する理由がわかりません。この解決策は、垂れ下がった線が1回だけインデントされており、後続の括弧がまったくない場合でも同様に読み取れると思います。
Carl Meyer

4
私の意見では、二重インデントは通常のインデントされたブロックと視覚的に区別できるため、ここでは便利です。他のコードで囲まれている場合、これはラップされた単一行であることをより明確にします。
2016年

1
括弧を使用するという点では、最良の回答です。Shanimalの別の回答のコメントで述べたように、括弧を介した暗黙の行継続の使用は、実際には継続文字よりもPEP 8が優先されます ''
kevlarr

私はバックスラッシュを好む。括弧はすべての状況のヒントではありません。例として、割り当て演算子では機能しません。あなたがこのチェーンで行を分割したい想像:foo.set_default('bar', {}).set_default('spam', {}).set_default('eggs', {})['lol'] = 'yeah'
loutre

56

これは、括弧を開くよりも行継続文字の方が望ましい場合です。このスタイルの必要性は、メソッド名が長くなり、メソッドが引数を取るようになるにつれて、より明白になります。

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に頻繁に対立する場合は、選択した空白文字を超える読みやすさの問題があることを示している可能性があります:-)


2
この特定のケースでは、バックスラッシュを+1し、チェーンフィルターを整列させます。この状況はジャンゴで発生だけでなく、この方法で最も読みやすいです-しかし、中に任意の括弧で囲まれたフレーズは、(「空白が私のバックスラッシュの後にあるのでしょうか?」問題に悩まされない)よりも優れているように、他の状況私は感じています。とは言え、括弧を括弧で囲んでも同じ効果が得られますが、Pythonを読んでいる途中でLispの読み取りモードになります。
zxq9 2013年

11
この方法が「メソッド名が長くなり、メソッドが引数を取り始めるにつれて」「外側の括弧で囲む」または「開いた括弧ごとと閉じた括弧の前で改行する」よりもうまく対処できる方法がわかりません。ソリューション。実際には(少なくともここに示すように)ぶら下がっている線ごとにはるかに深いインデントが必要であるため、その処理はより悪いです。
Carl Meyer

1
フィルター呼び出しにはインデントが多すぎます。ここでは1つのタブまたは4つのスペースで十分です。また、「...の位置合わせは、そのスペースキーを何秒押しましたか?一般に私はすべての方法に反対します。その方法では、明日がないようにスペースキーを叩く必要があります。
Zelphir Kaltstahl 2016年

2
fwiw、PEP8は、「長い行をラップする好ましい方法は、かっこ、角かっこ、中かっこ内でPythonの暗黙の行継続を使用することです。長い行は、括弧で式をラップすることにより、複数行に分割できます。これらは、バックスラッシュを使用するよりも優先して使用する必要があります。行継続のため。」— Python.orgバックスラッシュが適切な場合があるか
どう

PEP8への大きな参照!ここですべての.filter呼び出しを調整することの厄介な問題は、に変更subkeywordした場合、変数名を変更しただけsub_keywordすべての行のインデントを修正する必要があることです。スタイルが実際に保守性を妨げている場合は良くない...
kevlarr 2017年

15

私の個人的な選択は:

サブキーワード= Session.query(
    Subkeyword.subkeyword_id、
    Subkeyword.subkeyword_word、
).filter_by(
    subkeyword_company_id = self.e_company_id、
    subkeyword_word = subkeyword_word、
    subkeyword_active = True、
)。1()

1
複数のパラメーターが渡される場合は同意しますが、0または1のパラメーターが一般的である場合は見苦しく見えます。例:gist.github.com/andybak/b23b6ad9a68c7e1b794d
Andy Baker

1
ええ、そのスタイルには、(他のスタイルのように)退化したケースがあります。私は開いているすべての括弧を壊しません。どれも私を幸せにしませんが、いくつかのケースがあります:gist.github.com/pkoch/8098c76614765750f769
pkoch

12

中間結果/オブジェクトを保存して、次のメソッドを呼び出すだけです。

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()

10
これはクエリのようなものでうまく機能しますが、一般的なパターンとして、私はよくわかりません。たとえば、のようなBeautiful Soupでチェーンするteam_members = soup.find(class_='section team').find_all('ul').find_all('li')場合、各.find(...)呼び出しからの戻り値はteam_membersまだの意味に適合しません。
テイラーエドミストン

1
@TaylorEdmistonもちろん、部分的な結果には異なる名前を付けることができます。section = soup.find(class_='section team')およびのようなものteam_members = section.find_all('ul').find_all('li')
Jeyekomon、

4

Python言語リファレンスによると
、バックスラッシュを使用できます。
または単にそれを壊します。ブラケットがペアになっていない場合、Pythonはそれを行として扱いません。そして、そのような状況下では、次の行のインデントは重要ではありません。


4

他の人が提供するものとは少し異なるソリューションですが、時々気の利いたメタプログラミングにつながるため、私のお気に入りです。

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()

これは、検索を構築するための素晴らしいテクニックです。複雑なクエリフォーム(またはユーザーが探しているものについての文字列ベースの演繹)からマイニングする条件のリストを調べ、辞書をフィルターに分解します。


1

SQLAlchemyを使用しているsqlalchemy.orm.query.Query.filter_by()ようですが、trueの場合、メソッドは複数のキーワード引数を取るため、次のように記述できます。

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()

SQLAlchemy filter_by()ヒントの+1。この例には適していますが、1つの条件のみを受け入れるfilter()をよく使用します。
Juliusz Gonera、2011年

1

次のように、引数を2つのブロックでインデントし、ステートメントを1つのブロックでインデントするのが好きです。

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.