2016年7月23日 星期六

cProfile: 可量測Pythonn函式效能的模組

最近自己偶爾練習Python時,有時候會碰到效能不好
這時候可以使用內建的cProfile模組來看每個function call所需的時間
例如:cProfile.run( 'function()' )

可以看到像下面這樣的列表

42333 function calls (42317 primitive calls) in 0.489 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.489    0.489 :1()
        2    0.000    0.000    0.001    0.000 arrayprint.py:175(_array2string)
       32    0.000    0.000    0.000    0.000 arrayprint.py:208()
        2    0.000    0.000    0.000    0.000 arrayprint.py:22(product)
      6/2    0.000    0.000    0.001    0.000 arrayprint.py:246(array2string)
       32    0.000    0.000    0.000    0.000 arrayprint.py:312(_extendLine)
     10/2    0.000    0.000    0.000    0.000 arrayprint.py:320(_formatArray)
       32    0.000    0.000    0.000    0.000 arrayprint.py:493(_formatInteger)


能幫助分析是哪個函式造成效能瓶頸, 如果是使用物件的方法的話則必須寫成: cProfile.runctx('self.method()', globals(), locals())
否則cProfile會認不到method所在的scope

2015年10月31日 星期六

Python二維陣列寫法

Python實踐二維陣列的寫法注意事項

如果直覺地使用list, 可能會寫成

twoDimArray = [[0]*3]*3

陣列的樣子會是 [[0,0,0],[0,0,0], [0,0,0]]
看起來符合二維陣列的模樣, 但其中隱含一個問題
如果更改其中一個元素

twoDimArray[0][0] = 1

結果陣列內容會變成

[[1,0,0],[1,0,0],[1,0,0]]

如果使用id來看

for row in twoDimArray:
    print(id(row))

會發現id都一樣, 每一列所指的都是同一個list!!
這種bug可能會造成之後使用這個array時出現奇怪的錯誤

所以建議寫法應該改成

twoDimArray = []
    for rowCount in xrange(3)
        twoDimArray.append([0]*3)

再一次檢查id, 可以發現到已經是不同的list object了

Tip: 或者乾脆使用numpy 套件更為妥當

11/1新增:在stackflow上看到的相關討論

Reference:
http://stackoverflow.com/questions/12791501/python-initializing-a-list-of-lists

2015年4月26日 星期日

python 網路爬蟲避免被阻擋的方法

最近手癢寫一小支網路爬蟲,但是會碰到被伺服器擋下的問題

主要原因就是對方伺服器知道當前連線的程序是機器人
處理方式就是讓爬蟲偽裝成真人


python網路爬蟲常利用urllib2模組來實現, 但是預設的user-agent會註明這是一支python程式
因此需要修改成常見到的瀏覽器

例如:
即可讓本次的Request被視為是linux系統經由Firefox瀏覽器所送出

要注意:如果連線過於頻繁仍有可能被視為惡意攻擊

2014年9月13日 星期六

pip指令:freeze

最近在django的教學中看到的pip指令
freeze,能夠得知目前環境下透過pip安裝的套件
看來以後要盡量用pip安裝套件,方便日後變更環境
重新架設開發環境。

2014年5月10日 星期六

撰寫python常見的十大錯誤

原文如下:
http://www.toptal.com/python/top-10-mistakes-that-python-programmers-make

這篇文章列出了在撰寫Python時,常犯的錯誤
內容也稍微帶出了一些Python內部實做的細節

先寫下一點簡單的個人摘要,改天來翻譯一下好了

1. 誤用函式的參數:
python 的 函式參數是在函式宣告時就定義完畢,而且也只會定義一次
(the default value for a function argument is only evaluated once, at the time that the function is defined.)
int, float參數是沒啥感覺,但在list時,很容易誤以為每次都會產生新的list
實際reference是指向同一list

2. 誤用 class 變數:
子類別沒有特別override 父類別的變數時,子類別物件的變數其實都指向同一變數(即父類別的變數),會導致改了一個兒子,其他兄弟手上也跟著變

3. 例外處理沒正確捕捉
「except ValueError, IndexError:」的寫法只會看到ValueError, 後面的IndexError會被忽略,改成「except ( ValueError, IndexError ) as e:」就都能catch了

4. 誤解了Python 的 變數Scope
若想在函式內修改global 變數時,不要用assign operater (像是 += )
在函式內使用 += 時是會看區域變數,實際上當然沒有這個local變數
最後出現unboundLocalError, 畢竟等同於「尚未宣告就先指定值」

5. 在迭代list時修改了它
迭代過程中,刪除了list中的元素, 引發error
它建議是另開一個list, 迭代原list,並將符合條件者存入
反正沒被reference到的memory會被python的garbage collection回收

6. 弄錯Python的Closures實做
這部份要先去理解Closures(閉包),上次接觸這個名詞是在看JavaScript
的書,我記得好像是跟變數的生命週期有關.......
------待補-------

7. module互相引入
在架構上要注意這點,如果出現了互相引用,大概代表
功能之間的相依性有問題。

8. 取名時不小心跟標準函式庫一樣
盡量避免取什麼專有名詞的module吧

9. Python2.x 與 Python 3的寫法有點不同
說真的....我到現在都還是2.7版
------待補-------

10.誤用__del__ method
------待補-------



2014年3月2日 星期日

python中zip函式的範例,matrix transpose 及 split string to same size chunk

>>a = [  [1,2,3], [4,5,6], [7,8,9] ]
>>zip( *a ) # 等同於  zip( [1,2,3], [4,5,6], [7,8,9] )
>>[ (1,4,7), (2,5,8), (3,6,9) ]  # 矩陣轉置

zip 會擷取每個迭代物件所對應的元素放入tuple中
第一個tuple 內含每個list的第一個元素,第二tuple  則是第二元素
以此類推。

>> s = 'abcdefghi'
>>zip( *[iter(s)]*3 )
>>[ ( 'a', 'b', 'c' ), ( 'd', 'e', 'f' ),  ( 'g', 'h', 'i' ) ] # 字串切割成一塊塊

將字串切成同樣字元數的範例原理是因爲迭代器 iter
在每次呼叫時都會以 __next__ 取出一個元素

而在 [ iter(s) ] * 3 這步驟,並不是生成三個迭代字串s 的list
而是生成一個list, 裏面的三個元素的參照都指向同迭代器

>> [ iter(s) ]*3
>> [ <iterator object at 0xaddress>, <iterator object at 0xaddress>,
         <iterator object at 0xaddress> ]

因此當zip 在生成第一個tuple時,在list元素一的iter 回傳字串的第一個字
而去list元素二時,由於仍是同一個迭代器,此時會回傳第二個字
以此類推。

感覺像是這樣:

  tuple1              tuple2              tuple3
----------          ----------         -----------
abcdefghi        abcdefghi        abcdefghi
abcdefghi        abcdefghi        abcdefghi
abcdefghi        abcdefghi        abcdefghi


2014年2月23日 星期日

於python使用opencv的imread 可能會忽略的小地方

        最近在利用python與opencv 在做影像相關的work
其中我需要知道每一pixel在RGB下 ( B-R ) / ( B+R )
的比例。
        然而跑出來的值非常詭異,在查閱文件後
發現問題出在opencv的imread下
imread 在讀檔後所回傳的資料為numpy.ndarray
維度為影像的長乘上寬,每一element為一tuple
但資料型態是 「numpy.uint8」,當在做pixel運算時
如果有碰到負數則會出現錯誤的值。