Python 中為何沒有數字到字元串的自動轉換?

print " I am " + 10 + "years old " will raise error . but it is ok in many other languages. Java,eg.


哪有那麼複雜……Py是有隱式轉換的,只不過這個隱式轉換里沒有把str和int的__add__帶進去罷了。

所謂的隱式轉換其實都是事先實現好了轉換方法,並且以默認形式帶進了內置庫里。int是有__str__的,你調用.format的時候總不需要你手動轉換一下,只是在str類的__add__里與其他類型的加法運算遇到就拋異常。

你要覺得不爽,完全可以重寫str類的__add__,從此實現用+來連接任何類型,反正別的能輸出的類型至少都有個__str__或者__eval__。想用單獨的運算符也行啊,貌似str還沒有__del__呢,不如就用這個?

至於為什麼沒有默認寫進buildin里,大概因為Py最初目的就是通用語言而不是web專屬,考慮語言習慣與消歧義比較重要,出錯了拋異常也好抓;另一方面,大概是一般沒人覺得這有什麼不妥,不然怎麼連個PEP都沒人提?畢竟主流語言設計里都認為format形式更優雅,js都在加format string。

不過居然還有蹦噠出來喊Php用.來結合字元運算是設計優秀……類成員調用強行-&>也是無限的優越性?C++你說老,那往新了看Swift、C#又如何?Php獨出來個.你可以說這叫重視字元串處理,畢竟Php最初就是以一個模板合成腳本的形式出現的。

至於py3里print由語句變為函數,一來是str類型本質發生改變,二來是便於添加功能(ending、encode之類的)、patch和擴展,不信翻翻PEP,總之是跟字元串與數字運算的隱式轉換沒一毛錢關係……


因為 Python 禁止跨類型的 (+),它只有

  1. (+): int * int → int

  2. (+): string * string → string

而沒有

  • (+): int * str → ?

JavaScript 和 PHP 都允許 (+) 做跨類型的計算,JavaScript 使用 num * str → str,PHP 使用 num * str → num。


The Zen of Python裡面有這麼一句嘛

Explicit is better than implicit.

Python程序員的常見錯誤 裡面也解釋了這句話

只有在數字類型中才存在類型轉換

在Python中,一個諸如123+3.145的表達式是可以工作的——它會自動將整數型轉換為浮點型,然後用浮點運算。但是下面的代碼就會出錯了:

S = "42"

I = 1

X = S + I # 類型錯誤

這同樣也是有意而為的,因為這是不明確的:究竟是將字元串轉換為數字(進行相加)呢,還是將數字轉換為字元串(進行聯接)呢?在Python中,我們認為「明確比含糊好」(即,EIBTI(Explicit is better than implicit)),因此你得手動轉換類型:

X = int(S) + I # 做加法: 43

X = S + str(I) # 字元串聯接: "421"

對於 Python 這種強類型語言來說,沒有數字到字元串的自動轉換是很正常的事情

像其他可以實現數字到字元串的自動轉換的語言有多可怕,給你上個圖看看(圖是人人上扒來的,不完全切合題意,不過也可以參考)


看了半天,發現沒一個說的對的。

數字到字元串的轉換是用to_bytes函數來完成的;

相反,字元串到數字是用reduce來做到的。

如果短的話,那麼用chr和ord函數。

怎麼可能自動轉換呢?

比如數字32轉換成字元串,是一個空格。

例子如下:

&>&>&> (328983943).to_bytes(4, "big")
b"x13x9bxe5x87"

&>&>&> reduce(lambda x, y: x*256+y, b"x13x9bxe5x87")
328983943

大家可以看到,數字和字元串的轉化有長度,位元組序等參數需要確定,怎麼可能自動轉呢?

---------------------------------------------------------

回答樓主的答案,你需要的不是數字轉字元串,你需要的格式化一個數字

所以正確答案是:

age = 10
print (f" I am {age} years old ")

非常漂亮,清楚,明白,比前面的啰嗦的加號不知道高到哪裡去了, 不是嗎?

另外補充一點,使用加號速度非常的慢,非常的慢;如果你用的加號稍微多點的話,就更慢了


我要答一下了,很多人都很好奇,很多語言中中特別好用隱式轉換:

&

在Python中無法以這種方式辦到,必須手動將整數型結果轉換為字元串類型:

print "Result:"+str(1+2+3)

@HG Zhao 認為是:

數字和字元串相加存在歧義,默認可以是int轉str也可以是str轉int。

@HG Zhao 用了一個PHP的例子,輸出結果是3,他認為這種輸出是有歧義的。

&

沒錯,是存在歧義,但是這種歧義是Python特有的PHP中並不存在,因為PHP中"+"符號唯一的作用就是相加,所以1+2結果必然是3。

這是因為在PHP的語言設計中,echo中的"+"符號是數學運算符,它並沒有字元串連接符的作用,所以是將字元串隱式轉換為整數。

如果你在PHP中用

&

輸出結果則是"12",因為PHP中echo里的"."的作用就是連接兩個字元串,所以這樣處理結果肯定是"12",顯然PHP中是沒有歧義的。並且運算符是有優先順序的,「+」運算符優先順序高於字元串連接符"."。

PHP在語言設計上確實要比Python好上不少,Python因為設計失誤,把數字運算符"+"用來充當字元串連接符,所以如果做隱式轉換,會有歧義問題的出現從而難以處理。1+"2"到底要等於"12"還是3呢?當然也可以沒有歧義地單方面直接指定結果就是12,但是這對於初學Python的人來說肯定會造成困惑——為什麼1+"2"會是"12"而不是3?

這是Python的一個特點,並不是它不想做這種隱式轉換,而是實際上因為設計失誤,做不到。

如果Python一開始的設計,就把print作為一個函數處理,例如我隨便寫一個函數printf來在Python2下代替print:

def printf(*arg):
for i in xrange(len(arg)):
if not isinstance(arg[i], str):
print str(arg[i]),
else:
print arg[i],
printf("There are &<", 2**32, "> possibilities!")

那麼就可以以不定數量參數的形式向printf傳值,將所有參數作為字元串處理,不再使用數學運算符"+",將轉換放到黑盒內進行,從而實現無歧義的隱式轉換,就像PHP的echo那樣實現字元串和整數直接連接成新的字元串了。

printf("1",2) #輸出12

顯然,Python2中也是支持通過不定數量參數形式傳值實現在黑盒中隱式轉換int為str的,但是因為Python2中的print不是一個函數,而是一個語言構造器,所以Python2中這個方式並不為人所熟知。

但是這種轉換依舊只支持print時其他類型隱式轉換到str類型,依舊是同一原因,這和Java一致。

public class test
{
public static void main(String[] args)
{
int a = 1;
char b = "2";
//String c = a + b;//這句並不能執行
System.out.println("Result: " + a + b);
//只能在print時將所有類型強制轉換為String,Result: 12
}
}

這個失誤有多嚴重呢?嚴重到了Python不惜分裂版本也要修復!

如果我們打開What』s New In Python 3.0,很輕易就可以發現,Python3中的print不再是一個語言構造器而是一個函數了,並且非常高興地在第一頁最開頭的部分把這個當成Python 3.0的新賣點拿出來炫耀了:

很多人不理解Python為什麼要在3中將print改成函數形式,實際上有一部分原因就是為了修復這個設計上的失誤——選擇了數學運算符"+"來作為字元串連接符,而沒有選擇其他無用字元。

那麼不實現隱式轉換?當然不行。

要實現無歧義的隱式轉換隻能通過不定數量參數傳遞實現,但是這個傳遞應該傳遞給函數而不是語言構造器。

Python2

Python3

這裡要吐槽一下Python粉:「因為Python是一門嚴謹的強類型語言,所以它不支持隱式轉換!」——其實是支持的,無論2還是3。除了彙編,幾乎所有語言,都會有算術轉換、賦值轉換,輸出轉換看情況有或者沒有。還有一些特別喜歡黑自己不懂的語言的只會不多的編程語言的人(例如黑非常熱門的PHP)。起碼用七八種編程語言,起碼每種都寫個幾千行的小項目,熟悉一下各種語言的語法,之後再來談優劣——你連用都沒用過就黑得飛起?一門語言能流行無非就是不得不用、好用、性能高這麼幾個因素。

或者少發「XX編程語言就是比XX編程語言好」這種東西,每種編程語言的特性都有它適用的領域。

最後回應一下其他高票答案里的這張圖,PHP的比較有兩種:帶隱式轉換的比較、類型值完全相等嚴格比較。

也就是"=="和"===",如果你用:

var_dump(512=="0512");

結果當然是true,因為這個比較本來就是帶隱式轉換的。

如果不想要隱式轉換,你需要:

var_dump(512==="0512");
var_dump("aaa"===0);
var_dump("3.11"==="3.11000");
……

結果都是false。

這張圖就是對PHP特性一知半解就來黑PHP的典型——我TM PHP開了隱式轉換後怎麼就會隱式轉換了啊!如果你不想用隱式轉換,你應該使用不帶隱式轉換的「===」——這個比較符在幾乎所有PHP的入門文檔里都會提及。


Python是強類型的,因此不支持這個功能是很自然的,如果你使用Perl這樣弱類型的語言,就會支持你這麼做了。

其他的原因樓上都說的很多了,這種情況下比較好的方法,是使用格式化字元串或者字元串模板。


這個問題我覺得Python官方應該好好考慮,JAVA都支持的東西,你為什麼不支持?那個格式化輸出寫出來的代碼丑的一逼,看著就蛋疼……


靜態強類型效率高。

不過js不區分數字+和字元串+的自動轉換,可以玩自定義新類型對象的黑魔法:

({valueOf:function(){return 1;}}+{valueOf:function(){return 1;}})//猜猜等於幾?


題目本身只涉及強弱類型和字元串連接,不過有回答把問題擴展到 print/echo 以及運算符了。

先說強弱類型。

我的感受:

強類型語言認為不同類型的值是不同的,弱類型語言認為不同類型但相關的值在多數場合下是相同的。

所以在 Python 中,

1 != "1"

在 PHP 中,

1 == "1"

相對於強類型語言,弱類型語言給我的感覺是:

我不管你用什麼方式,總之要給我一個結果!

今天必須上線!

再說字元串連接。

如果我想連接的是字面值,如:

return "I am " + 10 + "years old."

我可以寫成這樣:

return "I am " + "10" + "years old."

問題解決了。

如果我想連接的是變數,如:

return "I am " + age + "years old."

那麼,age 是整數的情況就不說了。如果 age 不是整數,你希望程序怎樣執行?

return "I am 14.1421356237 years old."
return "I am inf years old."
return "I am nan years old."
return "I am None years old."
return "I am [25, 18, 23, 27] years old."
return "I am {"age": 18, "name": "Li Lei"} years old."

還是

raise TypeError
raise ValueError
raise 某種異常

如果運行時 age 不是整數,基本上這就是個 BUG。

如果可以容忍這個 BUG,在強類型語言 Python 中可以這樣寫:

return "I am " + str(age) + "years old."

如果不能容忍這個 BUG,在強類型語言 Python 中可以這樣寫(@Shawn Wu 說的 使用格式化字元串或者字元串模板):

return "I am {:d} years old.".format(age)

目的很清楚。

在弱類型語言 nohtyP 中,最短的寫法(也就是程序語言推薦的寫法?)是:

return "I am " + age + "years old."

又是這種感覺:

我不管你用什麼方式,總之要給我一個結果!

接著說運算符。

PHP 單獨拿出一個運算符 "." 用於字元串連接,而 Python、Java、C#、C++ 沒有這麼做。

我的理解是:

PHP 比其他語言更重視字元串處理。

這和語言早期設計的目的有關吧。

總結。

說白了就是 @康克由 引用的那句:

Explicit is better than implicit.

當然這要看場景。

最後說輸出函數/語句 print/echo。

這部分是回復 @林燦斌 的。

你說 Python 的 print 語句的問題

嚴重到了Python不惜分裂版本也要修復。

你指的 Python3 修復的問題是這個么?

不定數量參數傳遞應該傳遞給函數而不是語言構造器

我覺得 把 print 從語句改成函數 挺好的,減少了一條不必要的語法。雖然我覺得這和不定數量的參數沒什麼關係。

不過這個問題和字元串連接有關么?

如果Python一開始的設計,就把print作為一個函數處理……那麼就可以以不定數量參數的形式向printf傳值,將所有參數作為字元串處理,不再使用數學運算符"+",將轉換放到黑盒內進行,從而實現無歧義的隱式轉換。

字元串連接主要是用在 print 的參數里么?

字元串連接和輸出是兩個問題吧,為什麼要放在一起說?

如果 Python 有字元串連接的坑,為什麼要在 print 里修?

# // /* { & Python 又不是用來寫 CGI 的 & } */

況且你也說了,Python2 的 print 語句可以接收多個參數:

print 1, 2, 3

所以你說的這個問題和 print 是語句還是函數有什麼關係?

Python2中的print不是一個函數,而是一個語言構造器,所以Python2中這個方式並不為人所熟知。

print 語句傳遞多參數是否不為人所熟知,要看和誰比。

和 Python 3 的 print 函數比,可能確實是。

但和 PHP 的 echo 比呢?

&

這樣說來,print 語句除了佔用了一條本不需要存在的語法規則,還有其他問題么?嚴重么?


python 是一門強類型語言,強類型自然有強類型的好處。

我不是很了解Php和JavaScript,不過也用它們字元串和數字轉換的特性寫過不少利用漏洞的代碼。

坐等熟悉它們的人告訴你這種自動轉換有多坑。


推薦閱讀:

要用python研究股票需要安裝哪些庫?
為什麼 Python 的類不構成作用域(scope)?
這個python程序不能再簡化了吧?
python2.7,python3.3,對於小白,到底從哪個版本入手比較好?
在python中,怎樣計算list的累積和?不能用loop或者library的function。

TAG:Python | Python入門 |