4.1 ประโยค if
( if
Statements)
4.2 ประโยค for
( for
Statements)
4.3 ฟังก์ชั่น range()
(The range()
Function)
4.4 คำสั่ง break
และ continue
และวลี else
สำหรับการวนรอบ ( break
and continue
Statements, and else
Clauses on Loops)
4.5 คำสั่ง pass
( pass
Statements)
4.6 นิยามฟังก์ชั่น (Defining Functions)
4.7 เพิ่มเติมเรื่องฟังก์ชั่น (More on Defining Functions)
while
แล้ว บทนี้เรามารู้จักคำสั่งควบคุมให้มากขึ้น
if
( if
Statements)>>> x = int(raw_input("Please enter an integer: ")) >>> if x < 0: ... x = 0 ... print 'Negative changed to zero' ... elif x == 0: ... print 'Zero' ... elif x == 1: ... print 'Single' ... else: ... print 'More' ...
มี elif
กี่ตัวก็ได้ และมี else
หรือไม่มีก็ได้ (ภาษาอื่นอาจมี switch
และ case
แต่ไพธอนใช้ if
อย่างเดียว)
for
( for
Statements)for
ของไพธอน ต่างจากภาษาอื่นเล็กน้อย ตอนวนรอบ แทนที่จะใช้ตัวนับซึ่งเป็นตัวเลข ไพธอนกลับใช้ลำดับแทน (เช่น สตริงก์ ลิสต์ หรือทูเปิล)
>>> # Measure some strings: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12
range()
(The range()
Function)ใช้สร้างลิสต์จากช่วงของตัวเลขจำนวนเต็ม
แบบง่าย
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
อาจกำหนดเป็นช่วง
>>> range(5, 10) [5, 6, 7, 8, 9]
หรือแบบกำหนดขนาดขั้นของการเพิ่มด้วย
>>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70]
ใช้ร่วมกับ len()
กับลิสต์ (การทำงานกับลิสต์แบบอ้างอิงจากดัชนี จะใช้วิธีนี้เป็นปกติ)
>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Mary 1 had 2 a 3 little 4 lamb
break
และ continue
และวลี else
สำหรับการวนรอบ ( break
and continue
Statements, and else
Clauses on Loops)คำสั่ง break
ส่งผลให้หลุดจากวงรอบที่คำสั่งนี้บรรจุอยู่
ส่วน continue
จะมีผลให้หยุดการทำงานที่จุดนั้น แล้วกลับไปเริ่มวนรอบใหม่
วลี else
ใช้สำหรับเมื่อหลุดจากการวนแล้ว จะทำภายในบล๊อกนี้หนึ่งครั้ง ยกเว้นถ้าพบคำสั่ง break
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'equals', x, '*', n/x ... break ... else: ... # loop fell through without finding a factor ... print n, 'is a prime number' ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3
pass
( pass
Statements)คำสั่ง pass
ไม่ทำอะไรเลย แต่มีไว้เผื่อเวลาเราวางโครงสร้างโค๊ดไว้แล้ว แต่ยังไม่ได้เขียนท่อนนั้น ก็บรรจุคำสั่งนี้ไว้เพื่อให้สามารถทดสอบการรันได้
>>> while True: ... pass # Busy-wait for keyboard interrupt ...
เอาตัวอย่างในการเขียนอนุกรมฟิโบแนคซี่มาเขียน
>>> def fib(n): # write Fibonacci series up to n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Now call the function we just defined: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
ฟังก์ชั่น ขึ้นต้นด้วย def
ตามด้วยชื่อฟังก์ชั่นและวงเล็บซึ่งบรรจุอาร์กิวเมนต์ หลังจากนี้จะเป็นบล๊อกที่ต้องเยื้องย่อหน้า
บรรทัดพิเศษต่อจากชื่อฟังก์ชั่น อาจใส่คำอธิบายการทำงานของฟังก์ชั่นได้เลย ซึ่งไพธอนจะไม่ตีความเป็นโค๊ดที่จะรัน บรรทัดนี้เรียกว่า docstring
ตัวแปรในฟังก์ชั่นจะถือเป็นตัวแปรท้องถิ่นทั้งหมด เว้นแต่เรากำหนดให้เป็นตัวแปรร่วม ซึ่งต้องกำหนดด้วยคำสั่ง global
การส่งผ่านค่าตัวแปร จะถือเป็นการส่งผ่านโดยค่าทั้งหมด (pass by value)
ชื่อฟังก์ชั่นสามารถถูกกำหนดค่าให้กับตัวแปรได้
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89 >>> f <function fib at 10042ed0>
ฟังก์ชั่นในไพธอนจะคืนค่ากลับมาเสมอ ซึ่งปกติจะใช้ด้วยคำสั่ง return VALUE
แต่ในตัวอย่างข้างต้นไม่มีการคืนค่าด้วยคำสั่ง return
กรณีนี้ไพธอนจะคืนค่าเป็นค่าพิเศษคือ None
>>> print fib(0) None
จากตัวอย่างข้างต้น สามารถเขียนในรูปฟังก์ชั่นที่ส่งคืนค่าดังนี้
>>> def fib2(n): # return Fibonacci series up to ... """Return a list containing the Fibonacci series up to n."" ... result = [ ... a, b = 0, ... while b < n ... result.append(b) # see belo ... a, b = b, a+ ... return resul ... >>> f100 = fib2(100) # call i >>> f100 # write the result [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
ความรู้ใหม่
None
result.append(b)
เป็นเมธอดของลิสต์ result
เมธอดก็คือฟังก์ชั่นที่เป็นเฉพาะของออปเจคต์นั้น ซึ่งมีรูปแบบการเขียนเป็น obj.methodname
result.append(b)
มีผลเท่ากับ "result = result + [b]"
แต่เขียนได้กระชับและเข้าใจง่ายกว่ามีหลักในการกำหนดค่าอาร์กิวเมนต์คือ
เป็นการกำหนดค่าปริยายให้กับอาร์กิวเมนต์ มีรูปแบบว่าอาร์กิวเมนต์ที่จะกำหนดค่าปริยายให้ จะต้องอยู่ทางขวาเสมอ ส่วนตัวที่ไม่กำหนด จะต้องอยู่ทางซ้ายเสมอ
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while True: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint
การใช้งานเช่น ask_ok('Do you really want to quit?')
หรือ ask_ok('OK to overwrite the file?', 2, 'Please answer y or n')
จากตัวอย่างหลัง retries
คือ 2 และ complaint
คือ 'Please answer y or n'
ในตัวอย่างนี้ มีคำใหม่คือ in
เป็นการดูว่าตัวแปร ok
อยู่ภายในช่วงที่กำหนดหรือไม่
ข้อควรระวัง
>>> i = 5 >>> def f(arg=i): ... print arg ... >>> f() 5 >>> i=6 >>> f() 5
>>> def f(a, L=[]): ... L.append(a) ... return L ... >>> print f(1) [1] >>> print f(2) [1, 2] >>> print f(3) [1, 2, 3]
วิธีแก้คือ ให้หลีกเลื่ยงข้อมูลชนิดนี้ในการกำหนดค่าปริยาย จากตัวอย่างจะดัดแปลงฟังก์ชั่นเป็น
def f(a, L=None): if L is None: L = [] L.append(a) return L
เหมือนกับหัวข้อก่อนหน้า แต่ในหัวข้อนี้ เจาะจงอธิบายลักษณะที่กำหนดเป็นคีย์เวิร์ด มีรูปแบบคือ "keyword = value"
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, print "if you put", voltage, "volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!"
การใช้งาน
parrot(1000) parrot(action = 'VOOOOOM', voltage = 1000000) parrot('a thousand', state = 'pushing up the daisies') parrot('a million', 'bereft of life', 'jump')
parrot() # ผิดเพราะขาดค่าที่ไม่มีค่าปริยาย คือ voltage parrot(voltage=5.0, 'dead') # ผิดเพราะค่าปริยายอยู่ซ้าย จริง ๆ ต้องอยู่ขวา parrot(110, voltage=220) # ผิดเพราะกำหนดค่าซ้อน parrot(actor='John Cleese') # ผิดเพราะชื่อไม่มีชื่อคีย์เวิร์ด actor
ตัวอย่างการรายงานข้อผิดพลาดของการกำหนดค่าซ้อน
>>> def function(a): ... pass ... >>> function(0, a=0) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: function() got multiple values for keyword argument 'a'
ตัวอย่างต่อไปจะแสดงให้เห็นประโยชน์ที่แท้จริงของหัวข้อนี้ คือ การระบุอาร์กิวเมนต์แบบให้ง่ายต่อการพลิกแพลง คือเราสามารถระบุอาร์กิวเมนต์แบบอ้างอิงได้ โดยมีรูปแบบคือ
def function_name(normal_parameter, *tuple_parameter, **dictionary_parameter)
ตัวอย่างคือ
def cheeseshop(kind, *arguments, **keywords): print "-- Do you have any", kind, '?' print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg print '-'*40 keys = keywords.keys() keys.sort() for kw in keys: print kw, ':', keywords[kw]
เรียกใช้ด้วยคำสั่ง
cheeseshop('Limburger', "It's very runny, sir.", "It's really very, VERY runny, sir.", client='John Cleese', shopkeeper='Michael Palin', sketch='Cheese Shop Sketch')
ในที่นี้
kind = 'Limburger'
arguments = ("It's very runny, sir.", "It's really very, VERY runny, sir.")
keywords = { client:'John Cleese', shopkeeper:'Michael Palin', sketch:'Cheese Shop Sketch' }
ผลลัพธ์คือ
-- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch
ความรู้ใหม่
จากตัวอย่างเรียกใช้เมธอด sort()
ในการเรียงข้อมูลดัชนี ซึ่งเป็นเมธอดของลิสต์
ลิสต์นี้ได้มาจากการหาดัชนีของดิกชันนารี keyword
ได้ออกมาเป็นลิสต์ชื่อ keys
ด้วยเมธอดของดิกชันนารีคือ keys()
หากเราส่งผ่านอาร์กิวเมนต์แบบอ้างอิงซึ่งจะกลายเป็นทูเปิลแล้ว เราจะได้ความยืดหยุ่นในการกำหนดอาร์กิวเมนต์ ตัวอย่างคือ
>>> def testparm(x, *y): ... print 'x=',x,'y=',y ... >>> testparm('a',1,2,3) x= a y= (1, 2, 3)
หรือ
>>> def testparm(x, *y): ... print 'x=', x, 'y=', ... for i in y: ... print i, ... >>> testparm('a',1,2,3) x= a y= 1 2 3
ตัวอย่างในบทความต้นฉบับคือ
def fprintf(file, format, *args): file.write(format % args)
จากตัวอย่างก่อน ๆ ที่เรารู้เรื่องการผ่านค่าแบบอ้างอิงเป็นทูเปิลและดิกชันนารีแล้ว เราสามารถพลิกแพลงได้ เช่น
ในตัวอย่างนี้ใช้ลิสต์แทนทูเปิล (ถ้าไม่มีการเปลี่ยนแปลงค่า ลิสต์และทูเปิลสามารถใช้แทนกันได้แบบตรง ๆ )
>>> range(3, 6) # normal call with separate arguments [3, 4, 5] >>> args = [3, 6] >>> range(*args) # call with arguments unpacked from a list [3, 4, 5]
ตัวอย่างนี้เป็นดิกชันนารี
>>> def parrot(voltage, state='a stiff', action='voom'): ... print "-- This parrot wouldn't", action, ... print "if you put", voltage, "volts through it.", ... print "E's", state, "!" ... >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} >>> parrot(**d) -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
ยืมความสามารถเรื่อง Functional Programming แบบภาษา Lisp มาใช้
โครงสร้างชวนเวียนหัวหน่อย ดูตัวอย่างดีกว่า
แบบไม่ใช้ lambda
>>> def f(x): ... return x*2 ... >>> f(3) 6
ใช้ lambda
แบบแรก
>>> g = lambda x: x*2 >>> g(3) 6
ใช้ lambda
แบบชั่วคราวจริง ๆ
>>> (lambda x: x*2)(3) 6
อีกตัวอย่างนึง ใช้ผสมกับฟังก์ชั่น
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43
บรรทัดแรกถัดจากชื่อฟังก์ชั่น เป็นบรรทัดพิเศษที่ใส่บรรทัดข้อความอธิบายการทำงานของฟังก์ชั่น ถ้าใช้ตรีอัญประกาศ """
หรือ '''
ก็สามารถเขียนได้หลายบรรทัด
สามารถเรียกดูข้อความในบรรทัดนี้ได้จากเมธอด function_name.__doc__
ตัวอย่าง
>>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print my_function.__doc__ Do nothing, but document it. No, really, it doesn't do anything.