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('[email protected]', '123456', ['[email protected]'], '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>,)

# 匿名函数也可以是闭包

猜你喜欢

转载自www.cnblogs.com/dears/p/9138332.html