目錄
上篇文章思考題
簡介
函數長什麼樣子?
調用函數
位置傳參與關鍵字傳參
傳參是值傳遞還是引用傳遞
定義函數
參數
預設參數
關鍵字參數
參數組
傳回值
指定參數、傳回值類型
内置函數
标準類型函數
dir
help
id
len
str
type
數字類型函數
轉換工廠函數
功能函數
用于可疊代對象的函數
思考題
上篇文章思考題
Python-字典總結(操作符、方法、内置函數)
>>> d = {(1,):2}
>>> d = {(1,[1,2]):2}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
元組中不能含有清單,清單是不可哈希的,包含清單的元組也就無法哈希。這個元組的"不可變"還是有很大的讨論空間,有時間再詳細看看内部原理。
簡介
函數是對程式邏輯進行結構化或過程化的一種程式設計方法。能将整塊代碼巧妙地隔離成易于管理的小塊,把重複代碼放到函數中而不是進行大量的拷貝一這樣既能節省空間,也有助于保持一緻性,因為你隻需改變單個的拷貝而無須去尋找再修改大量複制代碼的拷貝。
函數長什麼樣子?
這是一個很簡單的求和函數:
def plus(a, b):
"""
:param a: a number
:param b: a number
:return: a+b
"""
return a + b
可以看到使用關鍵字def引入一個函數,然後是函數名,括号裡面a,b是兩個參數,使用關鍵字return進行傳回,a+b是傳回值。
三引号之間的是注釋,寫注釋是一個很好的習慣,通過參數和傳回值可以讓和你合作的人不用看函數内的代碼就知道函數的作用以及該怎麼調用。
我們來看一下平常用的很多的輸出函數,在builtins.py中,是一個内置函數,使用pycharm時,你可以寫出print()後選中print,按Ctrl+B跳轉到以下代碼:
def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
"""
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
"""
pass
作用是将值列印到流或系統标準輸出(預設情況下)。
值使用逗号隔開,後面有幾個預設參數(後面講),我們常用的是sep和end,一個用來分隔值,一個用于末尾。
不填預設值時:
>>> print('lady','killer')
lady killer
使用關鍵字參數填寫預設值(後面講)
>>> print('lady','killer',sep=';')
lady;killer
>>> print('lady','killer',end=';')
lady killer;>>>
參數數量不對,關鍵字錯誤,類型錯誤等會顯示TypeError
>>> print('lady','killer',edn=';')
TypeError: 'edn' is an invalid keyword argument for print()
()操作符是函數調用,函數的名字你可以認為是指針/引用,函數名字後面有()時,函數體内的代碼才會運作。
>>> display=print
>>> display('lady','killer')
上面代碼我使用display變量讓其指向print所指的函數,再使用()調用函數也可進行輸出。()操作符在面向對象時也可用作類的執行個體化。
代碼:
def function(x, lst):
print('函數内x修改前:', id(x), x)
print('函數内lst修改前:', id(lst), lst)
x += 1
lst.append(x)
print('函數内x修改後:', id(x), x)
print('函數内lst修改後:', id(lst), lst)
return x, lst
x = 3
lst = [3]
print('函數外x調用前:', id(x), x)
print('函數lst外調用前:', id(lst), lst)
x_return, lst_return = function(x, lst)
print('函數外x調用後:', id(x), x)
print('函數外lst調用後:', id(lst), lst)
print('傳回的x:', id(x_return), x_return)
print('傳回的lst:', id(lst_return), lst_return)
結果:
函數外x調用前: 140730711241024 3
函數lst外調用前: 1739892740680 [3]
函數内x修改前: 140730711241024 3
函數内lst修改前: 1739892740680 [3]
函數内x修改後: 140730711241056 4
函數内lst修改後: 1739892740680 [3, 4]
函數外x調用後: 140730711241024 3
函數外lst調用後: 1739892740680 [3, 4]
傳回的x: 140730711241056 4
傳回的lst: 1739892740680 [3, 4]
傳參引用傳遞:修改前與調用前的id一樣
傳回引用傳遞:修改後與傳回的id一樣
不可變類型變量x,傳參引用傳遞,傳回引用傳遞,由于不可變,故指向3和4的變量都叫x(實參和形參),我們輸出的修改後的x是指向4的x,指向3的x未變。
可變類型變量lst,傳參引用傳遞,傳回引用傳遞,由于可變,故id一直不變。
總結:函數傳參是引用傳遞,函數外一直不變,對于不可變類型,可以通過傳回修改後的引用來改變它(指向其他地方)。
我們定義一個簡單的求x的n次幂的函數:
def power(x, n):
return x ** n
print(power(2, 2))
print(power(3, 2))
print(power(4, 2))
print(power(2, 3))
得到結果:
4
9
16
8
我們定義了一個傳回x的n次幂的函數,調用函數的人說,我大部分情況下都是想要x的平方,我懶得寫2,這個時候你讓他滾可以使用預設參數。
def power(x, n=2):
return x ** n
print(power(2))
print(power(3))
print(power(4))
print(power(2, 3))
這樣,得到一樣的結果,當參數特别多而有些參數大部分情況下不會改變時可以使用預設參數,也可以增強函數的健壯性。
注意: 預設值隻會執行一次。這條規則在預設值為可變對象(清單、字典以及大多數類執行個體)時很重要。比如,下面的函數會存儲在後續調用中傳遞給它的參數:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
結果為:
[1]
[1, 2]
[1, 2, 3]
如果你不想要在後續調用之間共享預設值,你可以這樣寫這個函數:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
關鍵字參數在調用函數時使用過了,使用形如
kwarg=value
的關鍵字參數來調用函數。像print('lady','killer')是位置參數,python會根據參數前後位置進行比對,關鍵字參數必須跟随在位置參數的後面,否則會出現文法錯誤,例如:
>>> display(sep=';','killer')
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> display('lady','killer',end=';',sep='&')
lady&killer;>>>
關鍵字參數之間是不需要按定義函數時的順序填寫的(此時,我的display和print在互動式指令視窗是一樣的)。
這個時候調用函數的人說,我需要你完成一個複雜的函數,有很多的參數,你可以說老子辭職不幹了使用參數組對參數進行打包。python 提供了兩種,一種是元組,就是你經常看到的*args,另一個是字典,就是你經常看到的**kwargs。
在前面我們提到的print函數就把需要輸出的很多value打包成了一個元組。
我們定義一個學生函數,列印學生的id、科目分數,總分和其他資訊。
def student(id, *subjects, **more_info):
print('id:', id)
print('math:', subjects[0])
print('english:', subjects[1])
print('allscore:', sum(subjects))
print('name:', more_info['name'])
print('school:', more_info['school'])
print('classroom:', more_info['classroom'])
student(2, 80, 99, name='frank', school='computer', classroom='1114')
id: 2
math: 80
english: 99
allscore: 179
name: frank
school: computer
classroom: 1114
可以看到,python會自動的按照順序填寫好。
當然,大部分情況下是因為調用函數的人擁有的資料也是這個資料結構(得到的json資料等),此時可以這樣調用:
subjects = (80, 99)
more_info = {'name': 'frank', 'school': 'computer', 'classroom': '1114'}
student(2, *subjects, **more_info)
print(*subjects)得到的是 80 99 而不是 (80,99),因為print沒把subject作為一個value,而是拆成了多個(這是清單、元組兩篇文章埋下的坑)。
不像C++中函數前需要指定函數的傳回值類型
int plus(int a, int b)
{
return a+b;
}
python中函數可以不指定傳回值的類型,也可以傳回多個值,使用逗号分隔。
def sum_multiplication(a, b):
return a + b, a * b
res = sum_multiplication(2, 3)
print(res)
(5, 6)
可以看到傳回值是一個元組,你也可以使用對應的個數直接解析到每個傳回值
sums, multiplication = sum_multiplication(2, 3)
print(sums, multiplication)
5 6
使用冒号:和箭頭->
def plus(a: int, b: int) -> int:
"""
:param a: a number
:param b: a number
:return: a+b
"""
return a + b
print(type(plus(3, 4)))
print(plus(3, 4))
<class 'int'>
7
傳入字元串:
print(type(plus('3', '4')))
print(plus('3', '4'))
<class 'str'>
34
pycharm給出警告,僅此而已,畢竟python是動态語言,看python源代碼中的函數也沒看見過指定,如果非要進行類型檢查,你可以自己寫,使用isinstance等函數判斷。這個指定一般是在leetcode這樣的oj網站經常出現。
函數 | 作用 |
---|---|
dir() | 如果沒有實參,則傳回目前本地作用域中的名稱清單。如果有實參,它會嘗試傳回該對象的有效屬性清單。 |
help() | 如果沒有實參,解釋器控制台裡會啟動互動式幫助系統。如果實參是一個字元串,則在子產品、函數、類、方法、關鍵字或文檔主題中搜尋該字元串,并在控制台上列印幫助資訊。如果實參是其他任意對象,則會生成該對象的幫助頁。 |
id() | 傳回對象的“辨別值”。該值是一個整數,在此對象的生命周期中保證是唯一且恒定的。兩個生命期不重疊的對象可能具有相同的l值。 |
len() | 傳回對象的長度(元素個數)。 |
str() | 傳回一個str 版本的 object 。 |
type() | 傳入一個參數時,傳回 object 的類型。 傳回值是一個 type 對象,通常與object.__class__所傳回的對象相同。 |
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> help(list.insert)
Help on method_descriptor:
insert(self, index, object, /)
Insert object before index.
>>> a = 3
>>> b = 3
>>> id(a)
140707324522816
>>> id(b)
>>> b = 4
140707324522848
>>> l = [1,2]
>>> t = [1,2]
>>> id(l)
2141070401288
>>> id(t)
2141071612360
>>> t=l
不可變類型的id可能相同(我嘗試的一直相同),可變類型一般指派後才會相同。
>>> len(l)
2
>>> str(l)
'[1, 2]'
>>> type(l)
<class 'list'>
bool(x) | 傳回一個布爾值, 或者 。 x 使用标準的真值測試過程來轉換。如果 x 是假的或者被省略,傳回 ;其他情況傳回 。 |
chr(i) | 傳回 Unicode 碼位為整數 i 的字元的字元串格式。 |
float(x) | 傳回從數字或字元串 x 生成的浮點數。 如果實參是字元串,則它必須是包含十進制數字的字元串,字元串前面可以有符号,之前也可以有空格。可選的符号有 和 ;實參也可以是 NaN(非數字)、正負無窮大的字元串。 |
hex(x) | 将整數轉換為以“0x”為字首的小寫十六進制字元串。 |
int(x,base=10) | 傳回一個使用數字或字元串 x 生成的整數對象,或者沒有實參的時候傳回 |
abs() | 傳回一個數的絕對值。實參可以是整數或浮點數。如果實參是一個複數,傳回它的模。 |
(a, b) | 它将兩個(非複數)數字作為實參,并在執行整數除法時傳回一對商和餘數。對于混合操作數類型,适用雙目算術運算符的規則。對于整數,結果和 一緻。對于浮點數,結果是 ,q 通常是 但可能會比 1 小。 |
(x, y[, z]) | 傳回 x 的 y 次幂;如果 z 存在,則對 z 取餘(比直接 計算更高效)。兩個參數形式的 等價于幂運算符: |
(number[, ndigits]) | 傳回 number 舍入到小數點後 ndigits 位精度的值。 如果 ndigits 被省略或為 ,則傳回最接近輸入值的整數。 |
bool
傳回False的有以下三類:
- 被定義為假值的常量:
None
False
- 任何數值類型的零: ,
0.0
0j
Decimal(0)
Fraction(0, 1)
- 空的序列和多項集:
''
()
[]
{}
set()
range(0)
>>> bool(None)
False
>>> bool(0)
>>> bool(())
>>> bool(l)
True
chr
>>> chr(97)
'a
chr的逆函數是ord
ord
>>> ord('a')
97
float
>>> float(1.23)
1.23
>>> float('-1.23')
-1.23
>>> float('2e-3')
0.002
>>> float('inf')
inf
hex
>>> hex(10)
'0xa'
>>> hex(-255)
'-0xff'
int
>>> int(23.5)
23
>>> int('010',8)
>>> int('010',16)
abs
>>> abs(-5)
5
>>> abs(-2.5)
2.5
divmod
>>> divmod(10,3)
(3, 1)
>>> divmod(10,2.5)
(4.0, 0.0)
pow
>>> pow(2,5)
32
>>> pow(2,5,10)
round
>>> round(2.45)
>>> round(2.45,1)
dict() | 建立一個新的字典。 |
list() | 雖然被稱為函數,list實際上是一種可變序列類型, |
set() | 傳回一個新的 對象,可以選擇帶有從 iterable 擷取的元素。 |
tuple() | 雖然被稱為函數,但tuple實際上是一個不可變的序列類型, |
max() | 傳回可疊代對象中最大的元素,或者傳回兩個及以上實參中最大的。 |
min() | 回可疊代對象中最小的元素,或者傳回兩個及以上實參中最小的。 |
sorted() | 根據 iterable 中的項傳回一個新的已排序清單。 |
(iterable[, start]) | 從 start 開始自左向右對 iterable 中的項求l 和并傳回總計值。 start 預設為 |
dict
>>> dict()
{}
>>> dict({'one':1,'two':2})
{'one': 1, 'two': 2}
>>> dict(one=1,two=2)
更多字典相關内容:Python-字典總結(操作符、方法、内置函數)
list
>>> list((3,6,'7',[5,4]))
[3, 6, '7', [5, 4]]
更多清單相關内容:Python-清單總結(操作符、方法、内置函數、相關子產品)
set
>>> set([1,2,3])
{1, 2, 3}
更多集合相關内容:Python-集合類型set與frozenset(操作符、方法、内置函數)
turple
>>> tuple([1,2,'3',{'one':1,'two':2}])
(1, 2, '3', {'one': 1, 'two': 2})
更多元組相關内容:Python-元組總結(操作符、方法、内置函數、相關子產品)
max、min、sorted、sum
>>> l = [1,2,3,4,5,9,8,7,6,10]
>>> max(l)
10
>>> min(l)
1
>>> sorted(l)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> sum(l)
55
參考:python 3.7.8-内置函數
map等函數将在下一篇文章中提到,其餘的請讀者自行閱讀上方官方文檔。
思考題
1.将函數長什麼樣子?一節中的plus函數改為一個可以接受多個參數并傳回參數和的函數。
2.在預設參數一節中,我将power(x,n)改為了n有預設值,即power(x,n=2),請将x設定為有預設值2。
答案見:Python-命名空間和變量作用域詳解(global、nonlocal)