私はpythonを学ぼうとしていますが、ニースで短いコードに出くわしましたが、まったく意味がありません
コンテキストは:
def fn(*args):
return len(args) and max(args)-min(args)
私はそれが何をしているのかわかりますが、なぜpythonはこれを行うのですか-つまり、True/Falseではなく値を返しますか?
10 and 7-2
5を返します。同様に、とを変更すると、機能が変更されます。そう
10 or 7 - 2
10を返します。
これは合法/信頼できるスタイルですか、またはこれに関する落とし穴はありますか?
まず、2つの論理演算子and
およびor
の2つの動作を要約します。これらのイディオムは、以下の説明の基礎となります。
and
最初のFalsy値があればそれを返し、そうでなければ式の最後の値を返します。
or
最初のTruthy値がある場合はそれを返し、そうでない場合は式の最後の値を返します。
動作も ドキュメント にまとめられています。特にこの表では:
オペランドに関係なくブール値を返す唯一の演算子はnot
演算子です。
声明
len(args) and max(args) - min(args)
very パイソン 「args
が空でない場合、max(args) - min(args)
の結果を返す」という簡潔な(そしておそらく間違いなく読みにくい)方法、そうでなければ0
を返します。一般的に、それはif-else
式のより簡潔な表現です。例えば、
exp1 and exp2
(大まかに)次のように変換する必要があります。
r1 = exp1
if not r1:
r1 = exp2
または、同等に、
r1 = exp1 if exp1 else exp2
exp1
およびexp2
は、任意のpythonオブジェクト、またはオブジェクトを返す式です。ここでの論理and
およびor
演算子の使用を理解するための鍵は、それらが演算またはブール値を返すことに制限されていないことを理解することです。ここでは、真偽値を持つオブジェクトをテストできます。これには、int
、str
、list
、dict
、Tuple
、set
、NoneType
、およびユーザー定義オブジェクトが含まれます。短絡ルールも適用されます。
しかし、真実とは何ですか?
条件式で使用した場合にオブジェクトがどのように評価されるかを示します。 @Patrick Haughは、真実を この投稿 でうまくまとめています。
「偽」である以下を除き、すべての値は「真」と見なされます。
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[]
-空のlist
{}
-空のdict
()
-空のTuple
''
-空のstr
b''
-空のbytes
set()
-空のset
range(0)
のような空のrange
- の対象
obj.__bool__()
はFalse
を返しますobj.__len__()
は0
を返します「真の」値は、
if
またはwhile
ステートメントによって実行されるチェックを満たします。bool
の値True
およびFalse
と区別するために、「truthy」および「falsy」を使用します。
and
の仕組み私たちは、OPの質問に基づいて、これらのインスタンスでこれらの演算子がどのように機能するかについての議論のセグエとして構築します。
定義を持つ関数を与えられた
def foo(*args): ...
ゼロ個以上の引数のリストで最小値と最大値の差を返すにはどうすればよいですか?
最小値と最大値を見つけるのは簡単です(組み込み関数を使用してください!)。ここでの唯一の障害は、引数リストが空になる可能性があるコーナーケースを適切に処理することです(たとえば、foo()
の呼び出し)。 and
演算子のおかげで、両方を1行で実行できます。
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
and
が使用されるため、最初の式がTrue
の場合、2番目の式も評価する必要があります。最初の式が真であると評価された場合、戻り値はalways2番目の式の結果であることに注意してください。最初の式が偽と評価された場合、返される結果は最初の式の結果です。
上記の関数で、foo
が1つ以上の引数を受け取る場合、len(args)
は0
(正の数)よりも大きいため、返される結果はmax(args) - min(args)
です。 OTOH、引数が渡されない場合、len(args)
は0
(Falsy)であり、0
が返されます。
この関数を記述する別の方法は次のとおりです。
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
または、より簡潔に、
def foo(*args):
return 0 if not args else max(args) - min(args)
もちろん、これらの関数はいずれも型チェックを実行しないため、提供された入力を完全に信頼しない限り、do notはこれらの構造の単純さに依存します。
or
の仕組みor
の動作を、不自然な例を使って同様に説明します。
定義を持つ関数を与えられた
def foo(*args): ...
9000
を介してすべての数値を返すには、foo
をどのように完成させますか?
ここでは、or
を使用してコーナーケースを処理します。 foo
を次のように定義します。
def foo(*args):
return [x for x in args if x > 9000] or 'No number over 9000!'
foo(9004, 1, 2, 500)
# [9004]
foo(1, 2, 3, 4)
# 'No number over 9000!'
foo
は、リストのフィルタリングを実行して、9000
上のすべての数値を保持します。そのような番号が存在する場合、リストの内包表記の結果は空ではないリストであり、Truthyであるため、返されます(ここでは動作中の短絡)。そのような番号が存在しない場合、リストcompの結果は[]
であり、これは偽です。したがって、2番目の式が評価され(空ではない文字列)、返されます。
条件を使用して、この関数を次のように書き換えることができます。
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
前と同じように、この構造はエラー処理に関してより柔軟です。
Python Docs から引用
and
もor
restrictもvalueおよびtypeFalse
およびTrue
に戻りますが、代わりに最後に評価された引数。これは時々便利です。たとえば、s
が空の場合にデフォルト値に置き換える必要がある文字列である場合、式s or 'foo'
は目的の値を生成します。
したがって、これがPythonがブール式を評価するために設計された方法であり、上記のドキュメントはなぜそうしたのかについての洞察を与えてくれます。
ブール値を取得するには、型キャストするだけです。
return bool(len(args) and max(args)-min(args))
短絡。
例えば:
2 and 3 # Returns 3 because 2 is Truthy so it has to check 3 too
0 and 3 # Returns 0 because 0 is Falsey and there's no need to check 3 at all
同じことがor
にも当てはまります。つまり、検出されるとすぐにTruthyの式を返します。残りの式の評価は冗長です。 。
ハードコアTrue
またはFalse
を返す代わりに、PythonはTruthyまたはFalsey、とにかくTrue
またはFalse
に評価されます。式をそのまま使用できますが、それでも機能します。
TruthyおよびFalseyを確認するには、 Patrick Haughの答え
andおよびorはブール論理を実行しますが、比較すると実際の値の1つを返します。 andを使用すると、値は左から右にブールコンテキストで評価されます。 、 ''、[]、()、{}、およびNoneはブールコンテキストではfalseです。それ以外はすべて真実です。
ブールコンテキストですべての値がtrueの場合、andは最後の値を返します。
>>> 2 and 5
5
>>> 2 and 5 and 10
10
ブール値のコンテキストでいずれかの値がfalseの場合andは、最初のfalse値を返します。
>>> '' and 5
''
>>> 2 and 0 and 5
0
だからコード
return len(args) and max(args)-min(args)
argsがある場合はmax(args)-min(args)
の値を返します。それ以外の場合は、len(args)
を返します(0)。
これは合法/信頼できるスタイルですか、またはこれに関する落とし穴はありますか?
これは正当であり、最後の値が返される 短絡評価 です。
良い例を提供します。引数が渡されない場合、関数は0
を返します。また、コードは引数が渡されない特別なケースをチェックする必要はありません。
これを使用する別の方法は、空のリストのような可変プリミティブへのデフォルトのNone引数です:
def fn(alist=None):
alist = alist or []
....
真ではない値がalist
に渡されると、デフォルトで空のリストになります。これは、if
ステートメントと mutable default argument pitfall を避ける便利な方法です
はい、いくつかの落とし穴があります。
fn() == fn(3) == fn(4, 4)
まず、fn
が0
を返す場合、パラメーターなしで呼び出されたか、1つのパラメーターで呼び出されたか、複数の等しいパラメーターで呼び出されたかはわかりません。
>>> fn()
0
>>> fn(3)
0
>>> fn(3, 3, 3)
0
fn
はどういう意味ですか?そして、Pythonは動的言語です。 fn
が何をするのか、その入力はどうあるべきか、出力はどのように見えるべきかはどこにも指定されていません。したがって、関数に正しく名前を付けることが本当に重要です。同様に、引数はargs
と呼ばれる必要はありません。 delta(*numbers)
またはcalculate_range(*numbers)
は、関数が何をすべきかをよりよく説明する場合があります。
最後に、論理and
演算子は、引数なしで呼び出された場合に関数が失敗するのを防ぐことになっています。ただし、一部の引数が数値ではない場合でも失敗します。
>>> fn('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> fn(1, '2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: '>' not supported between instances of 'str' and 'int'
>>> fn('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
「許可よりも許しを求める方が簡単」という原則 に従って関数を記述する方法を次に示します。
def delta(*numbers):
try:
return max(numbers) - min(numbers)
except TypeError:
raise ValueError("delta should only be called with numerical arguments") from None
except ValueError:
raise ValueError("delta should be called with at least one numerical argument") from None
例として:
>>> delta()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in delta
ValueError: delta should be called with at least one numerical argument
>>> delta(3)
0
>>> delta('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta(3, 4.5)
1.5
>>> delta(3, 5, 7, 2)
5
delta
が引数なしで呼び出されたときに例外を発生させたくない場合は、それ以外では不可能な値を返すことができます(例:-1
またはNone
):
>>> def delta(*numbers):
... try:
... return max(numbers) - min(numbers)
... except TypeError:
... raise ValueError("delta should only be called with numerical arguments") from None
... except ValueError:
... return -1 # or None
...
>>>
>>> delta()
-1
これは合法/信頼できるスタイルですか、またはこれに関する落とし穴はありますか?
この質問に、合法で信頼できるだけでなく、極めて実用的でもあることを付け加えたいと思います。以下に簡単な例を示します。
>>>example_list = []
>>>print example_list or 'empty list'
empty list
したがって、あなたは本当にあなたの利点でそれを使うことができます。簡潔にするために、これは私がそれを見る方法です:
Or
演算子
Pythonのor
演算子は、最初のTruth-y値または最後の値を返し、停止します
And
演算子
Pythonのand
演算子は、最初のFalse-y値または最後の値を返し、停止します
舞台裏
Pythonでは、0を除くすべての数値はTrue
として解釈されます。したがって、次のように言います。
0 and 10
次と同じです:
False and True
明らかにFalse
です。したがって、0を返すことは論理的です
簡単な方法で理解するには、
AND:if first_val is False return first_val else second_value
例えば:
1 and 2 # here it will return 2 because 1 is not False
しかし、
0 and 2 # will return 0 because first value is 0 i.e False
および=>誰かが偽の場合、それは偽になります。両方が真の場合、それだけが真になります
または:if first_val is False return second_val else first_value
理由は、firstがfalseの場合、2がtrueかどうかをチェックするからです。
例えば:
1 or 2 # here it will return 1 because 1 is not False
しかし、
0 or 2 # will return 2 because first value is 0 i.e False
または=>誰かが偽の場合、真になります。したがって、2つの値が何であろうと最初の値がfalseの場合。そのため、可能な限り2番目の値を返します。
誰かが真実なら、それは真実になります。両方が偽の場合、偽になります。