web-dev-qa-db-ja.com

'if'ステートメントで複数行の条件をスタイリングする

時々私はifsの長い条件を数行に分けます。これを行う最も明白な方法は次のとおりです。

  if (cond1 == 'val1' and cond2 == 'val2' and
      cond3 == 'val3' and cond4 == 'val4'):
      do_something

アクションは条件と調和するため、視覚的にはあまり魅力的ではありません。しかし、それは4つのスペースの正しいPython字下げを使用する自然な方法です。

今のところ私が使っている:

  if (    cond1 == 'val1' and cond2 == 'val2' and
          cond3 == 'val3' and cond4 == 'val4'):
      do_something

しかし、これはあまりきれいではありません。 :-)

他の方法をお勧めしますか。

562
Eli Bendersky

2番目の条件付き行に4つのスペースを使用する必要はありません。多分使う:

if (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

また、空白はあなたが思っているよりも柔軟性があることを忘れないでください。

if (   
       cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something
if    (cond1 == 'val1' and cond2 == 'val2' and 
       cond3 == 'val3' and cond4 == 'val4'):
    do_something

どちらもかなり醜いです。

かっこをなくすかもしれません( スタイルガイド はこれを推奨しません)。

if cond1 == 'val1' and cond2 == 'val2' and \
   cond3 == 'val3' and cond4 == 'val4':
    do_something

これは少なくともある程度の差別化をもたらします。

あるいは:

if cond1 == 'val1' and cond2 == 'val2' and \
                       cond3 == 'val3' and \
                       cond4 == 'val4':
    do_something

私は私が好むと思います:

if cond1 == 'val1' and \
   cond2 == 'val2' and \
   cond3 == 'val3' and \
   cond4 == 'val4':
    do_something

これは スタイルガイド です。(2010年以降)これは角かっこの使用を推奨しています。

604
Harley Holcombe

単純なANDまたはORの縮退の場合は、次のようにしました。

if all( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

if any( [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4'] ):

それは数文字を削り、その状態に微妙なものがないことを明確にしています。

108
S.Lott

誰か ここで垂直空白の使用を支持しなければならない! :)

if (     cond1 == val1
     and cond2 == val2
     and cond3 == val3
   ):
    do_stuff()

これにより、各条件が明確に見えます。より複雑な条件をより明確に表現することもできます。

if (    cond1 == val1
     or 
        (     cond2_1 == val2_1
          and cond2_2 >= val2_2
          and cond2_3 != bad2_3
        )
   ):
    do_more_stuff()

はい、わかりやすくするために、垂直不動産を少し取り引きしています。それはIMOの価値があります。

50
Kevin Little

これは私の個人的な見方です。長い条件は(私の考えでは)ブール値を返す関数/メソッドへのリファクタリングを示唆するコードの匂いです。例えば:

def is_action__required(...):
    return (cond1 == 'val1' and cond2 == 'val2'
            and cond3 == 'val3' and cond4 == 'val4')

さて、複数行の条件を見栄えよくする方法が見つかった場合は、おそらくそれらを使用して満足していることに気付き、リファクタリングをスキップします。

その一方で、彼らに私の審美的な感覚を混乱させることはリファクタリングの動機として働きます。

したがって、私の結論は、複数の回線条件が見苦しいように見えるはずであり、これはそれらを避けるための動機となります。

24
krawyoti

これはそれほど改善されませんが...

allCondsAreOK = (cond1 == 'val1' and cond2 == 'val2' and
                 cond3 == 'val3' and cond4 == 'val4')

if allCondsAreOK:
   do_something
23

私はひどく大きいif条件があるとき私はこのスタイルを好みます:

if (
    expr1
    and (expr2 or expr3)
    and hasattr(thingy1, '__eq__')
    or status=="HappyTimes"
):
    do_stuff()
else:
    do_other_stuff()
21
Deestan

andキーワードを2行目に移動し、条件を含むすべての行を4つではなく2つのスペースでインデントすることをお勧めします。

if (cond1 == 'val1' and cond2 == 'val2'
  and cond3 == 'val3' and cond4 == 'val4'):
    do_something

これがまさに私のコードでこの問題を解決する方法です。行の最初の単語としてキーワードを使用すると、条件が読みやすくなります。スペースの数を減らすと、条件とアクションがさらに区別されます。

19
DzinX

PEP 0008 (Pythonの公式スタイルガイド)それはこの問題についてささやかな長さでコメントしているので引用する価値があるようです:

ifステートメントの条件部分が複数行にまたがることを要求するのに十分な長さであるとき、2文字のキーワード(すなわちif)と単一のスペース、そして開き括弧の組み合わせが自然なものになることは注目に値します複数行の条件式の後続行を4スペースでインデントします。これは、ifステートメント内にネストされたインデント付きのコードスイートと視覚的に矛盾を生じさせる可能性があります。これも当然4つのスペースにインデントされます。このPEPは、そのような条件付き行をifステートメント内のネスト化されたスイートとさらに視覚的に区別する方法(またはそのかどうか)について明確な位置を取りません。この状況で許容されるオプションには、次のものが含まれますが、これらに限定されません。

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

上記の引用文の「に限定されない」に注意してください。スタイルガイドで提案されているアプローチのほかに、この質問に対する他の回答で提案されているアプローチのいくつかも受け入れられます。

10
Mark Amery

これが私がしていることです、 "all"と "any"がイテラブルを受け入れることを忘れないでください、それで私はただ長い条件をリストに入れて、そして "all"に仕事をさせます。

condition = [cond1 == 'val1', cond2 == 'val2', cond3 == 'val3', cond4 == 'val4']

if all(condition):
   do_something
5
zkanda

個人的には、長いif文に意味を追加するのが好きです。適切な例を見つけるにはコードを検索する必要がありますが、最初に頭に浮かぶ例を示します。多くの変数に応じて特定のページを表示したいという風変わりなロジックに出会ったとしましょう。

英語:「ログインしたユーザが管理者教師ではなく、ただの普通の教師であり、学生自身ではない場合...」

if not user.isAdmin() and user.isTeacher() and not user.isStudent():
    doSomething()

確かにこれはうまくいくかもしれませんが、ifステートメントを読むのは大変な作業です。意味のあるラベルにロジックを割り当ててはどうでしょうか。 「ラベル」は実際には変数名です。

displayTeacherPanel = not user.isAdmin() and user.isTeacher() and not user.isStudent()
if displayTeacherPanel:
    showTeacherPanel()

これはばかげているように思えるかもしれませんが、他の特定のパネルへのアクセス権がある場合にのみ教師パネルORを表示している場合に限り、別の項目を表示したいという別の条件があります。デフォルトでは

if displayTeacherPanel or user.canSeeSpecialPanel():
    showSpecialPanel()

ロジックを保存してラベルを付けるために変数を使用せずに上記の条件を書いてみてください。そして、非常に面倒で読みにくい論理ステートメントになってしまうだけでなく、繰り返しています。合理的な例外がありますが、覚えておいてください。

4
rgenito

私は自分の好みの解決策を見ていないことに驚きました、

if (cond1 == 'val1' and cond2 == 'val2'
    and cond3 == 'val3' and cond4 == 'val4'):
    do_something

andはキーワードなので、私のエディタで強調表示され、その下のdo_somethingとはかなり異なって見えます。

4
Marius Gedminas

@krawyotiが言ったことに加えて...長い条件は読みにくく理解しにくいので匂いがします。関数または変数を使用すると、コードが明確になります。 Pythonでは、式が "浮動"のように見えないように、縦方向のスペースを使用し、括弧を囲み、各行の先頭に論理演算子を配置することを好みます。

conditions_met = (
    cond1 == 'val1' 
    and cond2 == 'val2' 
    and cond3 == 'val3' 
    and cond4 == 'val4'
    )
if conditions_met:
    do_something

whileループのように、条件を複数回評価する必要がある場合は、ローカル関数を使用するのが最善です。

3
Apalala

「all」と「any」は、同じタイプのケースの多くの条件にとって素晴らしいものです。しかし、彼らは常にすべての条件を評価します。この例に示すように:

def c1():
    print " Executed c1"
    return False
def c2():
    print " Executed c2"
    return False


print "simple and (aborts early!)"
if c1() and c2():
    pass

print

print "all (executes all :( )"
if all((c1(),c2())):
    pass

print
3

(固定幅の名前は実際のコードを表しているのではなく、少なくとも私が遭遇する実際のコードではないので、私は識別子をわずかに変更しました。そして例の読みやすさを信じます。)

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4"):
    do_something

これは "and"と "or"(2行目の先頭にあることが重要です)にはうまく機能しますが、他の長い条件ではそれほど重要ではありません。幸いなことに、前者はより一般的なケースであるように思われますが、後者は一時変数で簡単に書き直されることが多いです。 (通常は難しいことではありませんが、書き換え時の "and"/"or"の短絡を保存するのは困難であるか、または明らかに判読不能になる可能性があります。)

この質問は あなたのC++についてのブログ投稿 から見つけたので、私のC++スタイルは同じであることを含めます。

if (cond1 == "val1" and cond22 == "val2"
and cond333 == "val3" and cond4444 == "val4") {
    do_something
}
3
Fred Nurk

平易で単純な、またpep8チェックを渡します:

if (
    cond1 and
    cond2
):
    print("Hello World!")

AndとOrの比較をうまく組み合わせることはめったにないので、最近ではall関数とany関数を好んで使用しています。また、Failing Earlyというジェネレーターの理解という利点もあります。

if all([
    cond1,
    cond2,
]):
    print("Hello World!")

ただ一つのイテラブルを渡すことを忘れないでください! N引数を渡すことは正しくありません。

注:anyは多くのor比較に似ています。allは多くのand比較に似ています。


これは、ジェネレータ内包表記とうまく組み合わさっています。例えば:

# Check if every string in a list contains a substring:
my_list = [
    'a substring is like a string', 
    'another substring'
]

if all('substring' in item for item in my_list):
   print("Hello World!")

# or

if all(
    'substring' in item
    for item in my_list
):
    print("Hello World!")

ジェネレーターの理解

3
ThorSummoner

条件と本体の間に追加の空白行を挿入し、残りを正規の方法で挿入しただけではどうなりますか

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):

    do_something

pS私はいつもスペースではなくタブを使います。微調整できません….

2

私が普段していることは、

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'
   ):
    do_something

このように、閉じ括弧とコロンは視覚的に私たちの状態の終わりを示します。

1
tomekwi

私もこれを行うためのまともな方法を見つけるのに苦労していたので、私はアイデアを思いついた(これは主に好みの問題なので、銀の弾丸ではない)。

if bool(condition1 and
        condition2 and
        ...
        conditionN):
    foo()
    bar()

私が見た他のものと比較して、このソリューションにはいくつかのメリットがあります。つまり、すべての条件を垂直に並べることができる4つのインデントスペース(bool)が追加されます。明快な方法です。これはブール演算子の短絡評価の利点も保持しますが、もちろん基本的には何もしない関数呼び出しのオーバーヘッドを追加します。あなたはその引数を返すどんな関数でもboolの代わりにここで使うことができると主張することができますが、私が言ったようにそれは単なるアイデアであり、そしてそれは最終的に好みの問題です。

私がこれを書いていて「問題」について考えていたとき、私は さらに別の という考えを思いついたので、関数呼び出しのオーバーヘッドを取り除きました。余計な括弧を使って複雑な条件に入ることを示してはどうでしょうか。さらに2つ言うと、ifステートメントの本体に対する副条件のニース2スペースのインデントを指定します。例:

if (((foo and
      bar and
      frob and
      ninja_bear))):
    do_stuff()

あなたがそれを見たとき、すぐに と言ってあなたの頭の中でベルが鳴るので、私はこういうのが好きです。「ねえ、ここで起こっている複雑なことがあります!」 。はい、括弧は読みやすさには役立たないことを知っていますが、これらの条件はめったに表示されないはずであり、表示されたら、とにかく慎重に停止して読む必要があります(complex) 。

とにかく、ここでは見たことがないもう2つの提案があります。これが誰かに役立つことを願っています:)

1

完全を期すために、他にいくつかランダムに考えてみましょう。それらがあなたのために働くならば、それらを使ってください。それ以外の場合は、おそらく他の何かを試した方がいいでしょう。

辞書を使ってこれを行うこともできます。

>>> x = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> y = {'cond1' : 'val1', 'cond2' : 'val2'}
>>> x == y
True

このオプションはもっと複雑ですが、便利かもしれません。

class Klass(object):
    def __init__(self, some_vars):
        #initialize conditions here
    def __nonzero__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
                self.cond3 == 'val3' and self.cond4 == 'val4')

foo = Klass()
if foo:
    print "foo is true!"
else:
    print "foo is false!"

Dunnoそれがあなたのために働くならば、それは考慮するべきもう一つの選択肢です。もう1つ方法があります。

class Klass(object):
    def __init__(self):
        #initialize conditions here
    def __eq__(self):
        return (self.cond1 == 'val1' and self.cond2 == 'val2' and
               self.cond3 == 'val3' and self.cond4 == 'val4')

x = Klass(some_values)
y = Klass(some_other_values)
if x == y:
    print 'x == y'
else:
    print 'x!=y'

最後の2つはテストしていませんが、それでも構いたいのであれば概念は十分に理解できるはずです。

(そして、記録として、これが一度だけの場合は、最初に提示した方法を使用するほうがおそらく賢明です。多くの場所で比較を行っている場合は、これらの方法によって読みやすさが向上します。あなたは彼らが一種のハッキーであるという事実についてそれほど気分が悪くないと思う。)

1
Jason Baker

あなたはそれを2行に分割することができます

total = cond1 == 'val' and cond2 == 'val2' and cond3 == 'val3' and cond4 == val4
if total:
    do_something()

あるいは、一度に1つの条件を追加することもできます。そのように、少なくともそれはifからクラッタを分離します。

1
SarcasticSully

私はこのスレッドが古いことを知っています、しかし私はいくつかのPython 2.7コードを持っています、そしてPyCharm(4.5)はまだこのケースについて不平を言います:

if foo is not None:
    if (cond1 == 'val1' and cond2 == 'val2' and
        cond3 == 'val3' and cond4 == 'val4'):
            # some comment about do_something
            do_something

PEP8の警告「次の論理行と同じインデントを持つ視覚的にインデントされた行」があっても、実際のコードは完全に問題ありませんか?それは「過度にインデントしているのではない?」

... Pythonが弾丸を噛んで中括弧だけで終わったほうがいいと思うことがあります。偶然の誤った字下げのせいで、何年間に何個のバグが偶然にもたらされたのだろうか。

1
SMGreenfield

Ifステートメントに複数の条件を付けたすべての回答者は、提示された問題と同じくらい醜いです。同じことをしてもこの問題は解決できません。

PEP 0008の答えでさえ反発的です。

これははるかに読みやすいアプローチです。

condition = random.randint(0, 100) # to demonstrate
anti_conditions = [42, 67, 12]
if condition not in anti_conditions:
    pass

私の言葉を食べてもらいたいですか?私はあなたが複数の条件を必要とし、私は文字通りこれを印刷してあなたの娯楽のためにそれを食べるつもりだと納得させなさい。

1
Stoff

私は@ zkandaの解決策は、ちょっとした工夫でうまくいくと思います。あなたがあなた自身のそれぞれのリストの中にあなたの条件と値を持っていたならば、あなたは比較をするためにリスト内包表記を使うことができました。

conditions = [1, 2, 3, 4]
values = [1, 2, 3, 4]
if all([c==v for c, v in Zip(conditions, values)]):
    # do something

このような文をハードコードしたいのであれば、読みやすさのために次のように書きます。

if (condition1==value1) and (condition2==value2) and \
   (condition3==value3) and (condition4==value4):

そして iand演算子 を使って別の解決策を捨てるだけです。

proceed = True
for c, v in Zip(conditions, values):
    proceed &= c==v

if proceed:
    # do something
1
ryanjdillon

以下のように書くことができるよりも、if&else条件がその中で複数のステートメントを実行しなければならない場合。私たちが持っているときはいつでも、その中に1つのステートメントを持つ例があります。

どうもありがとう。

#!/usr/bin/python
import sys
numberOfArgument =len(sys.argv)
weblogic_username =''
weblogic_password = ''
weblogic_admin_server_Host =''
weblogic_admin_server_port =''


if numberOfArgument == 5:
        weblogic_username = sys.argv[1]
        weblogic_password = sys.argv[2]
        weblogic_admin_server_Host =sys.argv[3]
        weblogic_admin_server_port=sys.argv[4]
Elif numberOfArgument <5:
        print " weblogic UserName, weblogic Password and weblogic Host details are Mandatory like, defalutUser, passwordForDefaultUser, t3s://server.domainname:7001 ."
        weblogic_username = raw_input("Enter Weblogic user Name")
        weblogic_password = raw_input('Enter Weblogic user Password')
        weblogic_admin_server_Host = raw_input('Enter Weblogic admin Host ')
        weblogic_admin_server_port = raw_input('Enter Weblogic admin port')
#enfelif
#endIf
0
Laxman G

私は長い条件があるとき、私はしばしば短いコード本体を持っていることに気付きます。その場合は、本体を二重インデントするだけです。

if (cond1 == 'val1' and cond2 == 'val2' and
    cond3 == 'val3' and cond4 == 'val4'):
        do_something
0
xorsyst

私はいつも使う:

if ((cond1 == 'val1' and cond2 == 'val2' and
     cond3 == 'val3' and cond4 == 'val4')):
    do_something()
0
Artur Gaspar

あなたの条件をリストにまとめて、そしてsmthをしなさい。好きです:

if False not in Conditions:
    do_something
0
psihodelia

これは別のアプローチです:

cond_list = ['cond1 == "val1"','cond2=="val2"','cond3=="val3"','cond4=="val4"']
if all([eval(i) for i in cond_list]):
 do something

これはまた、単にリストに別の条件を追加することによってif文を変更することなく、簡単に別の条件を追加することを容易にします。

cond_list.append('cond5=="val5"')
0
user1487551

このようなものが最も読みやすいオプションだと思います。

for pet in Zoo:
    cute = every_pet()
    furry = hair is 'over9000'
    small = size < min_size
    if cute and furry and small:
        return 'I need to feed it!'
0
Alex
  if cond1 == 'val1' and \
     cond2 == 'val2' and \
     cond3 == 'val3' and \
     cond4 == 'val4':
      do_something

またはこれがより明確であれば:

  if cond1 == 'val1'\
     and cond2 == 'val2'\
     and cond3 == 'val3'\
     and cond4 == 'val4':
      do_something

この場合、インデントが4の倍数になる理由はありません。 「開始区切り文字と位置合わせ」を参照してください。

http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Indentation#Indentation

0
Dima Tisnek