1. 程式人生 > >python基礎---抽象(1)

python基礎---抽象(1)

抽象就是把單一的功能提取成函式,使程式簡介易懂。

建立函式舉例

#返回一個斐波那契數列列表的函式
 def fibs(num):
    fiblist = [0,1]
    for i in range(num-2):
        fiblist.append(fiblist[-2]+ fiblist[-1])
    return fiblist

輸出:
>>> fibs(8)
[0, 1, 1, 2, 3, 5, 8, 13]

文件化函式

通過寫函式文件,讓其他使用函式的人能理解函式的作用,可以使用註釋#,亦可以直接在def語句後面或模組開頭,類開頭加字串

>>> def square(x):
    'Calculates the square of the number x'
    return x*x
>>> square.__doc__   #__doc__為函式屬性
'Calculates the square of the number x'

>>> help(square)  #也可以通過help函式得到文件字串的資訊
Help on function square in module __main__:

square(x)
    Calculates the square of the number x

引數魔法

為什麼要修改引數

使用函式改變資料結構(字典列表)是一種將程式抽象化的好方法。假設需要編寫一個儲存名字並且能用名字、中間名或性查詢聯絡人的程式,可以使用下面的資料結構:

>>> storage = {}
>>> storage['first'] = {}
>>> storage
{'first': {}}
>>> storage['middle'] = {}
>>> storage['last'] = {}
>>> storage
{'first': {}, 'middle': {}, 'last': {}}
>>> me = 'Magnus Lie Hetland'
>>> storage['first'
]['Magnus'] = [me] >>> storage {'first': {'Magnus': ['Magnus Lie Hetland']}, 'middle': {}, 'last': {}} >>> storage['middle']['Lie'] = [me] >>> storage['last']['Hetland'] = [me] #得到所有註冊的中間名為Lie的人 >>> storage['middle']['Lie'] ['Magnus Lie Hetland']

擴充套件列表,在存入一個名字時:

>>> my_sister = 'Anne Lie Hetland'
#字典方法setdefault與get方法類似,能夠獲取與給定鍵相關聯的值,setdefault的特有用處是當字典中還不含有給定的鍵時,能夠設定相應的鍵值
#當鍵不存在時,setdefault返回預設值None,並且更新字典;若鍵存在,返回其對應的值
>>> storage['first'].setdefault('Anne', []).append(my_sister)   
>>> storage['middle'].setdefault('Lie', []).append(my_sister)
>>> storage['last'].setdefault('Heland', []).append(my_sister)
>>> storage['first']['Anne']
['Anne Lie Hetland']
>>> storage['middle']['Lie']
['Magnus Lie Hetland', 'Anne Lie Hetland']
>>> storage
{'first': {'Magnus': ['Magnus Lie Hetland'], 'Anne': ['Anne Lie Hetland']}, 'middle': {'Lie': ['Magnus Lie Hetland', 'Anne Lie Hetland']}, 'last': {'Hetland': ['Magnus Lie Hetland'], 'Heland': ['Anne Lie Hetland']}}

若像上述的方法更新列表中的人名非常繁瑣,很多重複的程式碼疊加
抽象的要點就是隱藏細節,因此抽象為函式
下面是初始化資料結構的函式的定義和使用:

>>> def init(data):
    data['first'] = {}
    data['middle'] = {}
    data['last'] = {}


>>> storage = {}
>>> init(storage)
>>> storage
{'first': {}, 'middle': {}, 'last': {}}

下面是獲得名字的函式:

>>> def lookup(data, lable, name):
    return data[lable].get(name)

儲存列表的函式:

>>> def store(data, full_name):                       #使用data和full_name進入函式,從函式外部獲取值
    names = full_name.split()                     #通過拆分full_name,得到一個列表,split預設使用空格作為分隔符分隔字串
    if len(names) == 2: names.insert(1, '')       #如果只有首名和末名,則插入空字串作為中間名
    lables = 'first', 'middle', 'last'            #用元組儲存標籤,也可使用列表
    for name,lable in zip(names,lables):
        people = lookup(data, lable, name)
        if people:
            people.append(full_name)
        else:
            data[lable][name] = [full_name]

上面幾個函式的使用:

>>> Mynames = {}
>>> init(Mynames)
>>> store(Mynames, 'Magnus Lie Hetland')
>>> lookup(Mynames, 'middle', 'Lie')
['Magnus Lie Hetland']
>>> store(Mynames, 'Robin Hood')
>>> store(Mynames, 'Robin Locksley')
>>> lookup(Mynames, 'first', 'Robin' )
['Robin Hood', 'Robin Locksley']
>>> store(Mynames, 'Mr.Gumby' )
>>> lookup(Mynames, 'middle', '')
['Robin Hood', 'Robin Locksley']
>>> lookup(Mynames, 'middle', ' ')
>>> store(Mynames, 'Mr Gumby' )
>>> lookup(Mynames, 'middle', ' ')
>>> lookup(Mynames, 'middle', '')
['Robin Hood', 'Robin Locksley', 'Mr Gumby']
>>> store(Mynames, 'Mr. Gumby' )
>>> lookup(Mynames, 'middle', '')
['Robin Hood', 'Robin Locksley', 'Mr Gumby', 'Mr. Gumby']

關鍵字引數和預設值

>>> def hello(name, greeting = 'Hello', punctuation = '!'):  #位置引數和關鍵字引數混用的情況,在定義函式時給關鍵字引數賦預設值
    print("%s, %s%s" % (greeting, name, punctuation))

#關鍵字引數在有預設值的情況下,呼叫函式的時候,可以不傳入引數 
>>> hello('mart')
Hello, mart!
>>> hello('mart', 'Howday')
Howday, mart!
>>> hello('mart', 'howday', '...')
howday, mart...
>>> hello('mart', punctuation = '.')
Hello, mart.
>>> hello('mart', greeting = 'Top of the morning to ya')
Top of the morning to ya, mart!
>>> hello()
Traceback (most recent call last):
  File "<pyshell#179>", line 1, in <module>
    hello()
TypeError: hello() missing 1 required positional argument: 'name'

收集引數(函式定義時候使用* 或 **)

>>> def print_params(x, y, z=3, *pospar, **keypar):  #  *表示收集位置引數--收集為元組,  **表示收集關鍵字引數--收集為字典
    print(x, y, z)
    print(pospar)
    print(keypar)


>>> print_params(1,2,3,4,5,6,7,foo=1,bar=2)
1 2 3
(4, 5, 6, 7)
{'foo': 1, 'bar': 2}
>>> print_params(1,2)
1 2 3
()
{}

引數收集的逆過程(在呼叫函式時候使用* 或 **)

>>> args = {'name': 'Mr.Gumby', 'age': 18}
>>> def with_stars(**kwds):
    print(kwds['name'], 'is', kwds['age'], 'years old')
>>> def without_stars(kwds):
    print(kwds['name'], 'is', kwds['age'], 'years old')
>>> with_stars(**args)
Mr.Gumby is 18 years old

>>> without_stars(args)
Mr.Gumby is 18 years old
>>> def add(x,y): return x+y
>>> add(1,2)
3
>>> params = (1,2)
>>> add(*params)
3

引數使用綜合練習

>>> def story(**kwds):
    return 'Once upon a time, there was a %(job)s called %(name)s.' % kwds

>>> print(story(job = 'king', name = 'Gumby'))
Once upon a time, there was a king called Gumby.
>>> print(story(name = 'Sir Robin', job = 'brave knight'))
Once upon a time, there was a brave knight called Sir Robin.
>>> params = {'name': 'Python', 'job': 'a language'}
>>> print(story(**params))
Once upon a time, there was a a language called Python.
>>> del params
>>> params
Traceback (most recent call last):
  File "<pyshell#237>", line 1, in <module>
    params
NameError: name 'params' is not defined
>>> params = {'name': 'Python', 'job': 'a language'}
>>> del params['job']
>>> params
{'name': 'Python'}
>>> print(story(job = 'stroke of genius', **params))
Once upon a time, there was a stroke of genius called Python.
>>> 

>>> def power(x, y, *others):
    if others:
        print("Received redundant parameters:", others)
    return pow(x,y)

>>> power(2,3)
8
>>> power(3,2)
9
>>> power(y=3, x=2)
8
>>> params = (5,)*2
>>> params
(5, 5)
>>> power(*params)
3125
>>> power(3, 3, 'Hello, word')
Received redundant parameters: ('Hello, word',)
27



>>> def interval(start, stop=None, step=1):
    'Imitates range() for step > 0'
    if stop is None:
        start, stop = 0, start
    result = []
    i = start
    while i<stop:
        result.append(i)
        i += step
    return result

>>> interval(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> interval(1, 5)
[1, 2, 3, 4]
>>> interval(3,12,4)
[3, 7, 11]
>>> power(*interval(3,7))
Received redundant parameters: (5, 6)
81
>>> 

遞迴

經典1 — 階乘

n的階乘定義為 n * (n-1) * (n-2) * … * 1 應用—計算將n個人排為一行共有多少種方法

#第一種方法:迴圈
>>> def factorial(n):
    result = n
    for i in range(1, n):
        result *= i
    return result

#第二種方法:遞迴 
>>> def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

經典2 — 冪

#第一種方法,使用內建函式
>>> power(2,3)
8

#第二種方法,迴圈
>>> def power(x, n):
    result = 1
    for i in range(n):
        result *= x
    return result

#第三種方法,遞迴
>>> def power(x, n):
    if n == 0:       #冪指數為0的任何整數都為1
        return 1
    else:
        return x * power(x, n-1)

**如果函式或者演算法很複雜,而且難懂的話,在實現之前用自己的話明確的定義一下是很有幫助的

經典3 — 二分法查詢

語言描述演算法:

  • 如果上下限相同,那麼就是數字所在的位置,返回;
  • 否則找到兩者的中間點(上下線平均值),查詢數字是在左側還是在右側,繼續查詢數字所在的那半部分
#演算法返回的是要查詢的數字對應的序列的索引,  sequence對應的是要查詢的序列,number對應要查的數,前提是預設number一定在sequence中
>>> def search(sequence, number, lower = 0, upper = None):
    if upper is None: upper = len(sequence) - 1
    if lower == upper:
        assert number == sequence[lower]
        return upper
    else:
        middle = (lower + upper) // 2
        if number > sequence[middle]:
            return search(sequence, number, middle+1, upper)
        else:
            return search(sequence, number, lower, middle)

>>> seq = [34, 67,8, 123, 4, 100, 95]
>>> seq.sort()
>>> seq
[4, 8, 34, 67, 95, 100, 123]
>>> search(seq, 34, 1, 7)
2
>>> search(seq, 100)
5

其實可以直接使用index方法