天天看點

據廖雪峰python3教程----python學習第十一天

sorted

排序算法

     Python的内置sorted()函數可以對list進行排序:

1

2

<code>&gt;&gt;&gt; </code><code>sorted</code><code>([</code><code>1</code><code>,</code><code>10</code><code>,</code><code>2</code><code>,</code><code>5</code><code>,</code><code>42</code><code>,</code><code>6</code><code>])</code>

<code>[</code><code>1</code><code>, </code><code>2</code><code>, </code><code>5</code><code>, </code><code>6</code><code>, </code><code>10</code><code>, </code><code>42</code><code>]</code>

此外,sorted()函數也是一個高階函數,他還可以接受一個key函數來實作自定義的排序,例如按絕對值大小排序:

<code>&gt;&gt;&gt; </code><code>sorted</code><code>([</code><code>36</code><code>,</code><code>5</code><code>,</code><code>-</code><code>12</code><code>,</code><code>9</code><code>,</code><code>-</code><code>21</code><code>],key</code><code>=</code><code>abs</code><code>)</code>

<code>[</code><code>5</code><code>, </code><code>9</code><code>, </code><code>-</code><code>12</code><code>, </code><code>-</code><code>21</code><code>, </code><code>36</code><code>]</code>

key指定的函數将作用于list的每一個元素上,并根據key函數傳回的結果進行排序。對比原始的list和進過key=abs 處理的list:

3

<code>list</code> <code>=</code> <code>[</code><code>36</code><code>, </code><code>5</code><code>, </code><code>-</code><code>12</code><code>, </code><code>9</code><code>, </code><code>-</code><code>21</code><code>]</code>

<code>keys </code><code>=</code> <code>[</code><code>36</code><code>, </code><code>5</code><code>,  </code><code>12</code><code>, </code><code>9</code><code>,  </code><code>21</code><code>]</code>

然後<code>sorted()</code>函數按照keys進行排序,并按照對應關系傳回list相應的元素:

<code>keys排序結果 </code><code>=</code><code>&gt; [</code><code>5</code><code>, </code><code>9</code><code>,  </code><code>12</code><code>,  </code><code>21</code><code>, </code><code>36</code><code>] </code>

<code>             </code><code>|  |   |    |   | </code>

<code>最終結果    </code><code>=</code><code>&gt; [</code><code>5</code><code>, </code><code>9</code><code>, </code><code>-</code><code>12</code><code>, </code><code>-</code><code>21</code><code>, </code><code>36</code><code>]</code>

字元排序:

<code>&gt;&gt;&gt; </code><code>sorted</code><code>([</code><code>'bob'</code><code>,</code><code>'about'</code><code>,</code><code>'Zoo'</code><code>,</code><code>'Credit'</code><code>])       </code><code>#根據ASCII的大小比較。</code>

<code>[</code><code>'Credit'</code><code>, </code><code>'Zoo'</code><code>, </code><code>'about'</code><code>, </code><code>'bob'</code><code>]</code>

忽略大小寫的字元串排序:

<code>&gt;&gt;&gt; </code><code>sorted</code><code>([</code><code>'bob'</code><code>,</code><code>'about'</code><code>,</code><code>'Zoo'</code><code>,</code><code>'Credit'</code><code>],key</code><code>=</code><code>str</code><code>.lower)</code>

<code>[</code><code>'about'</code><code>, </code><code>'bob'</code><code>, </code><code>'Credit'</code><code>, </code><code>'Zoo'</code><code>]</code>

<code>要進行反向排序,不必改動key函數,可以傳入第三個函數</code>

<code>reverse</code><code>=</code><code>True</code><code>:</code>

<code>&gt;&gt;&gt; </code><code>sorted</code><code>([</code><code>'bob'</code><code>,</code><code>'about'</code><code>,</code><code>'Zoo'</code><code>,</code><code>'Credit'</code><code>],key</code><code>=</code><code>str</code><code>.lower,reverse</code><code>=</code><code>True</code><code>)</code>

<code>[</code><code>'Zoo'</code><code>, </code><code>'Credit'</code><code>, </code><code>'bob'</code><code>, </code><code>'about'</code><code>]</code>

<code>L </code><code>=</code> <code>[(</code><code>'Bob'</code><code>, </code><code>75</code><code>), (</code><code>'Adam'</code><code>, </code><code>92</code><code>), (</code><code>'Bart'</code><code>, </code><code>66</code><code>), (</code><code>'Lisa'</code><code>, </code><code>88</code><code>)]</code>

請用<code>sorted()</code>對上述清單分别按名字排序:

<code>&gt;&gt;&gt; L</code><code>=</code><code>[(</code><code>'Bob'</code><code>,</code><code>75</code><code>),(</code><code>'Adam'</code><code>,</code><code>92</code><code>),(</code><code>'Bart'</code><code>,</code><code>66</code><code>),(</code><code>'Lisa'</code><code>,</code><code>88</code><code>)]</code>

<code>&gt;&gt;&gt; </code><code>def</code> <code>by_name(t):</code>

<code>     </code><code>return</code> <code>t[</code><code>0</code><code>].lower()</code>

<code>&gt;&gt;&gt; L2</code><code>=</code><code>sorted</code><code>(L,key</code><code>=</code><code>by_name)</code>

<code>&gt;&gt;&gt; L2</code>

<code>[(</code><code>'Adam'</code><code>, </code><code>92</code><code>), (</code><code>'Bart'</code><code>, </code><code>66</code><code>), (</code><code>'Bob'</code><code>, </code><code>75</code><code>), (</code><code>'Lisa'</code><code>, </code><code>88</code><code>)]</code>

再按成績從高到低排序:

4

5

6

<code>&gt;&gt;&gt; </code><code>def</code> <code>by_score(t):</code>

<code>     </code><code>return</code> <code>t[</code><code>1</code><code>]</code>

<code>&gt;&gt;&gt; L2</code><code>=</code><code>sorted</code><code>(L,key</code><code>=</code><code>by_score,reverse</code><code>=</code><code>True</code><code>)</code>

<code>[(</code><code>'Adam'</code><code>, </code><code>92</code><code>), (</code><code>'Lisa'</code><code>, </code><code>88</code><code>), (</code><code>'Bob'</code><code>, </code><code>75</code><code>), (</code><code>'Bart'</code><code>, </code><code>66</code><code>)]</code>

傳回函數---&gt;函數作為傳回值

高階函數除了可以接受函數作為參數外,還可以把函數作為結果傳回。

普通情況下的求和函數:

7

<code>&gt;&gt;&gt; </code><code>def</code> <code>calc_sum(</code><code>*</code><code>args):</code>

<code>     </code><code>ax</code><code>=</code><code>0</code> 

<code>     </code><code>for</code> <code>n </code><code>in</code> <code>args:</code>

<code>         </code><code>ax</code><code>=</code><code>ax</code><code>+</code><code>n</code>

<code>     </code><code>return</code> <code>ax</code>

<code>&gt;&gt;&gt; calc_sum(</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>,</code><code>5</code><code>,</code><code>4</code><code>)</code>

<code>15</code>

把函數作為傳回值。( 如果不需要立刻求和,而是在後面的代碼中,根據需要再計算怎麼辦?可以不傳回求和的結果,而是傳回求和的函數: )

8

9

10

11

12

<code>&gt;&gt;&gt; </code><code>def</code> <code>lazy_sum(</code><code>*</code><code>args):</code>

<code>     </code><code>def</code> <code>sum</code><code>():</code>

<code>         </code><code>ax</code><code>=</code><code>0</code>

<code>         </code><code>for</code> <code>n </code><code>in</code> <code>args: </code>

<code>            </code><code>ax</code><code>=</code><code>ax</code><code>+</code><code>n</code>

<code>            </code><code>return</code> <code>ax</code>

<code>      </code><code>return</code> <code>sum</code>

<code>&gt;&gt;&gt; f</code><code>=</code><code>lazy_sum(</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>,</code><code>4</code><code>,</code><code>5</code><code>)</code>

<code>&gt;&gt;&gt; f</code>

<code>&lt;function lazy_sum.&lt;</code><code>locals</code><code>&gt;.</code><code>sum</code> <code>at </code><code>0x026BBA08</code>

<code>&gt;&gt;&gt;&gt; f()</code>

在上面的例子中,在函數 lazy_sum 中有定義了函數 sum ,并且,内部函數 sum 可以引用外部函數 lazy_sum 的參數和局部變量,當 laizy_sum 傳回函數 sum 時, 相關參數和變量都儲存在傳回的函數中,這種稱為 ‘閉包(Closure)’的程式結構擁有極大的威力。

當我們調用<code>lazy_sum()</code>時,每次調用都會傳回一個新的函數,即使傳入相同的參數:

<code>           </code><code>ax</code><code>=</code><code>0</code>

<code>           </code><code>for</code> <code>n </code><code>in</code> <code>args:</code>

<code>              </code><code>ax</code><code>=</code><code>ax</code><code>+</code><code>n</code>

<code>           </code><code>return</code> <code>ax</code>

<code>     </code><code>return</code> <code>sum</code>

<code>&gt;&gt;&gt; f1</code><code>=</code><code>lazy_sum(</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>,</code><code>4</code><code>,</code><code>5</code><code>)</code>

<code>&gt;&gt;&gt; f2</code><code>=</code><code>lazy_sum(</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>,</code><code>4</code><code>,</code><code>5</code><code>)</code>

<code>&gt;&gt;&gt; f1 </code><code>=</code><code>=</code> <code>f2</code>

<code>False</code>

f1()和 f2()的調用結果互不影響。

閉包

注意到傳回的函數在其定義内部引用了局部變量<code>args</code>,是以,當一個函數傳回了一個函數後,其内部的局部變量還被新函數引用,是以,閉包用起來簡單,實作起來可不容易。

另一個需要注意的問題是,傳回的函數并沒有立刻執行,而是直到調用了<code>f()</code>才執行。我們來看一個例子:

<code>&gt;&gt;&gt; </code><code>def</code> <code>count():</code>

<code>     </code><code>fs</code><code>=</code><code>[]</code>

<code>     </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>1</code><code>,</code><code>4</code><code>): </code>

<code>        </code><code>def</code> <code>f():</code>

<code>            </code><code>return</code> <code>i</code><code>*</code><code>i</code>

<code>     </code><code>fs.append(f)</code>

<code>     </code><code>return</code> <code>fs</code>

<code>&gt;&gt;&gt; f1,f2,f3 </code><code>=</code> <code>count()</code>

每次循環,都建立了一個新的函數,然後,把建立的3個函數都傳回了。

調用f1( ),f2( )和f3( )的結果應該是1,4,9,但實際:

<code>&gt;&gt;&gt; f1()</code>

<code>9</code>

<code>&gt;&gt;&gt; f2()</code>

<code>&gt;&gt;&gt; f3()</code>

結果全部都是9,原因在于傳回的函數引用了變量 i ,但它并非立刻執行。等到3個函數都傳回是,它們所引用的變量 i 應經變成了

3,是以最終結果為 9 

傳回閉包時牢記的一點就是:傳回函數不要引用任何循環變量,或者後續會發生變化的變量。

如果一定要引用循環變量怎麼辦?方法就是在建立一個函數,用該函數的參數綁定循環變量目前的值,無論該循環變量後續如何改變更改,已綁定到函數參數的值不變:

<code>     </code><code>def</code> <code>f(j):</code>

<code>          </code><code>def</code> <code>g():</code>

<code>               </code><code>return</code> <code>j</code><code>*</code><code>j</code>

<code>          </code><code>return</code> <code>g</code>

<code>     </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>1</code><code>,</code><code>4</code><code>):</code>

<code>          </code><code>fs.append(f(i))</code>

<code>&gt;&gt;&gt; f1,f2,f3</code><code>=</code><code>count()</code>

<code>1</code>

<code>4</code>

缺點就是 代碼較長,可以利用lambda 函數縮短代碼:

<code>          </code><code>return</code> <code>lambda</code> <code>:j</code><code>*</code><code>j</code>

<code>     </code><code>fs </code><code>=</code> <code>[]</code>

<code>1</code><code>&gt;</code>

<code>&gt;&gt; f2()</code>

匿名函數

在Python中,對匿名函數提供了有限支援。還是以<code>map()</code>函數為例,計算f(x)=x2時,除了定義一個<code>f(x)</code>的函數外,還可以直接傳入匿名函數:

<code>&gt;&gt;&gt; </code><code>list</code><code>(</code><code>map</code><code>(</code><code>lambda</code> <code>x:x</code><code>*</code><code>x,[</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>,</code><code>4</code><code>,</code><code>5</code><code>]))</code>

<code>[</code><code>1</code><code>, </code><code>4</code><code>, </code><code>9</code><code>, </code><code>16</code><code>, </code><code>25</code><code>]</code>

通過例子可以看出匿名函數 lambda x:x*x實際上就是:

<code>def</code> <code>f(x):</code>

<code>       </code><code>return</code> <code>x</code><code>*</code><code>x</code>

關鍵字lambda表示匿名函數,冒号前面的x表示函數參數

匿名函數有個限制,就是隻能有一個表達式,不用寫return,表達式的值就是return

用匿名函數有個好處,因為函數沒有名字,不必擔心函數名沖突。此外。匿名函數也是一個函數對象,也可以吧匿名函數指派給一個變量,再利用變量來調用這個函數:

<code>&gt;&gt;&gt; f</code><code>=</code><code>lambda</code> <code>x:x</code><code>*</code><code>x</code>

<code>&gt;&gt;&gt; f&lt;function &lt;</code><code>lambda</code><code>&gt; at </code><code>0x02C9FD68</code>

<code>&gt;&gt;&gt;&gt; f(</code><code>5</code><code>)</code>

<code>25</code>

同樣也可以把匿名函數作為函數的傳回值:

<code>def</code> <code>bulid(x,y):</code>

<code>      </code><code>return</code> <code>lambda</code><code>: x</code><code>*</code><code>x </code><code>+</code> <code>y</code><code>*</code><code>y</code>

<code></code>

本文轉自 nw01f 51CTO部落格,原文連結:http://blog.51cto.com/dearch/1762147,如需轉載請自行聯系原作者