Pythonでのint()の直感に反する動作


83

int(number)はフローリング型変換であることがドキュメントに明確に記載されています。

int(1.23)
1

また、int(string)は、文字列が整数リテラルである場合にのみintを返します。

int('1.23')
ValueError

int('1')
1

その特別な理由はありますか?あるケースでは関数がフロアになり、他のケースではフロアにならないのは直感に反します。

回答:


123

特別な理由はありません。Pythonは、PerlやJavascriptなどの言語で、特に初心者にとって問題のよく知られた原因である暗黙の変換を実行しないという一般原則を単に適用しています。

int(some_string)文字列を整数形式に変換する明示的な要求です。この変換の規則では、文字列に有効な整数リテラル表現が含まれている必要があると指定されています。int(float)floatを整数に変換する明示的な要求です。この変換のルールは、フロートの小数部分が切り捨てられることを指定しています。

インタプリタint("3.1459")を返すためには3、文字列を暗黙的にfloatに変換する必要があります。Pythonは暗黙的な変換をサポートしていないため、代わりに例外を発生させることを選択します。


type(3)を返します<type int>。ただし、Pythonはについて文句を言いませんfloat("3")。Pythonは暗黙的に文字列をintに変換してからfloatに変換しませんか?
franksands

いいえ。「3」は、プログラムリテラルとしては整数として解釈されますが、有効な浮動小数点値です。整数変換は必要ありません。
holdenweb

75

これはほぼ間違いなく、Zen ofPythonの3つの原則を適用する場合です

明示的の方が暗黙的です。

[...]実用性は純粋さを打ち負かす

エラーは黙って通過してはいけません

ある割合の時間、誰かint('1.23')がユースケースに対して間違った変換を呼び出しており、floatまたはdecimal.Decimalその代わりに何かを望んでいます。このような場合、間違った値を黙って与えるよりも、修正できる即時エラーを取得する方が明らかに優れています。

あなたがいる場合にはないint型に、明示的にそれを通すことによってそうすることが自明であることを切り詰めたいfloatまず、その後の1呼び出しintroundtruncfloorまたはceil必要に応じてを。これにより、コードがより自己文書化intfloatれ、丸められた値必要なものであることを明確にすることで、仮想のサイレント切り捨て呼び出しを後で変更することを防ぎます。


これらの原則は、禅が策定されるずっと前に採用されたと思いますが、どちらにしても、両者は調和しているように見えます。
holdenweb 2018年

17

思考実験が役立つ場合があります。

  • 動作A:int('1.23')エラーで失敗します。これは既存の動作です。
  • 動作B:エラーなしでint('1.23')生成され1ます。これがあなたが提案していることです。

動作Aを使用すると、動作Bの効果を得るのは簡単で簡単int(float('1.23'))です。代わりに使用してください。

一方、動作Bの場合、動作Aの効果を取得することは非常に複雑です。

def parse_pure_int(s):
    if "." in s:
        raise ValueError("invalid literal for integer with base 10: " + s)
    return int(s)

(そして、上記のコードを使用しても、誤って処理されるコーナーケースがないことを完全に確信しているわけではありません。)

したがって、行動Aは行動Bよりも表現力があります。

考慮すべきもう1つのこと'1.23'は、浮動小数点値の文字列表現です。'1.23'整数への変換には、概念的には2つの変換(文字列から浮動小数点、整数)が含まれますがint(1.23)int('1')それぞれに1つの変換のみが含まれます。


編集:

そして実際、上記のコードは扱えないだろうとコーナーケースがあります1e-2し、1E-2両方あまりにも浮動小数点値をしています。


明確にするために:あなたや他の人が述べたように、それはただ危険なので、私は行動Bを提案しません。現在の解決策よりも優れた解決策が存在するかどうかはわかりません。1つのオプションは、関数に異なる名前を付けることですが、それは入力するものが多いだけです。int(1.23)が失敗し、int(float-with-no-decimal-places)のみが整数を返すという明白な解決策は、動的に型指定された言語では意味がありません。
StefanS 2016年

1
コーナーケースはint('123E-2')またはかもしれませんint('1L')
Jared Goguen 2016年

11

簡単に言えば、それらは同じ機能ではありません。

  • int(decimal)は 'floorとして動作します。つまり、10進数部分をノックオフし、int'として返します。
  • int(string)は次のように動作します 'このテキストは整数を記述し、それを変換してintとして返します'。

これらは、整数を返す同じ名前の2つの異なる関数ですが、異なる関数です。

'int'は短くて覚えやすく、各タイプに適用されるその意味はほとんどのプログラマーにとって直感的であるため、彼らはそれを選択しました。

それらが同じまたは組み合わせた機能を提供しているという意味はありません。それらは単に同じ名前を持ち、同じタイプを返します。それらは「floorDecimalAsInt」および「convertStringToInt」と簡単に呼ぶことができますが、覚えやすく(99%)直感的で混乱がほとんど発生しないため、「int」を選択しました。

「4.5」などの小数点を含むテキストの整数としてテキストを解析すると、ほとんどのコンピューター言語でエラーがスローされ、ほとんどのプログラマーはエラーをスローすると予想されます。これは、テキスト値が整数を表していないためです。彼らは誤ったデータを提供しています


2
では、なぜ2つの「異なる関数」が同じ名前を持っているのでしょうか。いくつかの禅のナンセンスの違反のように聞こえます。
hobbs 2016年

名前は2つの異なる機能に意味があり、簡潔だからです。10進数(floor)を整数化し、文字列をint(変換)に変換します

技術的にintは、それがタイプ(およびそれに組み込まれているタイプ)であることを覚えておくと役立つ場合があります。その作成者(__new__)は、いくつかの可能な引数タイプを取ります。各タイプの動作は明確に定義されています。
holdenweb 2016年

述べたように、この答えは単に間違っています。int事実ではないが、その機能タイプ、である__new__および__init__それぞれ適切に対処する方法文字列またはfloat型の引数を取り、。この型は2つの引数型を異なる方法で処理すると言う方が正確ですが、1つしかありませんint
holdenweb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.