「is」演算子が整数で予期せず動作する


509

Pythonで以下が予期しない動作をするのはなぜですか?

>>> a = 256
>>> b = 256
>>> a is b
True           # This is an expected result
>>> a = 257
>>> b = 257
>>> a is b
False          # What happened here? Why is this False?
>>> 257 is 257
True           # Yet the literal numbers compare properly

Python 2.5.2を使用しています。いくつかの異なるバージョンのPythonを試してみると、Python 2.3.3は上記の99〜100の動作を示しているようです。

上記に基づいて、「小さな」整数は大きな整数とは異なる方法で格納され、is演算子が違いを認識できるようにPythonが内部的に実装されていると仮定できます。なぜ漏れやすい抽象化なのか?2つの任意のオブジェクトを比較して、それらが数値であるかどうか事前にわからない場合にそれらが同じであるかどうかを確認するためのより良い方法は何ですか?


1
ここを見てください >現在の実装では、すべての整数オブジェクトの配列が保持されています> -5から256までの整数。
user5319825

2
これはCPython固有の実装の詳細であり、未定義の動作です。注意して使用してください
ospider

回答:


393

これを見てください:

>>> a = 256
>>> b = 256
>>> id(a)
9987148
>>> id(b)
9987148
>>> a = 257
>>> b = 257
>>> id(a)
11662816
>>> id(b)
11662828

これは、Python 2のドキュメント「プレーンな整数オブジェクト」で見つけたものです(Python 3でも同じです)。

現在の実装では、-5〜256のすべての整数の整数オブジェクトの配列が保持されます。その範囲でintを作成すると、実際には既存のオブジェクトへの参照が返されます。したがって、1の値を変更できるはずです。この場合のPythonの動作は定義されていないと思われます。:-)


46
その範囲(-5、256)がどのように選択されたかを誰かが知っていますか?(0、255)または(-255、255)であっても、それほど驚くことはありませんが、-5から始まる262の数値の範囲は驚くほど任意です。
Woodrow Barlow

6
@WoodrowBarlow:-5は一般的なネガティブプレースホルダーを取得するためのヒューリスティックにすぎないと思います。0..255は、単一バイト値の配列をカバーします。謎めいたのは256ですが、整数をバイトに(バイトから)から(逆に)組み立てるためのものだと思います。
デイビスヘリング

3
私が理解していることから、範囲は複数のプロジェクト(および複数の言語)で一般的に使用される値を調べることによって選択されました。
トニーサフォーク66

9
reddit.com/r/Python/comments/18leav/…によると、範囲は[-5,100]でした。これは、バイト値の全範囲を含むように拡張されました-おそらく一般的な数値であるため、256です。
mwfearnley 2018

2
@Ashwaniは、あなたのコメントの2年前に投稿されたコメントの隣にあるコメントを読んでみてください。質問に対する答えが見つかります。
jbg

116

Pythonの「is」演算子は整数で予期しない動作をしますか?

まとめ-強調してみましょう:整数の比較には使用しないでくださいis

これはあなたが期待すべき行動ではありません。

代わりに、==!=を使用して、それぞれ等価性と不等価性を比較します。例えば:

>>> a = 1000
>>> a == 1000       # Test integers like this,
True
>>> a != 5000       # or this!
True
>>> a is 1000       # Don't do this! - Don't use `is` to test integers!!
False

説明

これを知るには、次のことを知る必要があります。

まず、何をしisますか?比較演算子です。ドキュメントから:

演算子isis notオブジェクトIDのテスト:x is yxとyが同じオブジェクトである場合にのみtrueです。x is not y逆の真理値を生成します。

したがって、以下は同等です。

>>> a is b
>>> id(a) == id(b)

ドキュメントから:

id オブジェクトの「アイデンティティ」を返します。これは整数(または長整数)であり、このオブジェクトの存続期間中、一意で一定であることが保証されています。重複しないライフタイムを持つ2つのオブジェクトは、同じid()値を持つ場合があります。

CPython(Pythonのリファレンス実装)のオブジェクトのIDがメモリ内の場所であるという事実は、実装の詳細であることに注意してください。Pythonの他の実装(JythonやIronPythonなど)では、の別の実装を簡単に作成できますid

それで、ユースケースはis何ですか? PEP8について説明します:

のようなシングルトンとの比較Noneは、常にisまたはを 使用して行う必要がありますis not。等価演算子は使用しないでください。

質問

次の質問(コード付き)を尋ねて述べます。

Pythonで以下が予期しない動作をするのはなぜですか?

>>> a = 256
>>> b = 256
>>> a is b
True           # This is an expected result

期待した結果ではありません。なぜそれが予想されるのですか?それだけで評価整数であることを意味256両方によって参照a及びb整数の同じインスタンスです。整数はPythonでは不変であるため、変更できません。これはコードに影響を与えません。それは期待されるべきではありません。これは単なる実装の詳細です。

しかし、おそらく、値が256であると述べるたびに、メモリ内に新しい個別のインスタンスが存在しないことをうれしく思います。

>>> a = 257
>>> b = 257
>>> a is b
False          # What happened here? Why is this False?

値が257メモリ内にある整数の2つの個別のインスタンスがあるように見えます。整数は不変なので、メモリを浪費します。たくさん無駄になっていないことを願いましょう。私たちはおそらくそうではありません。ただし、この動作は保証されません。

>>> 257 is 257
True           # Yet the literal numbers compare properly

まあ、これは、Pythonの特定の実装がスマートである必要があり、必要でない限り、メモリ内に冗長な値の整数を作成しないようです。あなたはPythonの参照実装、つまりCPythonを使用していることを示しているようです。CPythonに適しています。

CPythonがこれをグローバルに実行できれば、さらに安価に(ルックアップにコストがかかるため)できれば、おそらく別の実装がそうなるかもしれません。

ただし、コードへの影響については、整数が整数の特定のインスタンスであるかどうかを気にする必要はありません。そのインスタンスの値が何であるかを気にするだけでよく、そのためには通常の比較演算子、つまりを使用し==ます。

is

isid2つのオブジェクトのが同じであることを確認します。CPythonでは、idはメモリ内の場所ですが、別の実装では他の一意に識別される番号である可能性があります。コードでこれを言い換えると:

>>> a is b

と同じです

>>> id(a) == id(b)

なぜisそれを使いたいのでしょうか?

これは、2つの非常に長い文字列の値が等しいかどうかをチェックするなど、非常に高速なチェックです。しかし、それはオブジェクトの一意性に適用されるため、そのため、使用例が限られています。実際、ほとんどの場合None、これを使用してシングルトン(メモリ内の1か所に存在する唯一のインスタンス)をチェックします。それらを混同する可能性がある場合、他のシングルトンを作成する可能性があります。これをで確認するis場合がありますが、これらは比較的まれです。以下に例を示します(Python 2および3で動作します)。例

SENTINEL_SINGLETON = object() # this will only be created one time.

def foo(keyword_argument=None):
    if keyword_argument is None:
        print('no argument given to foo')
    bar()
    bar(keyword_argument)
    bar('baz')

def bar(keyword_argument=SENTINEL_SINGLETON):
    # SENTINEL_SINGLETON tells us if we were not passed anything
    # as None is a legitimate potential argument we could get.
    if keyword_argument is SENTINEL_SINGLETON:
        print('no argument given to bar')
    else:
        print('argument to bar: {0}'.format(keyword_argument))

foo()

どのプリント:

no argument given to foo
no argument given to bar
argument to bar: None
argument to bar: baz

また、とを使用して、が引数なしで呼び出さisれた場合barとで呼び出された場合を区別できNoneます。これらはの主な使用例ですis- 整数、文字列、タプル、またはこれらのようなものの同等性をテストするために使用しないでください。


「これらは主な使用例ですis-整数、文字列、タプル、またはこれらのようなものの同等性をテストするために使用しないでください。」ただし、私は単純な状態マシンをクラスに統合しようとしています。状態は不透明な値であり、その唯一の観察可能なプロパティは同一または異なるものであるため、と比較するのは非常に自然に見えますis。インターン文字列を状態として使用する予定です。私は普通の整数を好んだでしょうが、残念ながらPythonは整数をインターンできません(これ0 is 0は実装の詳細です)。
Alexey

@Alexeyは列挙型が必要なように聞こえますか?stackoverflow.com/questions/37601644/...
アーロン・ホール

たぶん、ありがとう、それらを知りませんでした。これはIMOに答えるのに適切な追加となるでしょう。
Alexey

たぶん...もっと軽量な解決策になるあなたの答えでセンチネルのようなダムオブジェクトの数を使用して
アレクセイ

@Alexey列挙型はPython 3標準ライブラリにあります。これにより、コードが裸の歩哨よりも少し意味のあるものになる可能性があります。
アーロンホール

60

それは、2つのものが等しいかどうか、または同じオブジェクトかどうかを確認するかどうかによって異なります。

isそれらが等しいだけでなく、同じオブジェクトであるかどうかを確認します。小さな整数はおそらくスペース効率のために同じメモリ位置を指しています

In [29]: a = 3
In [30]: b = 3
In [31]: id(a)
Out[31]: 500729144
In [32]: id(b)
Out[32]: 500729144

==任意のオブジェクトの同等性を比較するために使用する必要があります。__eq__、および__ne__属性を使用して動作を指定できます。


OPが尋ねたように、任意のオブジェクトを比較する方法を実際に説明するのに賛成です!!
Joooeey

54

私は遅れていますが、あなたはあなたの答えでいくつかの情報源が欲しいですか 私はこれを紹介的な方法で試してみて、より多くの人々がフォローできるようにします。


CPythonの良いところは、このソースを実際に確認できることです。3.5リリースではリンクを使用しますが、対応する2.xのリンクを見つけるのは簡単です。

CPythonでは、新しいオブジェクトの作成を処理するC-API関数intPyLong_FromLong(long v)です。この関数の説明は次のとおりです。

現在の実装では、-5〜256のすべての整数の整数オブジェクトの配列が保持されますその範囲でintを作成すると、実際には既存のオブジェクトへの参照が返されます。したがって、値1を変更できるはずです。この場合のPythonの動作は定義されていないと思われます。:-)

(私の斜体)

あなたについて知らないが、私はこれを見て、考えます:その配列を見つけましょう!

CPythonを実装するCコードをいじっていない場合 を場合は、すべてがかなり整理され、読みやすくなっています。今回のケースでは、メインのソースコードディレクトリツリーのObjectsサブディレクトリを調べる必要があります

PyLong_FromLong 対処する longオブジェクトをため、内部を覗く必要があると推測するのは難しくありませんlongobject.c。中を見ると、混乱していると思うかもしれません。彼らはそうではありますが、恐れていませんが、私たちが探している機能は、230行目で、チェックアウトを待機していることです。これは小さめの関数なので、本体(宣言を除く)は簡単にここに貼り付けられます。

PyObject *
PyLong_FromLong(long ival)
{
    // omitting declarations

    CHECK_SMALL_INT(ival);

    if (ival < 0) {
        /* negate: cant write this as abs_ival = -ival since that
           invokes undefined behaviour when ival is LONG_MIN */
        abs_ival = 0U-(unsigned long)ival;
        sign = -1;
    }
    else {
        abs_ival = (unsigned long)ival;
    }

    /* Fast path for single-digit ints */
    if (!(abs_ival >> PyLong_SHIFT)) {
        v = _PyLong_New(1);
        if (v) {
            Py_SIZE(v) = sign;
            v->ob_digit[0] = Py_SAFE_DOWNCAST(
                abs_ival, unsigned long, digit);
        }
        return (PyObject*)v; 
}

さて、私たちはC マスターコードのhaxxorzではありませんではありませんが、馬鹿げているわけでもありませんCHECK_SMALL_INT(ival);。私たちはそれがこれと関係があることを理解できます。それをチェックしよう:

#define CHECK_SMALL_INT(ival) \
    do if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { \
        return get_small_int((sdigit)ival); \
    } while(0)

つまりget_small_int、値がival条件を満たす場合に関数を呼び出すマクロです。

if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS)

だから何ですNSMALLNEGINTSNSMALLPOSINTS?マクロ!ここにあります

#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS           257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS           5
#endif

したがって、私たちの状態はif (-5 <= ival && ival < 257)call get_small_intです。

次に、そのすべての栄光を見てみましょうget_small_intを見てみましょう(まあ、それは興味深いものがある場所なので、本体だけを見ていきます)。

PyObject *v;
assert(-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS);
v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);

さて、を宣言PyObjectし、前の条件が満たされていることを表明して、割り当てを実行します。

v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];

small_ints私たちが探していたその配列によく似ています。私たちはいまいましいドキュメントを読むだけで、ずっと知っていただろう!

/* Small integers are preallocated in this array so that they
   can be shared.
   The integers that are preallocated are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

うん、これは私たちの男です。新しいものを作りたいときint範囲内に[NSMALLNEGINTS, NSMALLPOSINTS)オブジェクトを作成する場合は、事前に割り当てられた既存のオブジェクトへの参照を取得するだけです。

参照は同じオブジェクトを参照しているため、発行 id()直接するか、そのis上でIDを確認すると、まったく同じものが返されます。

しかし、いつ割り当てられますか?

_PyLong_InitPythonでの初期化中に、喜んでforループに入ります:

for (ival = -NSMALLNEGINTS; ival <  NSMALLPOSINTS; ival++, v++) {

ソースをチェックしてループ本体を読んでください!

私の説明が今あなたにCのことを明確にしたことを願っています(明らかに意図的にしゃれた)。


しかし、257 is 257?調子はどう?

これは実際に説明する方が簡単です。私はすでに説明を試みました。これは、Pythonがこのインタラクティブなステートメントを単一のブロックとして実行するためです。

>>> 257 is 257

このステートメントのコンパイル中に、CPythonは2つの一致するリテラルがあることを確認し、同じPyLongObject表現を使用し257ます。自分でコンパイルしてその内容を調べると、これを確認できます。

>>> codeObj = compile("257 is 257", "blah!", "exec")
>>> codeObj.co_consts
(257, None)

CPythonが操作を実行すると、まったく同じオブジェクトが読み込まれます。

>>> import dis
>>> dis.dis(codeObj)
  1           0 LOAD_CONST               0 (257)   # dis
              3 LOAD_CONST               0 (257)   # dis again
              6 COMPARE_OP               8 (is)

だからis戻りTrueます。


37

あなたがソースファイルintobject.cをチェックインできるように、Pythonは効率のために小さな整数をキャッシュします。小さな整数への参照を作成するたびに、新しいオブジェクトではなく、キャッシュされた小さな整数を参照しています。257は短整数ではないため、別のオブジェクトとして計算されます。

==そのために使用することをお勧めします。


19

あなたの仮説は正しいと思います。id(オブジェクトのアイデンティティ)を試してみてください:

In [1]: id(255)
Out[1]: 146349024

In [2]: id(255)
Out[2]: 146349024

In [3]: id(257)
Out[3]: 146802752

In [4]: id(257)
Out[4]: 148993740

In [5]: a=255

In [6]: b=255

In [7]: c=257

In [8]: d=257

In [9]: id(a), id(b), id(c), id(d)
Out[9]: (146349024, 146349024, 146783024, 146804020)

数値<= 255はリテラルとして扱われ、上記のものは別の扱いになります。


1
これは、-5から+256までの値を表すオブジェクトが起動時に作成されるため、これらの値の使用はすべて、事前に作成されたオブジェクトに使用されます。その範囲外の整数へのほとんどすべての参照は、それらが参照されるたびに新しい内部オブジェクトを作成します。リテラルという用語の使用は紛らわしいと思います-リテラルは通常、コードの一部に入力された任意の値を指します-したがって、ソースコード内のすべての数値はリテラルです。
トニーサフォーク66

13

int、string、datetimeなどの不変値オブジェクトの場合、オブジェクトIDは特に役立ちません。平等について考える方がいいです。アイデンティティは本質的に値オブジェクトの実装の詳細です。それらは不変であるため、同じオブジェクトまたは複数のオブジェクトへの複数の参照を持つことの間に実質的な違いはありません。


12

既存の回答のいずれにも指摘されていない別の問題があります。Pythonは2つの不変値をマージすることが許可されており、事前に作成された小さなint値がこれが発生する唯一の方法ではありません。Pythonの実装では、これが保証されることは決してありませが、すべてが小さなintだけではありません。


一つには、そのような空のようないくつかの他の事前作成された値があるtuplestrbytes、と、いくつかの短い文字列は(CPythonと3.6で、それは256単一文字Latin-1の文字列です)。例えば:

>>> a = ()
>>> b = ()
>>> a is b
True

ただし、事前に作成されていない値でも同じになる場合があります。次の例を検討してください。

>>> c = 257
>>> d = 257
>>> c is d
False
>>> e, f = 258, 258
>>> e is f
True

そして、これはint値に限定されません:

>>> g, h = 42.23e100, 42.23e100
>>> g is h
True

明らかに、CPythonには事前に作成されたのfloat値が付属していません42.23e100。それで、ここで何が起こっているのですか?

CPythonのコンパイラは、のようないくつかの既知の不変の型の定数値をマージしますintfloatstrbytes、同じコンパイル単位インチ モジュールの場合、モジュール全体がコンパイル単位ですが、対話型インタープリターでは、各ステートメントは個別のコンパイル単位です。以来cd別の文で定義され、それらの値はマージされません。eおよびfは同じステートメントで定義されているため、それらの値はマージされます。


バイトコードを逆アセンブルすることで、何が起こっているかを確認できます。実行する関数を定義しe, f = 128, 128てから呼び出しdis.disてみると、定数値が1つあることがわかります。(128, 128)

>>> def f(): i, j = 258, 258
>>> dis.dis(f)
  1           0 LOAD_CONST               2 ((128, 128))
              2 UNPACK_SEQUENCE          2
              4 STORE_FAST               0 (i)
              6 STORE_FAST               1 (j)
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
>>> f.__code__.co_consts
(None, 128, (128, 128))
>>> id(f.__code__.co_consts[1], f.__code__.co_consts[2][0], f.__code__.co_consts[2][1])
4305296480, 4305296480, 4305296480

128実際にはバイトコードで使用されていなくても、コンパイラーが定数として格納していることに気付くかもしれません。これにより、CPythonのコンパイラーがどのように最適化を行っていないかがわかります。つまり、(空ではない)タプルは実際にはマージされません。

>>> k, l = (1, 2), (1, 2)
>>> k is l
False

関数内でそれを入れて、disそれは、と見co_consts-thereだ12、2つの(1, 2)同じタプルを共有1して2いるが同一ではなく、((1, 2), (1, 2))二つの異なる同じタプルを持つタプルを。


CPythonにはもう1つ最適化があります。それは文字列のインターンです。コンパイラ定数の折りたたみとは異なり、これはソースコードリテラルに限定されません。

>>> m = 'abc'
>>> n = 'abc'
>>> m is n
True

一方、それはstrタイプに限定され、内部ストレージの種類が "ascii compact"、 "compact"、または "legacy ready"のストリングに限定され、多くの場合、 "ascii compact"のみがインターンされます。


いずれにせよ、値が区別されなければならない、区別される、または区別できないルールは、実装ごとに、同じ実装のバージョン間で、場合によっては同じ実装の同じコピー上の同じコードの実行間でも異なります。 。

それを楽しむには、特定のPythonのルールを学ぶ価値があります。しかし、コードでそれらに依存する価値はありません。安全なルールは次のとおりです。

  • 2つの等しいが別々に作成された不変値が同一であると想定するコードを記述しないでください(使用しないでくださいx is y、使用しないでくださいx == y)。
  • 2つの等しいが別々に作成された不変値が異なると想定するコードを記述しないでください(使用しないでくださいx is not y、使用しないでくださいx != y)。

または、言い換えるisと、ドキュメント化されたシングルトン(などNone)またはコード内の1つの場所でのみ作成された(_sentinel = object()イディオムなど)のテストにのみ使用します。


より不可解なアドバイスは単純です:x is y比較に使用しないでくださいx == y。同様にx is not y、を使用しないでくださいx != y
smci

したがって、この質問を見て、なぜa=257; b=2571行にあるのかa is bTrue
Joe

8

is あるアイデンティティ等価演算子は(同じように機能しますid(a) == id(b))。2つの等しい数が必ずしも同じオブジェクトであるとは限らないということです。パフォーマンス上の理由から、いくつかの小さな整数は偶然メモ化されるため、同じになる傾向があります(これは不変なので可能です)。

===一方、PHPの演算子は、x == y and type(x) == type(y)Paulo Freitasのコメントに従って、等価性と型をチェックするものとして説明されています。これは一般的な数値には十分ですが、不合理な方法isで定義するクラスとは異なります__eq__

class Unequal:
    def __eq__(self, other):
        return False

PHPは、「組み込み」クラス(PHPではなくCレベルで実装されていることを意味します)でも同じことを可能にしています。少しばかげた使い方は、タイマーオブジェクトである可能性があります。タイマーオブジェクトは、数値として使用されるたびに値が異なります。Nowそれが評価であることをtime.time()私が知らないで示すのではなく、Visual Basicをエミュレートしたい理由はかなりあります。

グレッグ・ヒューギル(OP)は、「値の同等性ではなく、オブジェクトの同一性を比較することを目標としています。数値を除き、オブジェクトの同一性を値の同等性と同じように扱いたい」と1つの明確なコメントをしました。

これを別の答えにする必要があります。物事を数値として分類するかしないかで、またはと比較するかどうかを選択する==必要があるためisです。CPythonはPyNumber_Checkを含むプロトコル番号を定義しますが、これはPython自体からはアクセスできません。

私たちがisinstance知っているすべての数値タイプを使用してみることができますが、これは必然的に不完全になります。タイプモジュールにはStringTypesリストが含まれていますが、NumberTypesは含まれていません。Python 2.6以降、組み込みの数値クラスには基本クラスnumbers.Numberがありますが、同じ問題があります。

import numpy, numbers
assert not issubclass(numpy.int16,numbers.Number)
assert issubclass(int,numbers.Number)

ちなみに、NumPyは低い数値の個別のインスタンスを生成します。

この質問のバリエーションに対する答えは実際にはわかりません。理論的にはctypesを使用してを呼び出すことができると思いますPyNumber_Checkが、その関数でさえ議論されており、移植性はありません。今のところ、何をテストするかについてあまり気にする必要はありません。

結局のところ、この問題は、Scheme number?Haskellの 型クラス Num ような述語を持つ型ツリーが元々Pythonになかったことが原因です。is値の等価性ではなく、オブジェクトの同一性をチェックします。PHPにもカラフルな歴史があり、PHP5ではオブジェクト===としてisのみ動作し、PHP4では動作しないようです。これは、言語間(バージョンを含む)を移動する際の痛みの増大です。


4

文字列でも発生します:

>>> s = b = 'somestr'
>>> s == b, s is b, id(s), id(b)
(True, True, 4555519392, 4555519392)

今、すべてがうまくいくようです。

>>> s = 'somestr'
>>> b = 'somestr'
>>> s == b, s is b, id(s), id(b)
(True, True, 4555519392, 4555519392)

それも予想されます。

>>> s1 = b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> s1 == b1, s1 is b1, id(s1), id(b1)
(True, True, 4555308080, 4555308080)

>>> s1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> s1 == b1, s1 is b1, id(s1), id(b1)
(True, False, 4555308176, 4555308272)

今は予想外です。


これに起こった-奇妙なことに同意した。だから私はそれで遊んだ、そしてそれはまだ奇妙だ-スペースに関連して。たとえば、文字列'xx'は期待どおりであり、そのままですが'xxx'、そうで'x x'はありません。
Brian

2
スペースがないとシンボルのように見えるからです。名前は自動的にインターンされるためxx、Pythonセッションのどこかに名前が付けられている場合、その文字列はすでにインターンされています。名前に似ている場合は、それを行うヒューリスティックがある可能性があります。数値と同様に、これは不変であるため実行できます。docs.python.org/2/library/functions.html#intern guilload.com/python-string-interning
Yann Vernier

3

Python 3.8の新機能:Pythonの動作の変更

アイデンティティーチェック(および)が特定のタイプのリテラル(文字列、int など )で使用されると、コンパイラーはSyntaxWarningを生成します。これらはCPythonで誤って機能することがよくありますが、言語仕様では保証されていません。警告では 、代わりに等価テスト(および)を使用するようユーザーにアドバイスしています。isis not==!=

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.