def isBig(x):
if x > 4:
return 'Apple'
else:
return 'orange'
これは機能します:
if isBig(y): return isBig(y)
これは動作しません:
if fruit = isBig(y): return fruit
2つ目が機能しないのはなぜですか!? 1ライナーが欲しいです。ただし、最初の関数はTWICEを呼び出します。
関数を2回呼び出さずに、1つのライナーにする方法は?
他の誰かが私の古い「割り当てと設定」クックブックレシピをすでに指摘しているのがわかります。これは、最も単純なバージョンでは次のように要約されます。
class Holder(object):
def set(self, value):
self.value = value
return value
def get(self):
return self.value
h = Holder()
...
if h.set(isBig(y)): return h.get()
ただし、これは主に、Pythonと割り当てがif
またはwhile
で直接サポートされている言語との間の音訳を容易にすることを目的としていました。カスケードでのチェックアンドリターン、それははるかに完全に異なることをする方が良いです:
hundreds = isBig, isSmall, isJuicy, isBlah, ...
for predicate in hundreds:
result = predicate(y)
if result: return result
またはのようなもの
return next(x for x in (f(y) for f in hundreds) if x)
述語が満たされない場合にStopIteration例外を取得しても問題がない場合、または
return next((x for x in (f(y) for f in hundreds) if x)), None)
None
が、述語が満たされない場合の適切な戻り値である場合など。
ほとんどの場合、Holder
トリック/非イディオムを使用する(または希望する)ことは、別のよりPythonicなアプローチを探すことを示唆する「デザインの匂い」です-Holder
が正当化されるのは、まさに私が設計した特殊なケースです。つまり、PythonコードとPython以外のコード(音訳している)の間で密接な対応を維持したい場合です。 Pythonの参照アルゴリズムで、よりPythonの形式にリファクタリングする前に最初に動作させたい、またはPythonに音訳されるプロトタイプとして記述している) C++、C#、Javaなど、効果的に機能するようになったら)。
_Python 3.8
_から始まり、 代入式(PEP 572) (_:=
_演算子)の導入により、条件値(isBig(y)
)をキャプチャできるようになりました。条件の本体内で再利用するための変数(x
)として:
_if x := isBig(y): return x
_
Pythonでは、代入(fruit = isBig(y)
)は式ではなくステートメントであるため、ワンライナーは機能しません。 C、C++、Perl、およびその他の無数の言語では、これは式であり、if
またはwhile
など、好きなものに入れることができますが、Pythonではできません。 of Pythonこれは(あなたがしようとしているように)「賢い」コードを書くにはあまりにも簡単に誤用(または悪用)されたと考えました。
また、あなたの例はかなりばかげています。 isBig()
は常にtrue
と評価されます。これは、falseの文字列は空の文字列(""
)なので、この場合、if
ステートメントは役に立ちません。私はそれがあなたがやろうとしていることの単なる単純化だと思います。これを行うだけです:
tmp = isBig(y)
if tmp: return tmp
それは本当にもっと悪いですか?
PHP(またはC)でコーディングする場合は、コーディングします。メソッドを別の言語に強制しようとしないでください。
Python(私の意見では)の背後にある基本的な信条の1つは、その読みやすさです。次を使用する必要があります。
_fruit = isBig(y)
if fruit: return fruit
_
また、isXXX()
の使用は非常に奇妙です。通常、ブール値を返すために使用されます。特に、IF
ステートメントで使用しているこの場合。
これは意図的な言語設計のために機能しませんが、 このトリック を使用してこの決定を回避することができます
問題は、割り当て操作がブール値を持っていると評価できないことです。 if
ステートメントは、ブール値を評価できることに依存しています。例えば、
>>> fruit = 'Apple'
>>> bool(fruit = 'Apple')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/Users/jem/<ipython console> in <module>()
TypeError: 'fruit' is an invalid keyword argument for this function
>>> bool('a')
True
ジェネレーターを使用できます。
def ensure(x):
if x: yield x
for fruit in ensure(isBig(y)):
return fruit