聲明:以下所講機制,與Python不同版本的具體實現有關(implement specific)可能不同。Python中的數據類型Python中的數據類型,這可能是大家入門Python的第一節課。很簡單嘛,大家最常用的,int(包括long)、float、string、list、tuple、dict,加上bool和NoneType。但是這裡要重點說的,其實是可變類型和不可變類型。不可變(immutable):Number(包括int、float),String,Tuple可變(mutable):Dict,List,User-defined class
One is performance: knowing that a string is immutable means we can allocate space for it at creation time, and the storage requirements are fixed and unchanging. This is also one of the reasons for the distinction between tuples and lists.
Another advantage is that strings in Python are considered as 「elemental」 as numbers. No amount of activity will change the value 8 to anything else, and in Python, no amount of activity will change the string 「eight」 to anything else.
The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behaviour of Python in this case is undefined.
A Python program is constructed from code blocks. A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition. Each command typed interactively is a block. A script file (a file given as standard input to the interpreter or specified as a command line argument to the interpreter) is a code block. A script command (a command specified on the interpreter command line with the 『-c『 option) is a code block. The string argument passed to the built-in functions eval() and exec() is a code block.
A code block is executed in an execution frame. A frame contains some administrative information (used for debugging) and determines where and how execution continues after the code block』s execution has completed.
沒錯!跟我們猜的一樣!這就是原理的出處了!
代碼塊作為一個執行單元,一個模塊、一個函數體、一個類定義、一個腳本文件,都是一個代碼塊。在互動式命令行中,每行代碼單獨視作一個代碼塊。至此問題解決……了嗎?視作一個代碼塊,就意味著要把相同value的賦值指向相同的對象嗎?在此重複一下"is" operator behaves unexpectedly with non-cached integers中提到的實驗,並簡單翻譯結論。通過compile()函數和dis模塊的code_info()函數來檢測我們執行的命令的信息。示例:
The mode argument specifies what kind of code must be compiled; it can be "exec" if source consists of a sequence of statements, "eval" if it consists of a single expression, or "single" if it consists of a single interactive statement (in the latter case, expression statements that evaluate to something other than None will be printed).
至此…問題大概是解決了。(當然這是implement specific的事情,參見https://docs.python.org/3/reference/datamodel.html#objects-values-and-types中的CPython implementation detail)要說這道題教會了我什麼……那一定是:比較數值請一定一定用==不要用is!以上。參考資料:Immutable vs Mutable typesDesign and History FAQ"is" operator behaves unexpectedly with integersInteger Objects - Python 3.5.2 documentation"is" operator behaves unexpectedly with non-cached integers"is" operator behaves unexpectedly with floatsWhat is the difference between "a is b" and "id(a) == id(b)" in Python?Same value for id(float)Python Memory Management
以前就有過基本上同樣的問題,這是我以前的回答的傳送門:python idle 解釋和直接 python script.py 解釋有什麼差別? - RednaxelaFX的回答 - 知乎
但是 f 里的那個10.0呢?它是要等到MAKE_FUNCTION被調用的時候才會真正地初始化。做為 f 方法的返回值,它必然與我們之前所說的主&里的10.0不是同一個對象了。
本質上講,這是Python的一個設計缺陷(例如Java以一個文件為編譯單元,共享同一個常量池就會減輕這個問題。但如果跨文件使用 == 操作符,也會出現同樣的問題。仍然沒有解決這個問題。實際上,我自己也不知道該怎麼解決這個問題。)我們應該盡量避免 is 的這種用法。始終把 is 的用法限制在本文的第一個例子中。這樣相對會安全一些。
a = "hello"b = "hello"print a is b結果是True,如上所述,如果這三句寫到文件那也是True然而你把上面字元串換成"hello world"再在交互和文件中試試?再比如,id可以拿到一個對象的內存地址,但是看這個例子:&>&>&> str(12) is str(34)False&>&>&> id(str(12)) == id(str(34))True上面的False是顯然的,不同的兩個字元串,然而下面的結果為啥捏,呵呵……
------------------------------
很久以前在群里講課,講過這個問題:python對象的引用-python2群20130223群內授課記錄
我覺得,如果我開一個新問題【為什麼Python的第一個字母要大寫?】,估計也會有答主洋洋洒洒寫個幾萬字來解釋清楚。
簡單的來說呢,直接以文件的形式運行,編譯生成的pyc文件中只會有一個10.0的float的對象,運行時產量a和產量b都指向相同的此對象,當然a is b返回True。同理在命令行里執行 a, b=10.0 10.0 執行a is b也是返回True,倘若分開賦值,則會創建兩個float對象,a is b 就返回False。如果想要更深入的了解python,讀一讀python源碼分析,再看看源代碼,自然而然就知道了。