python之函數與閉包


函數的意義

#函數是對單一相關操作的有組織的可重用代碼的塊的封裝
#為應用程序提供更好的模塊化以及提高代碼的復用程度
def func1(x, y, z):
    return x + y + z

def func2():
    x, y, z = 1, 2, 3
    return x + y + z 

func1(x=1,y=2,z=3)
func2()

# 函數並不意味着對一段重復使用的代碼進行封裝 如func2,在x, y, z,不變的情況下這樣使用好像不會出問題
# 但是我們要的不僅僅是這個,在有可能的情況下,應該盡可能地提高函數的自定義程度,
如同func1,傳到函數里邊的可以是3個str,3個int,3個list等等,讓使用者來自己定義函數的輸入

定義和調用規則

def send_mail(sender, password, receiver,  message, subject=None, smtpserver='qq.smtp.com') -> bool:
    ''' function send_mail
    
    :param sender: 發件人的郵箱地址
    :type sender: str
    
    :param password: 發件人的郵箱密碼
    :type password: str
    
    :param receiver: 收件人的郵箱地址
    :type receiver: list
    
    :param message: 郵件內容
    :type message: str
    
    :param subject: 郵件標題
    :type subject: str
    
    :param smtpserver: 郵件服務器, 默認為'qq.smtp.com'
    :type smtpserver: str
    
    :return bool
    '''
    msg=MIMEText(message)
    msg['Subject']=subject
    msg['Form']=sender
    msg['To']=receiver
    result = False
    try:
      smtp=SMTP()
      smtp.connect(smtpserver)
      smtp.login(sender,password)
      smtp.sendmail(sender,receiver,msg.as_string())
      smtp.close()
      retult = True
    except Exception as e:
      print(e)
      result = False
    return result

result = send_mail('369574757@qq.com', '123456', ['369574757@qq.com'], 'Hello World')
print(result)


  • 定義函數  從def所在行開始 直至函數所在的最后1行
  • 函數注釋: 函數里邊第一個注釋塊 help()會返回函數的注釋
  • 函數返回值: return 所返回的值(默認為None)
  • 調用函數: send_mail() | result = send_mail()
  • 接收返回值: result = send_mail()
  • 內置函數與自定義函數:
  • send_mail()就是自定義函數
  • 內置函數-->不需要用戶自己定義就能調用的(list,dict,tuple等)

函數的傳參方式 按綁定關系傳遞


str1 = "dear"
list1 = []

print(sys.getrefcount(list1)) -> 2

def func(s:str, l:list):

  print(sys.getrefcount(list1)) -> 5
  print(sys.getrefcount(l)) -> 5
  print(id(l),l)

  l.append(s)
  print(id(l),l)
  
  print(id(s),s)
  s += "Eirs"
  print(id(s),s)

# 由sys.getrefcount(list1)統計得知在參數傳遞的過程中  只是把list1的綁定關系傳遞給l 相當於l = list1 
# 由於l.append(s)只是對[]進行修改,並沒有改變l與[]的綁定關系  所以兩次print出來的id 是一樣的
# s += "Eirs" 把變量s重新指向了新的元素'dearEirs', 變量從綁定'dear' 變為綁定'dearEirs'所以值的內存地址變了

傳參的形式

def func(a, b, c=6, *args):
  return id(a),id(b),id(c)
  
def func(x, y, z):
  return x-y+z

  • 必選參數: a, b func(1, 2)
  • 可選參數(默認參數): c func(1, 2) func(1, 2, 3)
  • 按位置傳參: func(1,2,3) 在第一、二、三位的參數1,2,3分別對應着參數a, b, c
  • 關鍵字參數: func(a=1, b=2, c=3)
  • 可變長參數: func(1,2,3,4,'dear'),在a,b,c 都接收到參數后,其余參數傳遞給*args

匿名函數

lambda x: x % 2

相當於
def func(x):
  return x % 2

#使用情景: 函數體可以用1條表達式就可以解決時

作用域

#!/usr/bin/env python

x = 1

if True:
  y = 2

for i in range(5):
  z = x+i

def func(x,y,z):
  total = x + y + z
  print(total)
  return total

#print(total)
total = func()
print(total)

  • 全局作用域:在當前py文件里都生效
  • 局部作用域:從函數或類的定義開始到該函數或類最后1行代碼 為該函數或類的 局部作用域
  • 全局變量:定格定義的變量(包含定格的if while for try里邊定義的變量),在全局生效,可用globals()查看
  • 局部變量:在函數或類里邊所定義的變量,只在該函數或類中生效,可用locals()查看

生命周期


a = 10000
sys.getrefcount(a) -> 2
del a
sys.getrefcount(a) -> 1
#變量a的生命周期結束,如果不del a   那么變量a將會一直存在 直至程序關閉

#函數的生命周期
def func(x,y,z):
  total = x + y + z
  print(total)
  return total
  
#從函數第一行開始 到函數 return 返回值 若沒return則到函數代碼里的最后1行執行結束  即為函數的生命周期

#對象的生命周期
當對象被垃圾回收機制回收時,對象才會結束它的生命周期

垃圾回收

引用計數

# sys.getrefcount() 統計變量所指向內存地址被引用的次數
a = 1000
sys.getrefcount(a) -> 2

b = c  = a 
sys.getrefcount(a) -> 4
sys.getrefcount(b) -> 4
sys.getrefcount(c) -> 4

# 每當有1個變量1000時  1000的引用計數就會加1  a, b, c, d,都指向着1000

del a 

sys.getrefcount(a) -> 1
sys.getrefcount(b) -> 3
sys.getrefcount(c) -> 3

當變量a被銷毀時, 1000的引用次數就會減1

閉包

  • 前提1:嵌套函數
  • 前提2:內層函數引用非全局變量
  • 前提3:不改變外部變量的綁定關系

'''
查看函數是不是閉包:
2.7:func.func_closure  返回cell對象即為閉包  返回None即不是
3.6:func.__closure__
'''

def outer():
  dict1 = {}
  def inner(key,value):
    dict1[key] = value
    return dict1
  return inner

f1 = outer()
print(f.__closure__) -> (<cell at 0x000002BEE0BC57C8: dict object at 0x000002BEE0FD5F78>,)
f1('key1','value1')
f1('key2','value2') -> {'key1': 'value1', 'key2': 'value2'}

f2 = outer()
f2('key3','value3')
f2('key4','value4') -> {'key3': 'value3', 'key4': 'value4'}

# 當外部函數被調用時,返回一個閉包 即f,f2
# 閉包 = 子函數 + 依賴的外部變量  子函數 inner 外部變量 dict1
# 閉包是一種特殊的函數
# 每調一次外部函數,返回一個新閉包 f f2 的互不干擾,是2個不一樣的閉包 各自指向着不同的內存地址


# 匿名函數可不可以是閉包

def outer():
  dict1 = {}
  l = lambda key, value: dict1.update({key:value})
  return l

f = outer()
print(f.__closure__) -> (<cell at 0x00000230A4645798: dict object at 0x00000230A46E2168>,)

# 匿名函數也可以是閉包


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM