1. 程式人生 > >我的Python成長之路---Day11-函式的使用及名稱空間和作用域

我的Python成長之路---Day11-函式的使用及名稱空間和作用域

1.昨天函式的引數內容的補充

命名關鍵字引數: 在定義函式時,*與**之間引數稱之為命名關鍵字引數
特點:
在呼叫函式時,命名關鍵字引數必須按照key=value的形式傳值

def func(x,*,y=1,z):       在這裡*後邊的y和z都是命名關鍵字引數,y像預設引數一樣被事先賦值好了,再實 
                           參進行傳值的時候可以不對y進行傳值
    print(x)
    print(y)
    print(z)

func(1,z=2)                傳值的時候必須要使用key=value的形式才可以傳值成功.

def func(a,b=2,*args,c,**kwargs):     設定形參時各種形參的位置順序
    print(a)
    print(b)
    print(args)
    print(c)
    print(kwargs)

------------------------------------------------------------------------------------分割線----------------------------------------------------------------------------

一、函式物件

函式是第一類物件: 指的是函式的記憶體地址可以像一個變數值一樣去使用

def foo():                        #foo  不加括號代表函式的記憶體地址
    print('from foo')

1. 變數值可以被引用
x=1                                #foo=函式的記憶體地址
y=x

f=foo
print(f)                          輸出:<function foo at 0x0000024CF6E63E18>
f()                                 輸出:from foo

2. 變數值可以當作引數傳給另外一個函式
def bar(x):        這時的x=foo
    print(x)          將函式foo的記憶體地址打印出來
    x()                 相當於呼叫函式foo(),會實現foo的功能


bar(foo)             函式bar中的引數為函式foo(foo的記憶體地址)

3. 變數值可以當作函式的返回值
def func(x):
    return x          將foo當做返回值返回

f=func(foo)         將foo當做引數傳給函式func,接受引數為foo時func的返回值
print(f)                其實這裡列印的還是foo的記憶體地址

4. 變數值可以當作容器型別中(容器型別指的是:元組、列表、字典)的元素
l=[foo,]               將foo當做列表中的元素
print(l)                輸出:[<function foo at 0x0000016828A43E18>]
l[0]()                   使用列表的特點呼叫函式foo

dic={'1':foo}        將foo當做字典中的元素
print(dic)
dic['1']()              使用字典特點呼叫函式foo

-----------------------------------------------------------------------使用函式物件的第四個特點對簡易購物車進行優化--------------------------------

def register():               前面定義函式實現相應的功能
    print('註冊....')

def login():
    print('登入....')

def pay():
    print('支付....')

def transfer():
    print('轉賬....')

func_dic={                    利用函式物件的第四個特點,將函式(記憶體地址)存放在字典中
    '1':register,
    '2':login,
    '3':pay,
    '4':transfer
}

#func_dic['1']()             可以使用這樣的形式直接呼叫相應功能的函式 

'''
整體程式碼就不用寫特別長了,並且可拓展性相對於之前來說好了很多,想要新增什麼功能,直接定義函式實現功能的新增,然後在字典中新增新功能對應的鍵值對,再在列印階段打印出新功能的提示資訊就可以了,主程式碼並不需要改動即可實現新功能的新增
'''
while True: 
    print("""
    0 退出
    1 註冊
    2 登入
    3 支付
    4 轉賬
    """)
    choice=input('請輸入你的操作: ').strip()
    if choice == '0':break        這裡輸入0對應的操作程式碼不能喝下面的判斷程式碼互換位置,換了位 
                                  置之後就不能實現退出的功能,會被判定為為錯誤的指令輸入,因為字 
                                  典中的key沒有0

    if choice not in func_dic:
        print('輸錯的指令不存在')   判斷輸入的指令編號是否存在與字典中
        continue

    func_dic[choice]()            執行相應key對應的函式

二、函式巢狀

函式的巢狀呼叫:在一個函式內部又呼叫其他函式

def max2(x,y):
    if x > y:
        return x
    else:
        return y

def max4(a,b,c,d):
    res1=max2(a,b)             在一個函式中又呼叫其他的函式
    res2=max2(res1,c)
    res3=max2(res2,d)
    return res3

print(max4(1,2,3,4))

函式的巢狀定義: 在函式內又定義了其他函式

def func():
    def foo():                  在func中巢狀定義函式foo
        print('from foo')
    # print(foo)                如果在這裡列印foo打印出來的是foo的記憶體地址
    foo()                       在func中也可以直接呼叫定義好的foo
    x=1
    print(x)                    這裡x的值為1

func()
-------------------------------------------函式巢狀的使用---------------------------------
使用函式巢狀可以將同系列的函式功能統一到一個函式裡邊,簡化了函式的呼叫
下邊是一個函式巢狀的例子

from math import pi

def circle(radius,action):       可以直接通過引數來選擇來進行的操作,是要結算周長還是計算面積
    def cal_perimeter():
        return 2 * pi * radius

    def cal_area():
        return pi * (radius ** 2)

    if action == 1:
        res=cal_perimeter()
    elif action == 2:
        res=cal_area()
    return res

res=circle(10,1)
print(res)

 

三、函式的名稱空間和作用域

一 、名稱空間相關
1. 名稱空間Namespaces:指的就是存放名字與值記憶體地址繫結關係的地方(記憶體空間)
x=1,需要在記憶體中申請一個空間來存放1這個值,同時還要尋找一個記憶體空間來儲存x和1的記憶體地址繫結關係的空間,存放名字與值對應繫結關係的地方就成為名稱空間,

2. 名稱空間分為三大類
內建名稱空間: 存放的是python直譯器自帶的名字(例如len()、print()、等等)
    產生:python直譯器的啟動則產生
    銷燬:python直譯器關閉則銷燬

全域性名稱空間: 在頂級程式碼中定義的名字

    產生:執行python程式時產生
    銷燬:python程式執行完畢後則銷燬

x=1
if True:
    y=2
while True:
    while True:
        while True:
            z=3                    z=3在這裡也算做頂級程式碼中定義的名字,因為while迴圈是一直往下走的一直走到了z=3,相當於寫了一行程式碼,只不                                        過z=3寫在最後邊而已,也是存在於全域性名稱空間中的.

區域性名稱空間: 在函式內定義的名字
    產生: 在函式呼叫時臨時產生
    銷燬: 在函式呼叫完畢後則銷燬

def foo():
    m=100                        比如這裡的m就屬於區域性名稱空間中的,區域性名稱都是函式呼叫時臨時產生臨時銷燬的

foo()

三種名稱空間的產生的先後順序: 內建->全域性->區域性
查詢名字的順序:從當前位置往外一層一層查詢             查詢名字指的是在執行當前程式碼時,所需要用到的變數名的名字,並這行代                                                                                          碼所在位置就是當前位置
    如果當前在區域性名稱空間: 區域性->全域性->內建
    如果當前在全域性名稱空間: 全域性->內建

# len=111
# def foo():
#     # len=222
#     print(len)           在這裡列印len的時候,首先從區域性名稱空間找,找到len=222,
# len=111                  如果區域性空間len=222不存在,就從全部名稱空間找,可以找到len=111,
                           如果全部名稱空間的len=111不存在,就從內建名稱空間中找,這時候打印出來 
                           的len就是python直譯器中求長度的函式len()的記憶體地址
# foo()

# x=0
def f1():
    # x=1
    def f2():
        # x=2
        def f3():
            # x=3
            print(x)
        f3()            
    f2()                
f1()    在f1()的最終結果中x=0,x=1,x=2,x=3都存在話,f1()的最終結果為x=3,如果從x=3.x=2,x=1,x=0一 
        次被註釋掉的時候,f1()的最終結果依次為3,2,1,0 這就是函式巢狀時尋找變數名的順序               

def foo1():
    def foo2():
        def foo3():
            print(x)

'''

二 、作用域:指的是作用範圍
全域性作用域:包含內建名稱空間與全域性名稱空間的名字
    特點:全域性存活(該範圍內的名字會伴隨程式整個的生命週期,即從讀取出來到執行完畢關閉的時候),

            全域性有效(在任何位置都能訪問的到)

區域性作用域:包含的是區域性名稱空間的名字
    特點:臨時存活(只有在呼叫函式時生效,呼叫結束時失效)

            區域性有效(只能在函式內使用)

作用域關係是在函式定義階段就已經固定死了,與呼叫位置無關


示範一:

def f1():
    print(xxx)
xxx=111

def f2():
    xxx=222
    f1()        在這裡呼叫f1()時打印出來的值並不是222因為f1中xxx的值在定義階段已經被定義了xxx=111 
                無論在哪個地方呼叫f1,打印出來的值都是111

示範二:

xxx=111

def f1():
    print(xxx)           這裡程式會進行報錯,原因是在定義階段已經就近找到了xxx的值為222但是在函式 
                         呼叫階段又出現了xxx=111的情況,和定義的時候出現了衝突,去掉函式頭頂的 
                         xxx=111即可正常使用函式,這時xxx的值為222
    xxx=222
    yyy=222
    print(yyy)            這裡的yyy是可以正常輸出的,在定義階段yyy=222,呼叫函式的時候沒有與定義階 
                          段衝突,但是如果在函式頭頂加上yyy=333時,呼叫時就會出現和xxx一樣的錯誤 
             
f1()

(全域性/區域性)名稱空間:是存放值與變數名繫結關係的記憶體空間,是存(全域性/區域性)變數的地方

(全域性/區域性)作用域:指的是(全域性/區域性)變數起作用的範圍

(全域性/區域性)變數:存放在(全域性/區域性)名稱空間中,在程式碼中體現為全域性變數是在頂級程式碼的位置的,區域性變數是在函式體內部的

四、閉包函式

閉包函式:
閉:封閉,指的是該函式是定義一個函式內部的函式
:該內部函式包含對外層函式名字(這裡的外層函式名字指的是外層函式包含的區域性變數)的引用

def outter():                   inner在這裡就是一個典型的閉包函式,它定義在outter()內部,在inner 
                                中使用的x屬於outter的區域性變數,也就是相對於inner來說的外部函式名 
                                字的引用.
    x=1
    def inner():
        print('from inner',x)
    return inner

f=outter()

def foo():
    # print(f)
    x=111111111111111111111111111111111111
    f()           在這呼叫f()時,x的值不會受到x=11111111111111111111111的影響,因為在f()定義階段 
                                                                                       x=1
foo()                 

為函式體傳值的兩種方式:
def foo():
    print('hello %s' %name)

方式一:直接以引數的形式傳入
def foo(name):
    print('hello %s' %name)

foo('egon')
foo('egon')
foo('egon')              這種在呼叫的時候每次都要輸入要傳給引數的內容,呼叫的時候如果遇到要經常傳較長內容內參數的時候就會比較麻煩

方式二:閉包函式(使用閉包函式傳值給函式體)
def outter(name):
    # name='egon'(省略了這一步)
    def foo():
        print('hello %s' %name)
    return foo

f=outter('egon')     之後就可以直接呼叫f()就可以打印出來hello egon
# print(f)
f()
f()
f()

f1=outter('alex')
f1()
f1()
f1()

pip3 install requests   安裝python中爬蟲必要的元件,直接在cmd中輸入改命令就可以

閉包函式的簡單應用
import requests

問題     要給url傳值(也就是需要爬的網站名字)
def get():     
    response=requests.get(url)
    if response.status_code == 200:
        print(response.text)

解決方案一:(設定引數,給引數賦值)
def get(url):
    response=requests.get(url)
    if response.status_code == 200:
        print(response.text)

get('https://www.baidu.com')         缺點:每次爬取都需要給引數url傳內容,呼叫比較麻煩
get('https://www.baidu.com')
get('https://www.baidu.com')

解決方案二:(使用閉包函式給url傳值)

def outter(url):
    # url='https://www.baidu.com'
    def get():
        response=requests.get(url)
        if response.status_code == 200:
            print(response.text)
    return get

baidu=outter('https://www.baidu.com')           一次傳值後賦值給變數名,以後可以重複使用
cnblogs=outter('https://www.cnblogs.com')

baidu()
baidu()
baidu()
baidu()
baidu()
baidu()

cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()