C++程序員Python notes

參考http://blog.chinaunix.net/uid/20039893/frmd/49956.html及其他一些網上資料,C++程序員的Python入門

1. important getchas:
    judge whether a object is a type
    type(object) == type(str())
    或
    from types import StringTypes
    type(object) == types.StringType    #記得要import types
    或if isinstance(obj, StringTypes):
    與系統定義的單值比較儘量使用is,雖然使用==能使用同樣功能但效率差許多,因爲一個是直接比較一個需要調用其比較函數,老外曾經測試過。如if x is None,if x is not None,不要if x == None。is的非形式爲is not。
    所有的控制語句需要用':'換行,定義函數同樣,切記,Python中的一切都是對象,包括函數。
    儘量使用xrange代替range,range直接生成指定大小的list,而xrange只是生成一個對象而在需要時才產生下一個值,這可以節省非常多的內存,對於足夠大的值使用range可能造成內存不足。
    編碼規範:類名首字母大寫,e.g. ,Dog,變量和函數名__開頭爲私有,儘量只將函數暴露給外部,變量命名小寫加_即可,同Linux。某些時候和系統的命名衝突可以_結尾,如_china_。
http://www.cnblogs.com/kym/archive/2011/03/17/1986640.html

2. itertools模塊對迭代和組合非常有效,比如
    import itertools
    iter = itertools.permutations([1, 2, 3])
    lst = list(iter)    #此時lst爲[1, 2, 3]的全排列

3. 數組即list,下標中的冒號表示到XX爲止或以XX開始
    string中單個item是不可修改的,故不可使用str_test[5] = 'm'來修改一個字節
    正確的方式是str_test = str_test[4:] + 'm' + str_test[:6]
    但這種方法會多次拷貝字符串造成效率較低,故較好的方法是先用list存儲之後再轉
    其長度並非list.len而是len(list)

4. sequence類型的slice詳解,比如string、list、tuple
    1)+不能用來連接一個字符串和數字,因爲其也數字加法運算符
    2)[1:4:2]除起始兩個值代表起始和結束位置外,最後一個代表步進值

5. Python數據類型分類
    number
    sequence: string(不可變)、list、tuple(不可變)
    mapping: dictionary,類似stl中的map
    可變和不可變類似於c++中的const,即一旦定義後不許改變其值。
    number支持各種算術運算。
    string是順序的,不可變的。
    list是順序的,可變的。
    dictrionary是無順序的,可變的
    tuple是順序的,不可變的。
    str() list() dict() tuple()這幾內置函數分別用於構造相應的類型。

6. list
    特點:有序、可變
    可直接使用list將序列構造一個list,如:test_list = list('china')
    修改時可直接以slice爲單位,且不要求被替換的內容與新內容長度相同,故修改後可能list的長度會改變,如:test_list[4:6] = ['n', 'a', 'm', 'mddd']或test_list[4:] = ['e']
    注意list中的count並非其中的元素個數,而是給定的value在list中出現的次數
    其他如下:

  1. >>> L.append(4)  #只能一次添加一個object,不能用於兩個sequence連接,因爲新sequence將會被作爲一個object添加進去
  2. >>> L
  3.     [0, 1, 2, 3, 4]
  4. >>> L.extend([5, 6])  #參數爲一個sequence,直接添加到其末尾
  5. >>> L
  6.     [0, 1, 2, 3, 4, 5, 6]
  7. >>> L = L + [7]  #可爲sequence或object,與前面的區別是會新構造一個對象,故需要重新賦值,至於+=是否會被當作append或extend處理目前並未有相關資料,如果作者有注意到的話應該會做此類優化
  8. >>> L
  9.     [0, 1, 2, 3, 4, 5, 6, 7]

7. dictionary
    初始化方式爲test_dic = {1:'one', 2:'two}
    可以使用items()導出到list, test_list = test_dic.items(),將會得到一個類似[(1, 'one'), (2, 'two')]的list。
    可以使用fromkeys()從list導入key,value將以None填充,如:
    test_list = [1, 2, 3, 4]
    test_dic.fromkeys(test_list)
    for x in test_dic會遍歷test_dic,默認遍歷key,使用test_dic的iterkeys()、itervalues()、iteritems()可以分別得到遍歷key、value和item的iterator。

8. tuple
    test_tuple = (1, 3, 4)
    可將tuple理解成const的list,但其成員的成員是可變,即其某一位置必須指向某一對象不可再指向另一對象,但該對象本身是可變的。
    注意當只有一個初始成員時需要在初始化末尾加',',如:
    test_tuple = (1, )
    否則將會被初始化爲整型。

9. 查找一個值是否在容器中要用in而不是用index然後去檢查其返回值是不是>0...

10. print a, b, c,    print會自動在每個變量後加一個空格,最後以逗號結尾可以防止調用print結束會自動附加的\n換行符
    print >> object, x, y    將x,y出到object的write方法中,該ojbect必須有些方法哦
    Python中print爲以下語句的簡寫
    import sys
    sys.stdout.write(str(x) + '\n')
    故可通過將stdout重定向而實現print的輸出重定向功能
    import sys
    fp = file('log.txt', 'a')
    sys.stdout = fp
    print 'hello world! heihei'
    sys.stdout = sys.__stdout__    # reset to default

11. 語句和語法
    Python要寫超過一行的語句,需要一對符號的語句或者在前一行後加上'\',與C相同,第二種不推薦,因爲任何第二種的情況都可使用()來代替
    Python中的switch/case可用多個if/elif/else代替,或者個人感覺可以使用dictionary結合lambda表達式,如:
    choice = 'inc'
    g = {'inc' : lambda x: x + 1,
     'dec' : lambda x: x - 1}
    g[choice](x)
    Python中的while和for都可帶else子句,注意break是不會跳到else中的,只有循環的判斷表達式爲False方可。

12. map(function, seq1, seq2, ...) 對seq列表中的所有的的seq每項依次調用function,將其返回值構建列表,如果functon爲None則直接返回seq中的值
    map(lambda x, y: y / x, time, ratio)    #每個時刻點的平均ratio

13. zip就是把2個數組糅在一起
x=[1, 2, 3, 4, 5 ]
y=[6, 7, 8, 9, 10]
zip(x, y)就得到了
[(1, 6), (2, 7), (3, 8), (4, 9), (5, 10)]
比如你有2組座標,你想兩兩對應的相加,那麼zip函數就很有用了。
再比如,你有2個數組A,B,A存了班級裏的人的名字,B是每個人的考試分數,你需要通過某個人的名字來查考試分數,那你需要一個字典,zip可以很方便地幫你建立字典:
>>> x=['bob','tom','kitty']
>>> y=[80,90,95]
>>>d=dict(zip(x,y))
[('bob', 80), ('tom', 90), ('kitty', 95)]
>>> d['bob']
返回80,多方便啊

14. 在Python中所有的都是對象,函數也不例外。
    def定義一個函數對象,定義的對象可賦值,lambda函數同理。

  1. if x ==0:
  2.     def npower(n): x**2
  3. else:
  4.     def npower(n): x**3
  5. nload = npower
  6. nload(5)
  7. L = [npower, nload]

15. 命名空間
第一,賦值(包括顯式賦值和隱式賦值)產生標識符,賦值的地點決定標識符所處的命名空間。
第二,函數定義(包括def和lambda)產生新的命名空間。
第三,python搜索一個標識符的順序是"LEGB"。
所謂的"LEGB"是python中四層命名空間的英文名字首字母的縮寫。最裏面的一層是L(local),表示在一個函數定義中,而且在這個函數裏面沒有再包含函數的定義。第二層E(enclosing function),表示在一個函數定義中,但這個函數裏面還包含有函數的定義,其實L層和E層只是相對的。第三層G(global),是指一個模塊的命名空間,也就是說在一個.py文件中定義的標識符,但不在一個函數中。第四層B(builtin),是指python解釋器啓動時就已經具有的命名空間,之所以叫builtin是因爲在python解釋器啓動時會自動載入__builtin__模塊,這個模塊中的list、str等內置函數的就處於B層的命名空間中。
其實只要在編程的時候注意一下,不要使用相同的標識符,基本上就可以避免任何與命名空間相關的問題。還有就是在一個函數中儘量不要使用上層命名空間中的標識符,如果一定要用,也最好使用參數傳遞的方式進行,這樣有利於保持函數的獨立性。

16. 函數傳參方式
關鍵字賦值法:不像C/C++,形參的順序是可根據傳參順序改變,如:F(arg2 = 2, arg1 = 1)
F(arg1,arg2,...)
F(arg2=<value>,arg3=<value>...)    #帶默認值的函數定義,如果需要用到默認值的參數在前面,則使用關鍵字賦值法
F(*arg1)    #參數不管多少個都被存放在以形參名爲標識符的tuple中
F(**arg1)    #參數不管多少個都被存放在以形參名爲標識符的dictionary中,調用時需要採用F(x = 1, y = 2)類似的形式, 則arg1 = {('x' : 1), ('y' : 2)}

17. lambda函數
與C++不同,lambda在Python中只能是一行,可以使用';',但不能使用for/while/if,雖然使用某些技巧可以實現但不推薦,系統自帶的map/reduce/filter等函數比較好用。
lambda x, y: x + y; print x, y; x + y + 1

18. 類相關
__init__(self)    類的構造函數,如果傳參可寫爲__init__(self, arg1, arg2...),類似於c++中的bind。
__del__(self)    類的析構函數
__call__(self, arg1, ...)  類似於C++中的重載括號運算符
類中的權限完全根據_和__來區分,即直接命名的爲public函數
派生類需要手動調用基類的__init__,否則繼承將不起作用

class Animal(object):
    name = 'unname' # member varieble
 
    def __init__(self, voice = 'hello', name = 'default'):
        self.voice = voice
        print 'animal::__init__, name: ', name
 
    def __call__(self, voice)
        self.voice = voice
 
    def say(self):
        print self.voice
        print self.name
 
class Dog(Animal):
    def __init__(self):
        #Animal.__init__(self)    # 手動調用
        super(Dog, self).__init__()    #代替上面的寫法
        self.dogName = 'dogName'
 
Dog d
d('wangwang')    # invoke __call__
d.say()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章