Python基礎之函數

  咱們能夠用一段代碼來實現咱們須要的功能,可是當咱們須要重複使用這段代碼時,複製粘貼並非一個酷的方法,咱們能夠用到函數來實現這一需求python

1、函數定義linux

函數是邏輯結構化和過程化的一種編程方法,經過一個函數名封裝好一串用來完成某一特定功能的代碼編程

函數的定義:緩存

def 函數名(參數1,參數2....):閉包

  ''註釋''app

  函數體 ide

def func1():  #定義函數
    print('this is a function')  #函數體
func1()  #調用函數
#一般無參函數不須要返回值,有參函數須要有返回值
def
func1(name):  #帶參數的形式 print('%s is a good man'%name) func1('egon')
#關於函數的返回值,若是沒有指定,默認是None
#函數與過程的定義就是過程沒有返回值,用完以後就沒有了,而函數有返回值
def
func1(name): print('%s is a good man'%name) print(func1('egon')) 

-->  egon is a good man函數

    Nonethis

函數的優勢:1.代碼重用url

      2.保持一致性,易於維護

      3.可擴展性好

注意:1.函數必須先定義,在使用,和變量相似,在定義前使用會報錯

   2.函數在定義階段只檢測語法錯誤,不會執行代碼,因此即便在函數體內有未定義的變量名,在函數未調用前也不會報錯

   3.函數的返回值能夠是任意類型,若是是返回多個值,必定是元組形式

   4.return 的做用是終止函數的執行,return只執行一次,後面的內容不執行

2、函數參數

函數的參數分爲形式參數和實際參數,在函數定義的時候,函數名後面括號裏的就是形式參數,在函數調用的時候,傳遞的參數是實際參數。形式參數只在函數內部有效,外部沒法引用。

1.形參

1)位置參數:按照從左到右的順序依次定義的參數 def foo(x,y,z)

  位置形參必須被傳值,且多一個少一個都不行

2)默認參數:在函數定義階段就已經爲形參賦值,調用階段不賦值也會有默認值 def foo(x,y=10)

  值常常變化的狀況,一般定義成位置參數,可是值在多數狀況下不變的狀況下,能夠定義成默認參數

注意:

a.默認參數必須放在位置參數後面

b.默認參數一般定義成不可變類型

c.默認參數只在定義時被賦值一次

3)命名關鍵字參數:def register(*,name,age) *後面定義的形參,必須被傳值,且必須以關鍵字的形式傳值

2.實參

1)位置實參:與位置形參一一對應

2)關鍵字參數:實參在定義時,按照key-values的形式定義

  def foo(x,y)

  foo(x=1,y=2)

  關鍵字參數能夠不用向位置參數同樣與形參一一對應,能夠打破順序限制

注意:a.位置參數和關鍵字參數混合使用的時候,位置參數必須在關鍵字參數前面

   b.既能夠是位置實參形式,也能夠是關鍵字實參形式,可是一個形參只能傳值一次

3)可變長參數:

  按位置定義的可變長參數用*表示

  按關鍵字定義的可變類型的參數用**表示  

def func(x,y,*args):
    print(x,y,args)
func(1,2,3,4,5)  --->1 2 (3 4 5)

#遇到*就是位置參數,把*後面的所有拆開,再一一匹配,多餘的就以元組的形式存放到一塊兒

def func(x,y,**kwargs):
    print(x,y,kwargs)
func(1,y=2,z=3,a=1,b=2)---->1 2 {'z': 3, 'a': 1, 'b': 2}

#遇到**就是關鍵字參數,把**後面的所有拆成關鍵字,再一一匹配,多餘的以字典形式存放到一塊兒

def wrapper(*args,**kwargs):能夠接受任意形式,任意長度的參數

參數的定義順序:x,y=1,*args,z,**kwargs,分別是位置參數,默認參數,可變長位置參數,命名關鍵字參數,可變類型參數

但須要注意的是,這些參數並不會同時所有出現

3、名稱空間和做用域

名稱空間存放名字和值的綁定關係,以key-value 的形式

在Windows命令提示行中輸入命令:import this ,在最後一行會看到這樣一句話:

  Namespaces are one honking great idea -- let's do more of those!

名稱空間分爲三種:

1)內置名稱空間:Python自帶的,如print,int,len....當Python解釋器啓動的時候,就會生成內置名稱空間

2)全局名稱空間:文件級別定義的名字會存放到全局名稱空間,執行Python程序的時候產生,簡單點說就是沒有縮進的變量名

3)局部名稱空間:定義在函數(或模塊、類)內部的名字,只有在函數(模塊、類)調用的時候才生效,調用結束後就會釋放

加載順序是:內置名稱空間-->全局名稱空間-->局部名稱空間

取值順序是:局部名稱空間-->全局名稱空間-->內置名稱空間

4、函數嵌套和做用域

1.函數嵌套包括函數的嵌套調用和函數的嵌套定義

函數嵌套調用能夠用求最大值的例子來講明:

def max2(x,y):
    if x > y:
        return x
    else:
        return y
def max4(a,b,c,d):
    res1=max2(a,b) #23
    res2=max2(res1,c) #23
    res3=max2(res2,d) #31
    return res3

print(max4(11,23,-7,31))

函數嵌套定義:

def f1():
    def f2():
        def f3():
            print('from f3')
        print('from f2')
        f3()
    print('from f1')
    f2()
# print(f1)
f1()

2.做用域

1)全局做用域:內置名稱空間與全局名稱空間的名字屬於全局範圍,在整個文件的任意位置都能引用

2)局部做用域:屬於局部範圍,只在函數內部能夠被引用,局部有效

必定要注意局部變量和全局變量的做用範圍,在局部修改全局變量會出錯,在全局範圍引用局部變量也會出錯

做用域在函數定義時就已經固定了,不會因調用位置而改變

可是若是必定要在局部修改全局變量,也是用辦法的,就是在要修改的變量前加一個global

x=1
def foo():
    x=10
    print(x)        

foo()       #10
print(x)    #1
x=1
def foo():
    global x
    x=10
    print(x)

foo()       #10
print(x)    #10
def foo():
    x=1
    def f2():
        x+=x
        return x
    return f2()

print(foo())        #會報錯UnboundLocalError: local variable 'x' referenced before assignment

def foo():
    x=1
    def f2():
        nonlocal x  #告訴Python解釋器,這裏的x不是局部變量,只會找函數內部的,不會修改全局變量
        x+=x
        return x
    return f2()

print(foo())    #會打印出修改後的x的值,2

5、閉包函數

定義在函數內部的函數,該內部函數包含對外部做用域,而非全局做用域的名字的引用,那麼該內部函數稱爲閉包函數

name='egon'
def func():
    name='alex'
    def bar():
        print(name)
    return bar

f=func()        #f就是閉包函數
print(f.__closure__[0].cell_contents) #該命令能夠查看閉包函數外面包了什麼東西------>alex

閉包函數的特色:a.自帶做用域,b.延遲計算(f只是拿到了函數的內存地址,何時用,加括號就能夠運行)

閉包函數最基本的形式:

def 外部函數名():

  內部函數須要的變量

  def 內部函數名():

    引用外部變量

  return 內部函數名

6、裝飾器

1.開放封閉原則:對擴展是開放的,對修改是封閉的

2.裝飾器本質是任意可調用的對象,被裝飾對象也是任意可調用的對象

3.裝飾器的功能是:在不修改被裝飾對象源代碼及調用方式的前提下,爲其添加新的功能

4.裝飾器語法:在被裝飾對象的正上方的單獨一行,寫上@裝飾器名字

5.有多個裝飾器的時候,每行一個,執行時從上往下運行

6.被裝飾函數有參數的狀況:寫成(*args,**kwargs)的形式

裝飾器示例一:

#實現緩存網頁內容的功能,下載的頁面存放於文件中,若是文件內有值(文件大小不爲0),
# 就優先從文件中讀取網頁內容,不然,就去下載,而後存到文件中
from urllib.request import urlopen
import os

cache_path=r'C:\untitled\0615Python第8天\cache_file.txt'
def make_cache(func):
    def wrapper (*args,**kwargs):
        if os.path.getsize(cache_path):
            #有緩存
            print('\033[45m========>有緩存\033[0m')
            with open(cache_path,'rb') as f:
                res=f.read()
        else:
            res=func(*args,**kwargs)#下載
            with open(cache_path,'wb') as f:#製做緩存
                f.write(res)
        return res
    return wrapper


@make_cache

def get(url):
    return urlopen(url).read()


print(get('https://www.python.org'))

裝飾器示例二:

#爲多個函數加上認證的功能(用戶的帳號密碼來源於文件),要求登陸成功一次,後續的函數都無需再輸入用戶名和密碼
db_dic={
    'egon':'123',
    'alex':'alex3714',
    'yuanhao':'smallb'
}


db_path=r'C:\untitled\0615Python第8天\db_dic.txt'

with open(db_path,'w',encoding='utf-8') as f:
    f.write(str(db_dic))

login_dic={
    'user':None,
    'status':False,
}

def auth(func):
    def wrapper(*args,**kwargs):

        #加一個驗證狀態的字典,若是已經登陸成功,下次使用就不用從新驗證
        if login_dic['user'] and login_dic['status']:
            res=func(*args,**kwargs)
            return res
        else:
            name=input('name:')
            password=input('password:')
            with open(db_path, 'r', encoding='utf-8') as f:
                auth_dic = eval(f.read())
            if name in auth_dic and password==auth_dic[name]:
                print('login ok')
                login_dic['user']=name
                login_dic['status']=True
                res=func(*args,**kwargs)
                return res
            else:
                print('error')
    return wrapper

@auth
def index():
    print('welcom to the page')

@auth
def home(name):
    print('welcom  to %s\'s home page'%name)


index()
home('egon')

7、迭代器

1.對於字符串、列表、元組的數據類型,咱們能夠依據索引來實現迭代的效果,可是字典、集合這種沒有索引的數據類型,就須要其餘方式

2.Python爲了提供一種不依賴索引的迭代方式,爲一些對象內置了__iter__方法,obj.__iter__()獲得的結果就是迭代器

獲得的迭代器既有.__iter__方法,又有.__next__方法

3.迭代器的優勢:

  a.提供了一種不依賴索引的取值方式

  b.惰性計算,節省內存

4.迭代器的缺點:

  a.取值不如按照索引取值方便

  b.一次 性的,取值只能日後走,不能往前退

  c.沒法獲取迭代器的長度

5.for循環實際上會默認調用.__iter__方法

6.判斷是不是可迭代對象和迭代器,能夠用命令

print(isinstance(str1,Iterable)) --->判斷是否爲可迭代對象

print(isinstance(str1,Iterator)) --->判斷是否爲迭代器

8、生成器函數(語句形式和表達式形式)

1.生成器函數:函數體內包含有yield關鍵字,該函數的執行結果就是生成器

2.生成器實際就是迭代器的一種

3.yield的功能:

  a.與return相似,均可以返回值,但不同的地方在於yield返回屢次值,而return只能返回一次值
  b.爲函數封裝好了__iter__和__next__方法,把函數的執行結果作成了迭代器
  c.遵循迭代器的取值方式obj.__next__(),觸發的函數的執行,函數暫停與再繼續的狀態都是由yield保存的
4.生成器語句形式應用實例

 1 #模擬linux中tail -f a.txt|grep 'error' |grep '404'的功能
 2 import time
 3 def tail(filepath,encoding='utf-8'):
 4     with open(filepath,encoding='utf-8') as f:
 5         f.seek(0,2)  #以末尾爲開始位,第0個
 6         while True:
 7             line=f.readline()
 8             if line:
 9                 yield line
10             else:
11                 time.sleep(0.5)
12 
13 def grep(lines,pattern):
14     for line in lines:
15         if pattern in line:
16             # print(line)
17             yield line
18 
19 g1=tail('a.txt')
20 g2=grep(g1,'error')
21 g3=grep(g2,'404')
22 
23 for i in g3:
24     print(i)
View Code

5.生成器的表達式形式

def foo():
    print('starting')
    while True:
        x=yield #默認就是yield None
        print('value :',x)

g=foo() 
next(g)  #初始化,等同於g.send(None)
g.send(2)  

將yield賦值給一個變量如x=yield,而後用send()傳值,但注意要先作一個相似初始化的操做

g.send(2)的操做實際是先把2傳值給yield,再由yield傳值給x,send()既有傳值的效果,又有next()的效果

生成器表達式形式應用示例

 1 def init(func):
 2     def wrapper(*args,**kwargs):
 3         g=func(*args,**kwargs)
 4         next(g)
 5         return g
 6     return wrapper
 7 @init
 8 def eater(name):
 9     print('%s ready to eat' %name)
10     food_list=[]
11     while True:
12         food=yield food_list#return None
13         food_list.append(food)
14         print('%s start to eat %s' %(name,food))
15 
16 
17 e=eater('alex')
18 print(e.send('狗屎'))
19 print(e.send('貓屎'))
20 print(e.send('alex屎'))
21 
22 
23 def make_shit(people,n):
24     for i in range(n):
25         people.send('shit%s' %i)
26 
27 e=eater('alex')
28 make_shit(e,5)
29 #from egon
30 #egon老師的例子有味道,可是我又忍不住不用這個
View Code

9、三元表達式

res= x if x>y else y----->判斷條件x>y是否爲真,爲真則把x賦給res,不然把y賦給res

10、列表解析

s='hello'
res=[i.upper() for i in s]
print(res)          #['H', 'E', 'L', 'L', 'O']
相關文章
相關標籤/搜索