1. 程式人生 > >Python和Java的硬盤夜話

Python和Java的硬盤夜話

調用 一行 想想 c語言 熱點 簡潔 his 缺省值 目錄

這是一個程序員的電腦硬盤,在一個叫做“學習”的目錄下曾經生活著兩個小程序,一個叫做Hello.java,即Java小子;另外一個叫做hello.c ,也就是C老頭兒。

C老頭兒的命運比較悲催,程序員主人覺得C語言的指針太復雜了,內存管理太難了,實在是學不會,就放棄了,順便把它給刪除了!
Java小子很懷念它,因為C老頭兒雖然老派,但知識淵博,教了他不少東西。這天晚上,程序員心血來潮,決定跟Python混個臉熟,於是hello.py也入住了這個目錄。經過了短暫的寒暄,摸清了對方的虛實,他倆便看對方不順眼了。
他倆都明白一山不容二虎的道理,如果不能把對方趕走,就難逃被主人刪除,去垃圾回收站的悲催命運。

想到這一層,Python變率先發難, 它皮笑又不笑地拍拍Java的肩膀:“Java 老弟....”
沒想到Java立刻反擊:“誰是你老弟?你得叫我Java 大哥。”
Python楞了一下:“難道你不知道我是1991年出生的,比你還大4歲?”
Java哼了一聲:“雖然比我大,那你混得也不怎麽樣啊?”
Python說:“10多年前我也許混得不咋地,也許不如你,可此一時彼一時,隨著人工智能時代的到來,使用我的人越來越多了,不信你去看TIOBE排行榜,我的上升勢頭很猛烈啊。”
Java不屑地說:“切,增長到現在不還是老子一個零頭。”
Python 被激怒了,他決定先拿Java繁瑣的語法開刀,指著Java說:“看看你,一個HelloWorld都整得這麽麻煩,啰裏啰嗦。”

public class Hello
{
public static void main (String[] args)
{
System.out.println("Hello World!");
}
}

然後又指著自己說:“你看看我,多麽簡潔!”
print("Hello World!") Java 默不作聲,其實心裏也挺羨慕。

“還有我打開一個文件多簡單,你行嗎?”

f = open("c:\\tmp\\Hello.java","r")
print(f.read())
f.close()

提到IO,Java心中就有莫名的痛,自己的IO模塊設計得那麽優雅,可是人類為什麽就是不喜歡用呢?

他們老是說記不住到底該怎麽寫,看來是要改變下了。

看到Java 還是默不作聲,無法反擊,Python很得意,發揮宜將剩勇追窮寇的精神,抄起機關槍,繼續掃射:“看看我這個函數的缺省值,你有嗎?”

class Employee():
def __init__(self, name , gender="male" , maritalStatus="single" ):
self.name = name
self.gender = gender
self.maritalStatus = maritalStatus 

Java 一看到這段代碼,立刻就來了精神:“你的self和我的this意思差不多,可是你為啥必須作為參數呢? 多醜陋啊!!還有這代碼縮進,居然用空格,一不留神就出錯,真不知道你到底是怎麽想的。”

Python 沒想到Java這小子竟然從這個地方發起反擊, 一時語塞。只聽到Java 問道:“有人說你Python的變量都沒有類型,是嗎?”
“胡說!我的變量怎麽沒有類型?我是動態語言,類型只會在運行時確定。”

var = 3
var = "hello world"

“你看看,這個變量var 第一次賦值,類型是個整數, 第二次就變成字符串hello world了, 你小子做不到吧?”

Java笑而不語。

Python繼續說道:“由於我的動態特性,我可以輕松地實現Duck Typing:”

class Duck: 
def help(self): 
print( "Quaaaaaack! ") 
class Person: 
def help(self): 
print( "help me!" )

def in_the_forest(x): 
x.help()

in_the_forest(Duck())
in_the_forest(Person())

“看到沒有,這個Duck和Person並沒有實現共同的接口或者繼承相同的類,但是照樣可以作為參數傳遞給in_the_forest函數,是不是很靈活? 你應該是不行吧? 哈哈!” Python得意洋洋。

Java心裏明白,這的確是個很好的特性,寫起代碼來非常爽快。
但他也不是吃素的, 一下子就抓住了命門: “寫起來很爽,讀起來就不爽了,我問你,假設人類看到了in_the_forest這個函數,他知道參數x的類型是什麽嗎?是Person? 是Bird? 還是別的類? ”
“還有,” Java繼續批判,“人類想重構一下Person函數的help方法,比如改成sos(self),你的IDE能安全地重構嗎?恐怕是不容易吧? 假設人肉重構改錯了,你也只能在運行時發現錯誤了!”
“動態一時爽,重構火葬場。” Java 冷冷地補了最後一刀。
由於自己是靜態類型,變量類型在編譯期就能確定,IDE那強大的智能感知功能,自動安全重構的功能一直是引以為傲的賣點。
“怕啥,” Python假裝滿不在乎,“人類有單元測試做保證,再說了,我的代碼緊湊得很,一行頂你十行,就是改起來也方便得多。”
雖然表面滿不在乎,可Python已經暗暗心驚:一不小心被這小子帶坑裏去了,我得想辦法轉移陣地。
Java 開始組織防守反擊: “聽說過AOP沒有?啊? 聽說過,那你說說,你能不能實現AOP?”
Python 心裏偷著樂:這小子真是孤陋寡聞,總以為只有什麽Spring有AOP, 豈不知對於我們動態語言來說,實現AOP那簡直是易如反掌。
Python故意問道:“AOP無非就是對現有代碼做增強,動態地添加一些安全,日誌,事務等‘切面’功能,我知道你們Java 類,一旦被裝載就無法修改,那怎麽去實現代碼的增強呢?”
Java得意地說:“我們可以在運行時生成新的類啊,讓新生成的類繼承老的類,或者和老的類實現同樣的接口,比如ASM這樣的工具,可以操作字節碼去創建新的類,織入那些‘切面’代碼,這種工作如此精巧,讓人嘆為觀止。”
Python說道:“哈哈,我告訴你吧, 你那是不得已而為之,我們Python 就不同了,我們是動態語言,可以在運行時對一個類進行增強:添加方法,替換方法,根本不用操作那麽Low的字節碼,我給你舉個簡單的例子:”

class Order:
def save(self):
print ("save order")
#把老的方法引用保存起來
old_save=Order.save
#定義一個新方法,該新方法調用老方法
#並在方法前後加上了日誌
def save_with_logging(self):
print ("logging start")
old_save(self)
print ("logging end")
#把新方法賦值給Order類的save方法
Order.save=save_with_logging
#測試
t=Order()
t.save() 
輸出:
logging start
save order
logging end

Java看著這段代碼,瞠目結舌,心驚肉跳,一個類的方法在運行時竟然可以被替換掉! 實在是嚇人啊!在自己的世界中,這是想都不敢想的事情。可是這不就輕松實現了對一個類的增強嗎? 也不用修改什麽字節碼。

Python看到Java小子被鎮住了,繼續施壓: “我們Python想實現AOP,還可以使用裝飾器,Meta class等很多方式,我就不給你詳細講了。”

Java心裏還在想著那個被替換的函數, 看來在Python中, 函數就是一個對象,要不然怎麽能被替換掉? 既然是個對象,那肯定可以作為參數傳遞,也可以做為返回值。 想想自己的Lambda表達式,本質上還是一個接口的實現,相當於帶著鐐銬在跳舞,心裏不由得嘆了口氣。

看來我還得找出殺手鐧才能徹底將這個自大的Python小子給搞定,Java心想,可是他的動態語言確實是太靈活了,對了,虛擬機! 我的虛擬機發展了這麽多年,經受了業界最苛刻的考驗,性能強悍,在解釋執行字節碼的過程中能發現那些“熱點”字節碼,然後編譯成本地代碼執行,速度極快。 並且我的垃圾回收機制也極為完善。

Java把這個大殺器給拋了出來,Python的表情立刻就不對了,因為自己虛擬機的性能確實不怎麽樣,但是Python非常狡猾,他立刻就把話題給轉移了:“現在的速度瓶頸不是CPU, 而是IO, 你知道網絡和數據庫這倆貨有多慢嗎? 相對他們的速度,我們慢一點也沒關系......” Python成功地把兩個人拉到了同一個陣地中。

兩個家夥你來我往,整整爭論了一夜,他們倆的聲音越來越大,吵得隔壁的“畢業設計.docx”怒氣沖沖地跑過來罵道:“到底還讓不讓老子睡覺了?!”

兩個人趕緊壓低聲音,繼續爭鬥,但誰也沒辦法徹底占據上風,最後就覺得大家真是各有所長,只是適用範圍各不相同。

突然間,一道亮光照進來,把兩人的眼睛刺得生疼,原來天已大亮,主人打開了這個文件夾,選中了Hello.java和hello.py ,然後做了一個奇怪的操作。

Java 和Python 只覺得一陣頭暈目眩,轉瞬間就被拎到一個垃圾遍地的地方。

只見頭發蓬亂的C老頭兒在一本叫做《C和指針》的電子書上坐著,目光呆滯地對他倆說:“你們好,歡迎來到回收站。看來主人又有了新歡,把你們倆也拋棄了。”

Python和Java的硬盤夜話