[解決済み] and "と "or "はブール値以外ではどのように作用するか?
質問
私はpythonを学ぼうとしていて、いくつかのコードに出くわしました。
という文脈でした。
def fn(*args):
return len(args) and max(args)-min(args)
何をやっているかはわかりますが、なぜpythonはこのようなことをするのでしょうか。つまり、True/Falseではなく、値を返すのでしょうか。
10 and 7-2
は5を返します。同様に、andをorに変更すると、機能が変更されます。そのため
10 or 7 - 2
10を返します。
これは合法的で信頼できるスタイルですか、それともこれには何か問題があるのでしょうか?
どのように解決するのですか?
TL;DR
まず、2つの論理演算子の挙動をまとめることから始めます。
and
と
or
. これらの慣用句は、以下の議論の基礎となります。
<ブロッククオート
and
Falsyの値があれば最初の値を返し、なければ式の最後の の値を返します。
or
真実の値があれば最初の値を、そうでなければ式の最後の の値を返す。
また、この挙動をまとめたものが ドキュメント で、特にこの表にまとめられています。
オペランドに関係なくブール値を返す唯一の演算子は
not
演算子です。
真偽判定と評価
ステートメント
len(args) and max(args) - min(args)
は
は非常に
ピトニック
という簡潔な(そして間違いなく読みにくい)言い方をします。
args
が空でない場合、その結果を返します。
max(args) - min(args)
を返し、それ以外の場合は
0
. 一般に、これは
if-else
をより簡潔に表現します。例えば
exp1 and exp2
と訳すべきでしょう(大雑把ですが)。
r1 = exp1
if r1:
r1 = exp2
あるいは、同等に
r1 = exp2 if exp1 else exp1
同様に
exp1 or 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)は、真理性を次のようにうまくまとめています。
この投稿
.
以下の値を除き、すべての値は "truthy" とみなされます。 "falsy"です。
-
None
-
False
-
0
-
0.0
-
0j
-
Decimal(0)
-
Fraction(0, 1)
-
[]
- 空のlist
-
{}
- 空のdict
-
()
- 空のtuple
-
''
- 空のstr
-
b''
- 空のbytes
-
set()
- 空のset
-
空
range
のようにrange(0)
-
オブジェクト
-
obj.__bool__()
が返すFalse
-
obj.__len__()
リターン0
-
真実の値("truthy")は
if
または
while
といったステートメントがあります。 と区別するために "truthy" と "falsy" を使用します。
bool
という値で区別しています。
True
と
False
.
どのように
and
の働き
OPの質問をもとに、このような場合にこれらの演算子がどのように作用するかについて議論します。
という定義の関数があるとします。
def foo(*args): ...
ゼロ個以上の引数を持つリストにおいて、最小値と最大値の差分を返すには の差を返すにはどうしたらよいでしょうか?
最小値と最大値を見つけるのは簡単です(内蔵の関数を使いましょう!)。ここでの唯一の難点は、引数リストが空である可能性があるというコーナーケースを適切に処理することです (たとえば
foo()
). のおかげで一行で両方できるようになりました。
and
演算子のおかげで一行で済みます。
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
以降
and
が使われている場合、2つ目の式も評価されなければなりません。
True
. 最初の式が真であると評価された場合、返り値は
常に
の結果である。
二番目の式
. 最初の式がFalsyと評価された場合、返される結果は最初の式の結果である。
上の関数では、もし
foo
は一つ以上の引数を受け取ります。
len(args)
よりも大きい
0
(正の数)であるため、返される結果は
max(args) - min(args)
. 乙は、引数が渡されない場合は
len(args)
は
0
であり、ファルシーである
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)
もちろん、これらの関数は型チェックを一切行わないので、提供された入力を完全に信頼しない限りは を使用しないでください。 はこれらの構成の単純さに頼ってはいけません。
どのように
or
の働き
の動作を説明します。
or
の動作を、同じような方法で工夫した例で説明します。
という定義の関数が与えられると
def foo(*args): ...
どのように
foo
を超える全ての数を返すために9000
?
私たちは
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 なので、それが返されます (ここでは短絡的に動作しています)。そのような数が存在しない場合、リスト内包の結果は
[]
であり、これはFalsyです。したがって、2番目の式が評価され(空でない文字列)、返されます。
条件式を使うと、この関数を次のように書き直すことができます。
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
前述と同様に、この構造はエラー処理の面でより柔軟性があります。
関連
-
[解決済み] argparseによるブーリアン値のパース
-
[解決済み] 関数デコレータを作成し、それらを連鎖させるには?
-
[解決済み] 割り当て後にリストが予期せず変更されました。その理由と防止策を教えてください。
-
[解決済み] 列の値に基づいてDataFrameから行を選択するにはどうすればよいですか?
-
[解決済み] 環境変数の値にアクセスする方法
-
[解決済み] pipでPythonの全パッケージをアップグレードする方法
-
[解決済み] NaN値をチェックするにはどうすればよいですか?
-
[解決済み】大文字と数字を含むランダムな文字列の生成
-
[解決済み】ビットシフト(bit-shift)演算子とは、どのようなもので、どのように機能するのですか?
-
[解決済み] PythonによるCURLの代替
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] googletransがエラー 'NoneType' オブジェクトに 'group' 属性がない、と言って動かなくなった。
-
[解決済み] Djangoで2つの日付の間を選択する
-
[解決済み] PythonでSelenium WebDriverを使用してテキストを取得する方法
-
[解決済み] 2つの弦をインターリーブさせる最もピトニックな方法
-
[解決済み] Pythonで関数の引数として辞書の項目を渡すには?重複
-
[解決済み] Pythonで文字列が数字で始まるかどうかを判断するには?
-
[解決済み] Seleniumから要素の属性を取得するには?
-
[解決済み] SQLAlchemy が db に送る SQL コマンドのデバッグ(表示)
-
[解決済み] PILでPNG画像を文字列に書き出すには?
-
[解決済み] 2ウェイ/リバースマップ[重複]について