程式扎記: [ The python tutorial ] 4. More Control Flow Tools

標籤

2012年1月2日 星期一

[ The python tutorial ] 4. More Control Flow Tools


翻譯自 這裡
More Control Flow Tools :
Besides the while statement just introduced, Python knows the usual control flow statements known from other languages, with some twists.

if Statements
使用 if...elif...else 可以達成類似 switch 語法的功能 :


for Statements
在 Python 中的 for loop 跟你在 C 或是 Java 語言使用上有點不太一樣, 反而有點類似 foreach 的用法 :


如果要使用類似其他語言 for(; ;) 類似的用法, 可以使用 slice :


- The range() Function
函數 range(n) 可以幫你產生類似串列 [0...n] 的物件:


關於該函數更多用法如下 :
range(5, 10)
#5 through 9

range(0, 10, 3)
#0, 3, 6, 9

range(-10, -100, -30)
#-10, -40, -70

for loop 搭配 range() 函式還可以這樣用 :

(更多 loop 的用法可以參考 Looping Techniques)

事實上 range() 返回的不是一個串列, 而是一個具備 iterable 的物件. 而你可以使用 iterator 操作具備 iterable 的物件, 如 for loop 與 list() :
>>> print(range(10))
range(0, 10) # 返回是一個物件而非串列.
>>> list(range(5))
[0, 1, 2, 3, 4] # list() 可將具備 iterable 的物件轉為串列.

break and continue Statements, and else Clauses on Loops
在 Python 中的 break 與 continue 與 C 語言一樣, 但是多了個 for loop 的 else, 當你在 for-loop 使用 break, 該 else 的子句就會被執行 :


pass Statements
在 Python 中的 pass 通常是用在為了語法可以通過而存在, 底下是一些使用的可能狀況 :
>>> while True:
... pass # Busy-wait for keyboard interrupt (Ctrl+C)
...

底下是建立類別最陽春的寫法 :
>>> class MyEmptyClass:
... pass
...

Defining Functions :
底下為 費比數列 定義的函示, 你使用關鍵字 def 定義函數並藉由傳入參數決定數列的 upper bound :


函數的第一行可以給定註解的字串, 則它會成為該函數的 documentation string 或 docstring (更多說明可以參考 這裡). 透過某些工具, 可以裡用這樣的註解幫你快速的處理或尋找函數, 或是自動生成 API 文檔. 所以養成習慣為你的函數撰寫 docstring 吧. 底下為函數變數使用範圍說明 :
The execution of a function introduces a new symbol table used for the local variables of the function. More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names. Thus, global variables cannot be directly assigned a value within a function (unless named in a global statement), although they may be referenced.

由函數傳入的參數是 call by value (where the value is always an object reference, not the value of the object), 簡單說就是傳入的是原有物件的參考而非物件的值, 當你的函數又呼叫另一個函數時, 另一個 new local symbol table 又會被建立. 另外你建立的函數在當前的 symbol table 會以該函數名稱建立一個 symbol, 所以你可以使用另一個變數參考到你剛剛定義的函數, 達成為該函數改名的用途 :
>>> fib
<function fib at 0x00000000029565C8>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89

函數中你可以使用關鍵字 return 返回值. 就算你不使用 return, 它也會自動幫你回傳 None (it’s a built-in name) :
>>> fib(0)

>>> print(fib(0))

None

底下為函數可以幫你返回小於 n 的 費比級數 的串列 :


More on Defining Functions :
函數的傳入參數可以多個, 也可以有預設值, 更多說明參考下面.

- Default Argument Values
當你函數的傳入參數有預設值時, 意味你可以少傳點參數 (沒傳入的使用預設值) :


上面的函數可以以下面形式呼叫 :
* giving only the mandatory argument: ask_ok('Do you really want to quit?')
* giving one of the optional arguments: ask_ok('OK to overwrite the file?', 2)
* or even giving all arguments: ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

上面使用到關鍵字 in 用來確認是否某個值存在串列中. 接著猜猜下面的函數會印出什麼 (答案是5) :
>>> i = 5
>>> def f(arg=i): # arg 被設定為 i=5, 就算之後 i 改變, arg 還是 5!
... print(arg)
...
>>> i = 6
>>> f()

在使用預設值時要注意一點是如果你的物件是一個類似串列, 字典物件等可以包含多個其他物件時, 則你在函數本體對它操做的任何動作是會有記憶性的 :


如果這不是你預期的行為, 你想要沒有記憶性的話則可以 :


- Keyword Arguments
在函數定義時, 參數的名稱可以是你在呼叫函數傳入參數可以指定的對象 (更多參考 這裡) :


則你可以如下呼叫函式 :
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword

但底下的呼叫會錯誤 :
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument

當你函數的參數最後一個是 **name (name 可以是任何變數名稱), 他接受一個字典輸入 (參考 這裡), 除了參數列有定義過的名稱外, 其他 key-value pairs 都會存在 **name. 而在 **name 前你還可以放一個 *name (*name must occur before **name.), 同樣的它可以用來存放除了你參數列表有義過的名稱外的 tuple, 底下為使用範例 :


- Arbitrary Argument Lists
所以不定參數的使用可以使用 *name. 它會以 tuple 形式串入函式本體 (see Tuples and Sequences). 通常它會放在函式參數列表最後一個, 如果在它之後還有參數, 則那些參數只能以 keyworld 方式賦值, 而不能用 position 方式 :


- Unpacking Argument Lists
函數的參數列表也能用 tuple 或 list 傳入, 但是需要 unpack. 這時你可以使用 * 來達成 :
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]

同樣的字典物件可以在 unpack 後傳入參數列表, 使用 ** 來達成 :


- Lambda Forms
可以把 Lambda 想像成匿名函式或是 C 中的巨集, 在 Python 使用關鍵字 lambda. 底下是相關說明 :
Lambda forms can be used wherever function objects are required. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal function definition. Like nested function definitions, lambda forms can reference variables from the containing scope



- Documentation Strings
底下是有關你在為你的函式, 類別撰寫說明時的建議與慣例 :
The first line should always be a short, concise summary of the object’s purpose. For brevity, it should not explicitly state the object’s name or type, since these are available by other means (except if the name happens to be a verb describing a function’s operation). This line should begin with a capital letter and end with a period.

If there are more lines in the documentation string, the second line should be blank, visually separating the summary from the rest of the description. The following lines should be one or more paragraphs describing the object’s calling conventions, its side effects, etc.

The Python parser does not strip indentation from multi-line string literals in Python, so tools that process documentation have to strip indentation if desired. This is done using the following convention. The first non-blank line after the first line of the string determines the amount of indentation for the entire documentation string. (We can’t use the first line since it is generally adjacent to the string’s opening quotes so its indentation is not apparent in the string literal.) Whitespace “equivalent” to this indentation is then stripped from the start of all lines of the string. Lines that are indented less should not occur, but if they occur all their leading whitespace should be stripped. Equivalence of whitespace should be tested after expansion of tabs (to 8 spaces, normally).

底下為範例 :


Intermezzo: Coding Style :
到目前為止, 透過所學你應該能撰寫稍微大型的程式. 這時 coding style 能幫助你建立好習慣, 撰寫容易維護且可讀的程式碼. 在 Python 比較多人遵循的是 PEP 8, 底下是一些擷取的重點 :
* Use 4-space indentation, and no tabs.

* 4 spaces are a good compromise between small indentation (allows greater nesting depth) and large indentation (easier to read). Tabs introduce confusion, and are best left out.

* Wrap lines so that they don’t exceed 79 characters. This helps users with small displays and makes it possible to have several code files side-by-side on larger displays.

* Use blank lines to separate functions and classes, and larger blocks of code inside functions.

* When possible, put comments on a line of their own.

* Use docstrings.

* Use spaces around operators and after commas, but not directly inside bracketing constructs: a = f(1, 2) + g(3, 4).

* Name your classes and functions consistently; the convention is to use CamelCase for classes and lower_case_with_underscores for functions and methods. Always use self as the name for the first method argument (see A First Look at Classes for more on classes and methods).

* Don’t use fancy encodings if your code is meant to be used in international environments. Python’s default, UTF-8, or even plain ASCII work best in any case.

* Likewise, don’t use non-ASCII characters in identifiers if there is only the slightest chance people speaking a different language will read or maintain the code.
This message was edited 37 times. Last update was at 03/01/2012 11:40:52

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!