一,函數是什麼?
函數一詞來源于數學,但程式設計中的「函數」概念,與數學中的函數是有很大不同的,具體差別,我們後面會講,程式設計中的函數在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子過程或子程式),在Pascal中叫做procedure(過程)和function,在C中隻有function,在Java裡面叫做method。
函數能提高應用的子產品性,和代碼的重複使用率。你已經知道Python提供了許多内建函數,比如print()。但你也可以自己建立函數,這被叫做使用者自定義函數。
函數定義:函數是指一組語句的集合通過一個名字(函數名)封裝起來,要想執行這個函數,隻需要調用其函數名即可
函數特性:
- 代碼重用
- 保持一緻性
- 可擴充性
二,函數的建立
2.1格式:
python定義函數使用def關鍵字,一般格式如下:
def 函數名(參數清單):
函數體
舉個例子:
def hello():
print("hello")
hello() #調用
# 結果:hello
2.2函數名的命名規則:
- 函數名必須以下劃線或字母開頭,可以包含任意字母、數字或下劃線的組合。不能使用任何的标點符号;
- 函數名是區分大小寫的。
- 函數名不能是保留字。
2.3形參和實參
形參:形式參數,不是實際存在,是虛拟變量,在定義函數和函數體的時候使用形參,目的就是在函數調用的時候接收實參(實參個數,類型應與實參一一對應)
實參:實際參數,調用函數時候傳給函數的變量,可以是常量,變量,表達式,函數,傳給形參
差別:形參是虛拟的,不占用記憶體空間,形參變量隻有在調用時才配置設定記憶體單元,實參是一個變量,占用空間,資料傳送單向,實參傳給形參,不能形參傳給實參。
import time
times = time.strftime('%Y-%m-%d')
def func(time):
print("Now time is :%s"%times)
func(times)
# 結果:Now time is :2018-03-24
下面具體舉個例子
def show_shoppingcart():
balance = 100000
shopping_cart = [
('mac',9000),
('kindle',800),
('tesla',100000),
('python_book',120),
]
print("shopping_cart".center(50,'*'))
for i,v in enumerate(shopping_cart):
print('\033[35;1m %s: %s \033[0m'%(i,v))
expense = 0
for i in shopping_cart:
expense +=i[1]
print('\n\033[32;1m您的餘額為 %s \033[0m'%(balance-expense))
show_shoppingcart()
# 結果:
# ******************shopping_cart*******************
# 0: ('mac', 9000)
# 1: ('kindle', 800)
# 2: ('tesla', 100000)
# 3: ('python_book', 120)
#
# 您的餘額為 -9920
現在我們用一個例子說明函數的三個特性:
def action1(n):
print ('starting action1...')
with open('日志記錄','a') as f:
f.write('end action%s\n'%n)
def action2(n):
print ('starting action2...')
with open('日志記錄','a') as f:
f.write('end action%s\n'%n)
def action3(n):
print ('starting action3...')
with open('日志記錄','a') as f:
f.write('end action%s\n'%n)
action1(1)
action2(2)
action3(3)
##***************代碼重用
def logger(n):
with open('日志記錄','a') as f:
f.write('end action%s\n'%n)
def action1():
print ('starting action1...')
logger(1)
def action2():
print ('starting action2...')
logger(2)
def action3():
print ('starting action3...')
logger(3)
action1()
action2()
action3()
##***************可擴充和保持一緻
##為日志加上時間
import time
def logger(n):
time_format='%Y-%m-%d %X'
time_current=time.strftime(time_format)
with open('日志記錄','a') as f:
f.write('%s end action%s\n'%(time_current,n))
def action1():
print ('starting action1...')
logger(1)
def action2():
print ('starting action2...')
logger(2)
def action3():
print ('starting action3...')
logger(3)
action1()
action2()
action3()
函數的特性展示
三,函數的參數
- 必備參數
- 關鍵字參數
- 預設參數
- 不定長參數
3.1必需的參數:
必須參數須以正确的順序傳入函數,調用的數量必須和聲明時的一樣
def f(name,age):
print('I am %s,I am %d'%(name,age))
f('alex',18)
f('alvin',16)
3.2關鍵字參數:
關鍵字參數和函數調用關系緊密,函數調用使用關鍵字參數來确定傳入的參數值。使用關鍵字參數允許函數調用時參數的順序與聲明時不一緻,因為 Python 解釋器能夠用參數名比對參數值。
def f(name,age):
print('I am %s,I am %d'%(name,age))
# f(16,'alvin') #報錯
f(age=16,name='alvin')
3.3預設參數(預設參數):
調用函數時,預設參數的值如果沒有傳入,則被認為是預設值。下例會列印預設的age,如果age沒有被傳入:
def print_info(name,age,sex='male'):
print('Name:%s'%name)
print('age:%s'%age)
print('Sex:%s'%sex)
return
print_info('alex',18)
print_info('鐵錘',40,'female')
3.4不定長參數
你可能需要一個函數能處理比當初聲明時更多的參數。這些參數叫做不定長參數,和上述2種參數不同,聲明時不會命名。
# def add(x,y):
# return x+y
def add(*tuples):
sum=0
for v in tuples:
sum+=v
return sum
print(add(1,4,6,9))
print(add(1,4,6,9,5))
加了星号(*)的變量名會存放所有未命名的變量參數。而加(**)的變量名會存放命名的變量參數
def print_info(**kwargs):
print(kwargs)
for i in kwargs:
print('%s:%s'%(i,kwargs[i]))#根據參數可以列印任意相關資訊了
return
print_info(name='alex',age=18,sex='female',hobby='girl',nationality='Chinese',ability='Python')
###########################位置
def print_info(name,*args,**kwargs):#def print_info(name,**kwargs,*args):報錯
print('Name:%s'%name)
print('args:',args)
print('kwargs:',kwargs)
return
print_info('alex',18,hobby='girl',nationality='Chinese',ability='Python')
# print_info(hobby='girl','alex',18,nationality='Chinese',ability='Python') #報錯
#print_info('alex',hobby='girl',18,nationality='Chinese',ability='Python') #報錯
注意,還可以這樣傳參:
def f(*args):
print(args)
f(*[1,2,5])
def f(**kargs):
print(kargs)
f(**{'name':'alex'})
3.5高階函數
至少滿足下面一個條件的函數:
- 接受一個或者多個函數作為輸入
- 輸出一個函數
def add(x,y,f):
return f(x) + f(y)
res = add(3,-6,abs)
print(res)
###############
def foo():
x=3
def bar():
return x
return bar
四,函數的傳回值
要想擷取函數的執行結果,就可以用return語句把結果傳回
注意:
- 函數在執行過程中隻要遇到return語句,就會停止執行并傳回結果,so 也可以了解為 return 語句代表着函數的結束
- 如果未在函數中指定return,那這個函數的傳回值為None
- return多個對象,解釋器會把這多個對象組裝成一個元組作為一個一個整體結果輸出。
五,作用域
5.1 作用域介紹
python中的作用域分4種情況:
- L:local,局部作用域,即函數中定義的變量;
- E:enclosing,嵌套的父級函數的局部作用域,即包含此函數的上級函數的局部作用域,但不是全局的;
- G:globa,全局變量,就是子產品級别定義的變量;
- B:built-in,系統固定子產品裡面的變量,比如int, bytearray等。 搜尋變量的優先級順序依次是:作用域局部>外層作用域>目前子產品中的全局>python内置作用域,也就是LEGB。
x = int(2.9) # int built-in
g_count = 0 # global
def outer():
o_count = 1 # enclosing
def inner():
i_count = 2 # local
print(o_count)
# print(i_count) 找不到
inner()
outer()
# print(o_count) #找不到
當然,local和enclosing是相對的,enclosing變量相對上層來說也是local。
5.2 作用域産生
在Python中,隻有子產品(module),類(class)以及函數(def、lambda)才會引入新的作用域,其它的代碼塊(如if、try、for等)是不會引入新的作用域的,如下代碼:
if 2>1:
x = 1
print(x) # 1
這個是沒有問題的,if并沒有引入一個新的作用域,x仍處在目前作用域中,後面代碼可以使用。
def test():
x = 2
print(x) # NameError: name 'x2' is not defined
def、class、lambda是可以引入新作用域的。
5.3變量的修改
#################
x=6
def f2():
print(x)
x=5
f2()
# 錯誤的原因在于print(x)時,解釋器會在局部作用域找,會找到x=5(函數已經加載到記憶體),
但x使用在聲明前了,是以報錯:
# local variable 'x' referenced before assignment.
#如何證明找到了x=5呢?簡單:注釋掉x=5,x=6
# 報錯為:name 'x' is not defined
#同理
x=6
def f2():
x+=1 #local variable 'x' referenced before assignment.
f2()
5.4 global關鍵字
當内部作用域想修改外部作用域的變量時,就要用到global和nonlocal關鍵字了,當修改的變量是在全局作用域(global作用域)上的,就要使用global先聲明一下,代碼如下:
count = 10
def outer():
global count
print(count)
count = 100
print(count)
outer()
#10
#100
5.5 nonlocal關鍵字
global關鍵字聲明的變量必須在全局作用域上,不能嵌套作用域上,當要修改嵌套作用域(enclosing作用域,外層非全局作用域)中的變量怎麼辦呢,這時就需要nonlocal關鍵字了
def outer():
count = 10
def inner():
nonlocal count
count = 20
print(count)
inner()
print(count)
outer()
#20
#20
5.6小結
(1)變量查找順序:LEGB,作用域局部>外層作用域>目前子產品中的全局>python内置作用域;
(2)隻有子產品、類、及函數才能引入新作用域;
(3)對于一個變量,内部作用域先聲明就會覆寫外部變量,不聲明直接使用,就會使用外部作用域的變量;
(4)内部作用域要修改外部作用域變量的值時,全局變量要使用global關鍵字,嵌套作用域變量要使用
nonlocal關鍵字。nonlocal是python3新增的關鍵字,有了這個 關鍵字,就能完美的實作閉包了。
六,遞歸函數
定義:在函數内部,可以調用其他函數。如果一個函數在内部調用自身本身,這個函數就是遞歸函數。
執行個體1(階乘)
def factorial(n):
result=n
for i in range(1,n):
result*=i
return result
print(factorial(4))
#**********遞歸*********
def factorial_new(n):
if n==1:
return 1
return n*factorial_new(n-1)
print(factorial_new(3))
執行個體二(斐波那契數列)
def fibo(n):
before=0
after=1
for i in range(n-1):
ret=before+after
before=after
after=ret
return ret
print(fibo(3))
#**************遞歸*********************
def fibo_new(n):#n可以為零,數列有[0]
if n <= 1:
return n
return(fibo_new(n-1) + fibo_new(n-2))
print(fibo_new(3))
print(fibo_new(30000))#maximum recursion depth exceeded in comparison
遞歸函數的優點: 是定義簡單,邏輯清晰。理論上,所有的遞歸函數都可以寫成循環的方式,但循環的邏輯不如遞歸清晰。
遞歸特性:
- 1. 必須有一個明确的結束條件
- 2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
- 3. 遞歸效率不高,遞歸層次過多會導緻棧溢出(在計算機中,函數調用是通過棧(stack)這種資料結構實作的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返 回,棧就會減一層棧幀。由于棧的大小不是無限的,是以,遞歸調用的次數過多,會導緻棧溢出。)
七,内置函數
1 ,filter(function, sequence):
對sequence中的item依次執行function(item),将執行結果為True的item做成一個filter object的疊代器傳回。可以看作是過濾函數。
str = ['a', 'b','c', 'd']
def fun1(s):
if s != 'a':
return s
ret = filter(fun1, str)
print(list(ret))# ret是一個疊代器對象
2, map(function, sequence)
map()函數,可以将一個函數映射到一個可以枚舉類型上面。對sequence中的item依次執行function(item),将執行結果組成一個List傳回
另外map也支援多個sequence,當然這也要求function支援相應數量的參數輸入。
str = ['a', 'b','c','d']
def fun2(s):
return s + "alvin"
ret = map(fun2, str)
print(ret) # map object的疊代器
print(list(ret))# ['aalvin', 'balvin', 'calvin', 'dalvin']
>>> def cube(x): return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> def cube(x) : return x + x
>>> def add(x, y): return x+y
>>> map(add, range(8), range(8))
[0, 2, 4, 6, 8, 10, 12, 14]
對sequence中的item依次執行function(item),将執行結果組成一個map object疊代器傳回.
map也支援多個sequence,這就要求function也支援相應數量的參數輸入:
def add(x,y):
return x+y
print (list(map(add, range(10), range(10))))
##[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
3,reduce(function, sequence, starting_value)
對sequence中的item順序疊代調用function,如果有starting_value,還可以作為初始值調用.
from functools import reduce
def add1(x,y):
return x + y
print (reduce(add1, range(1, 101)))## 4950 (注:1+2+...+99)
print (reduce(add1, range(1, 101), 20))## 4970 (注:1+2+...+99+20)
對sequence中的item順序疊代調用function,如果有starting_value,還可以作為初始值調用,例如可以用來對List求和,示例如下:
>>> def add(x,y): return x + y
>>> reduce(add, range(1, 11))
(注:1+2+3+4+5+6+7+8+9+10)
>>> reduce(add, range(1, 11), 20)
(注:1+2+3+4+5+6+7+8+9+10+20)
4,lambda
它允許你快速定義單行的最小函數(其本質就是函數),類似C語言中的宏,可以用在任何需要函數的地方,示例如下:
>>> g = lambda x: x * 2
>>> g(3)
6
>>> (lambda x: x * 2)(3)
6
普通函數與匿名函數的對比:
#普通函數
def add(a,b):
return a + b
print add(2,3)
#匿名函數
add = lambda a,b : a + b
print add(2,3)
#========輸出===========
5
5
匿名函數的命名規則,用lamdba 關鍵字辨別,冒号(:)左側表示函數接收的參數(a,b) ,冒号(:)右側表示函數的傳回值(a+b)。
因為lamdba在建立時不需要命名,是以,叫匿名函數
5,int64和int的差別?
int是Python的基本類型,而int64是numpy中引入的一個類,即numpy.int64;
使用numpy子產品中的numpy.sum()方法得到的結果是Int64,而使用預設的sum()得到的結果是Int類型。
下面代碼中,雖然執行結果a和b的數值都是6,但是類型不同。
1 import numpy as np
2 # a 的類型是int64
3 a = np.sum([1,2,3])
4 # b 的類型是int
5 b = sum([1,2,3])
int64不會報除0的錯誤(事實上numpy中的其他類型也不會報錯,比如float64等);而int會報除0錯誤(其他基本類型也會,比如float等)
6,sorted函數
對sequence進行排序,直接看例子:
>>> s = [('a', 3), ('b', 2), ('c', 1)]
>>> sorted(s, key=lambda x:x[1])
s = [('a', 3), ('b', 2), ('c', 1)]
更多例子:
>>> l = ['foo', 'bar', 'far']
>>> map(lambda x: x.upper(), l)
['FOO', 'BAR', 'FAR']
>>> filter(lambda x: 'f' in x, l)
['foo', 'far']
>>> map(lambda x: x.upper(), filter(lambda x: 'f' in x, l))
['FOO', 'FAR']
>>> reduce(lambda a, b: a * b, xrange(1, 5)) # 計算 1*2*3*4 = 24
24
7,序列解包(for x,y in zip(keys,values):)詳解
序列解包是一個非常重要和常用的一個功能,使用序列解包可以用非常簡潔的方法完成複雜的功能。增強代碼的可讀性,減少代碼量。
zip函數接受多個(包括0個和1個)序列作為參數,傳回一個tuple清單。
7.1 使用序列解包對多個變量同時進行指派
a, b, c = 1, 2, 3
print(a, b, c)
test_tuple = (False, 3.5, 'test')
d, e, f = test_tuple
print(d, e, f)
x, y, z = map(str, range(3))
print(x, y, z)
輸出結果為:
1 2 3
False 3.5 test
0 1 2
7.2 序列解包也可以用于清單和字典
字典的話預設是對“key” 進行操作,如需對“key”----"value" 進行操作則需要使用字典的items()方法進行操作。“value” 進行操作的話就使用values進行操作。
#清單進行解包
a = [1, 2, 3, 5, 6]
b, c, d, f, g = a
print(b, c, d, f, g)
print('---------------------------')
#字典進行解包
test_dicts = {'a': 'x', 'b': 1, 'c': 3}
q, w, e = test_dicts
r, t, y = test_dicts.items()
i, o, p = test_dicts.values()
print(q, w, e)
print(r, y, t)
print(i, o, p)
輸出結果:
1 2 3 5 6
---------------------------
a b c
('a', 'x') ('c', 3) ('b', 1)
x 1 3
7.3 用序列解包同時周遊多個序列
list_1 = [1, 2, 3, 4]
list_2 = ['a', 'b', 'c']
for x, y in zip(list_1, list_2):
print(x, y)
結果:
1 a
2 b
3 c
7.4 Python3.x和Python2.x在zip函數的差別
x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]
#注意:Python3.x和Python2.x這裡的差别
#Python3.x
xyz = list(zip(x, y, z))
#Python2.x
#xyz = zip(x, y, z)
print(xyz)
#輸出結果:[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
八 函數式程式設計
學會了上面幾個重要的函數後,我們就可以來聊一聊函數式程式設計到底是個什麼鬼
一 概念(函數式程式設計)
函數式程式設計是一種程式設計範式,我們常見的程式設計範式有指令式程式設計(Imperative programming),函數式程式設計,常見的面向對象程式設計是也是一種指令式程式設計。
指令式程式設計是面向計算機硬體的抽象,有變量(對應着存儲單元),指派語句(擷取,存儲指令),表達式(記憶體引用和算術運算)和控制語句(跳轉指令),一句話,指令式程式就是一個馮諾依曼機的指令序列。
而函數式程式設計是面向數學的抽象,将計算描述為一種表達式求值,一句話,函數式程式就是一個表達式。
函數式程式設計的本質
函數式程式設計中的函數這個術語不是指計算機中的函數,而是指數學中的函數,即自變量的映射。也就是說一個函數的值僅決定于函數參數的值,不依賴其他狀态。比如y=x*x函數計算x的平方根,隻要x的平方,不論什麼時候調用,調用幾次,值都是不變的。
純函數式程式設計語言中的變量也不是指令式程式設計語言中的變量,即存儲狀态的單元,而是代數中的變量,即一個值的名稱。變量的值是不可變的(immutable),也就是說不允許像指令式程式設計語言中那樣多次給一個變量指派。比如說在指令式程式設計語言我們寫“x = x + 1”,這依賴可變狀态的事實,拿給程式員看說是對的,但拿給數學家看,卻被認為這個等式為假。
函數式語言的如條件語句,循環語句也不是指令式程式設計語言中的控制語句,而是函數的文法糖,比如在Scala語言中,if else不是語句而是三元運算符,是有傳回值的。
嚴格意義上的函數式程式設計意味着不使用可變的變量,指派,循環和其他指令式控制結構進行程式設計。
函數式程式設計關心資料的映射,指令式程式設計關心解決問題的步驟,這也是為什麼“函數式程式設計”叫做“函數式程式設計”。
二 執行個體
假如,現在你來到 baidu面試,面試官讓你把number =[2, -5, 9, -7, 2, 5, 4, -1, 0, -3, 8]中的正數的平均值,你肯定可以寫出:
#計算數組中正整數的平均值
number =[2, -5, 9, -7, 2, 5, 4, -1, 0, -3, 8]
count = 0
sum = 0
for i in range(len(number)):
if number[i]>0:
count += 1
sum += number[i]
print sum,count
if count>0:
average = sum/count
print average
#========輸出===========
30 6
5
首先循環清單中的值,累計次數,并對大于0的數進行累加,最後求取平均值。
這就是指令式程式設計——你要做什麼事情,你得把達到目的的步驟詳細的描述出來,然後交給機器去運作。
這也正是指令式程式設計的理論模型——圖靈機的特點。一條寫滿資料的紙帶,一條根據紙帶内容運動的機器,機器每動一步都需要紙帶上寫着如何達到。
那麼,不用這種方式如何做到呢?
number =[2, -5, 9, -7, 2, 5, 4, -1, 0, -3, 8]
positive = filter(lambda x: x>0, number)
average = reduce(lambda x,y: x+y, positive)/len(positive)
print average
#========輸出===========
5
這段代碼最終達到的目的同樣是求取正數平均值,但是它得到結果的方式和 之前有着本質的差别:通過描述一個清單->正數平均值 的映射,而不是描述“從清單得到正數平均值應該怎樣做”來達到目的。
再比如,求階乘
通過Reduce函數加lambda表達式式實作階乘是如何簡單:
from functools import reduce
print (reduce(lambda x,y: x*y, range(1,6)))
又比如,map()函數加上lambda表達式(匿名函數)可以實作更強大的功能:
squares = map(lambda x : x*x ,range(9))
print (squares)# <map object at 0x10115f7f0>疊代器
print (list(squares))#[0, 1, 4, 9, 16, 25, 36, 49, 64]
三 函數式程式設計有什麼好處呢?
1)代碼簡潔,易懂。
2)無副作用
由于指令式程式設計語言也可以通過類似函數指針的方式來實作高階函數,函數式的最主要的好處主要是不可變性帶來的。沒有可變的狀态,函數就是引用透明(Referential transparency)的和沒有副作用(No Side Effect)。
練習:
1,簡述普通參數,指定參數,預設參數,動态參數的差別
普通參數:以正确的順序傳入函數,調用時數量必須和聲明的一樣
指定參數:參數和函數調用關系密切,函數調用使用關鍵字參數來确定傳入的參數值,參數
允許函數調用時參數的順序和聲明時不一緻
預設參數:函數進行調用時,如果沒有新的參數傳入則預設的情況下,就調用預設參數
動态參數:個别函數能處理比當初聲明時更多的參數,這些參數就動态參數
2,寫函數,計算傳入的字元串中數字,字母,空格,以及其他的個數
def func(s):
al_num =0
space_num = 0
digit_num = 0
others_num = 0
for i in s:
if i.isdigit():
digit_num +=1
elif i.isspace():
space_num +=1
elif i.isalpha():
al_num +=1
else:
others_num +=1
return (al_num,space_num,digit_num,others_num)
result = func("asdsadjlk1212jdjakdk2 d d d d323233223下")
print(result)
result = func(" d d d d323233223下")
print(result)
3,寫函數,判斷使用者傳入的對象(字元串,清單,元組)長度是否大于5
def func(s,lis,tup):
zifuchuan = len(s)
liebiao = len(lis)
yuanzu = len(tup)
if zifuchuan>5:
print("大于5")
else:
print("小于5")
if liebiao >5:
print("大于5")
else:
print("小于5")
if yuanzu >5:
print("大于5")
else:
print("小于5")
return (zifuchuan,liebiao,yuanzu)
func('dadadad','[1,2,3]',{1,2,3})
4,寫函數監測使用者傳入的對象(字元,清單,元組)的每一個元素是否有空内容
def func(n):
for i in a:
i = str(i)
if '' in i:
return ('空格: ',i)
else:
return ('沒空格')
a = ('dasdsd dasd','ds')
res = func(a)
print(res)
5,寫函數,檢查傳入清單的長度,如果大于2,那麼僅僅保留前兩個長度的内容,并将新内容傳回給調用者
def func(li):
len_li = len(li)
if len_li>2:
print("清單長度大于2")
new_li = li[0:2]
return (new_li)
res = func([12,12,45,78,32,12])
print(res)
6,寫函數,檢查擷取傳入清單或元組的所有奇數位索引對應的元素,并将其作為新清單傳回給調用者
def func(li,tup):
li = []
tup = []
for i in range(len(li)):
if i %2 ==1:
li.append(li[i])
print(li)
for j in range(len(tup)):
if j %2 ==1:
tup.append(tup[j])
print(tup)
return (li,tup)
res = func([1,2,3,4,5,6,7,8,9],(1,2,3,11,21,4,5,6,7))
print(res)
7,寫函數,檢查傳入字典的每一個value的長度,如果大于2,那麼僅僅儲存前兩個長度的内容,并将新内容傳回給調用者
8,寫函數,計算傳入字元串中的【數字】、【字母】、【空格】和【其他】的個數
# 8,寫函數,計算傳入字元串中的【數字】、【字母】、【空格】和【其他】的個數
def func(strr):
digit_number = 0
space_number = 0
alpha_number = 0
else_number = 0
for i in strr:
if i.isdigit():
digit_number +=1
elif i.isspace():
space_number +=1
elif i.isalpha():
alpha_number +=1
else:
else_number +=1
return ("數字,空格,字母,其他内容分别有:",(digit_number,space_number,alpha_number,else_number))
res = func('sda!@#$%^&1234567dfghj da da ')
print(res)
# ('數字,空格,字母,其他内容分别有:', (7, 3, 12, 7))
此文内容參考http://www.cnblogs.com/yuanchenqi/articles/5828233.html
不經一番徹骨寒 怎得梅花撲鼻香