• Python学习之路6☞函数,递归,内置函数


    一python中的函数

    函数是逻辑结构化和过程化的一种编程方法。

    python中函数定义方法:
     
    def test(x):
        "The function definitions"
        x+=1
        return x
         
    def:定义函数的关键字
    test:函数名
    ():内可定义形参
    "":文档描述(非必要,但是强烈建议为你的函数添加描述信息)
    x+=1:泛指代码块或程序处理逻辑
    return:定义返回值
    
    
    调用运行:可以带参数也可以不带
    函数名()

    二 为何使用函数

    背景提要

    现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码

     1 while True:
     2     if cpu利用率 > 90%:
     3         #发送邮件提醒
     4         连接邮箱服务器
     5         发送邮件
     6         关闭连接
     7      
     8     if 硬盘使用空间 > 90%:
     9         #发送邮件提醒
    10         连接邮箱服务器
    11         发送邮件
    12         关闭连接
    13      
    14     if 内存占用 > 80%:
    15         #发送邮件提醒
    16         连接邮箱服务器
    17         发送邮件
    18         关闭连接

    上面的代码实现了功能,你这个重复代码太多了,每次报警都要重写一段发邮件的代码,太low了,这样干存在2个问题:

    1. 代码重复过多,一个劲的copy and paste不符合高端程序员的气质
    2. 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍

    其实很简单,只需要把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下

     1 def 发送邮件(内容)
     2     #发送邮件提醒
     3     连接邮箱服务器
     4     发送邮件
     5     关闭连接
     6      
     7 while True:
     8      
     9     if cpu利用率 > 90%:
    10         发送邮件('CPU报警')
    11      
    12     if 硬盘使用空间 > 90%:
    13         发送邮件('硬盘报警')
    14      
    15     if 内存占用 > 80%:
    16         发送邮件('内存报警')

    总结使用函数的好处:

    1.代码重用

    2.保持一致性,易维护

    3.可扩展性

    三 函数和过程

    过程定义:过程就是简单特殊没有返回值的函数

    这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情

     1 def test01():
     2     msg='hello The little green frog'
     3     print msg
     4  
     5 def test02():
     6     msg='hello WuDaLang'
     7     print msg
     8     return msg
     9  
    10  
    11 t1=test01()
    12  
    13 t2=test02()
    14  
    15  
    16 print 'from test01 return is [%s]' %t1
    17 print 'from test02 return is [%s]' %t2

    总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None,

    所以在python中即便是过程也可以算作函数。

     1 def test01():
     2     pass
     3  
     4 def test02():
     5     return 0
     6  
     7 def test03():
     8     return 0,10,'hello',['alex','lb'],{'WuDaLang':'lb'}
     9  
    10 t1=test01()
    11 t2=test02()
    12 t3=test03()
    13  
    14  
    15 print 'from test01 return is [%s]: ' %type(t1),t1
    16 print 'from test02 return is [%s]: ' %type(t2),t2
    17 print 'from test03 return is [%s]: ' %type(t3),t3

    总结:

       返回值数=0:返回None

       返回值数=1:返回object

       返回值数>1:返回tuple

    四 函数是第一类对象

    在python中所有的名字都没有储值功能

    函数是第

    1 def foo():
    2     print("yyp")
    3 f1=foo
    4 f1()
    5 # 输出结果:
    6 yyp

    可以当做参数

     1 def foo():
     2     print("tom")
     3 
     4 def func(msg):
     5     print(msg)
     6     msg()
     7 
     8 func(foo)
     9 输出结果:
    10 <function foo at 0x00000000020D3E18>
    11 tom

    可以当做返回值

     1 def foo():
     2     print("tom")
     3 
     4 def func(msg):
     5     return msg
     6 
     7 f=func(foo)
     8 print(f)
     9 f()
    10 输出结果:
    11 <function foo at 0x0000000002423E18>
    12 tom

    可以当做容器类型的一个元素

    1 def foo():
    2     print("tom")
    3 
    4 func_dic={
    5     'foo':foo
    6 }
    7 输出结果:
    8 tom

    一类对象指的是:函数可以被当做数据来处理被引用

    五 函数参数

    1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

    2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

    3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)

    4.默认参数

    5.参数组

    六 局部变量和全局变量

    在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

    全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
    当全局变量与局部变量同名时:
    在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
     1 name='lhf'
     2 
     3 def change_name():
     4     print('我的名字',name)
     5 
     6 change_name()
     7 
     8 
     9 def change_name():
    10     name='帅了一笔'
    11     print('我的名字',name)
    12 
    13 change_name()
    14 print(name)
    15 
    16 
    17 
    18 def change_name():
    19     global name
    20     name='帅了一笔'
    21     print('我的名字',name)
    22 
    23 change_name()
    24 print(name)

    七 前向引用之'函数即变量'

     1 def action():
     2     print 'in the action'
     3     logger()
     4 action()
     5 报错NameError: global name 'logger' is not defined
     6 
     7 
     8 def logger():
     9     print 'in the logger'
    10 def action():
    11     print 'in the action'
    12     logger()
    13  
    14 action()
    15  
    16 
    17 def action():
    18     print 'in the action'
    19     logger()
    20 def logger():
    21     print 'in the logger'
    22  
    23 action()

    八 嵌套函数和作用域

    看上面的标题的意思是,函数还能套函数?of course

     1 name = "yyp"
     2  
     3 def change_name():
     4     name = "yyp2"
     5  
     6     def change_name2():
     7         name = "yyp3"
     8         print("第3层打印",name)
     9  
    10     change_name2() #调用内层函数
    11     print("第2层打印",name)
    12  
    13  
    14 change_name()
    15 print("最外层打印",name)

    此时,在最外层调用change_name2()会出现什么效果?

    没错, 出错了, 为什么呢?

    作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变

     1 例一:
     2 name='yyp'
     3 
     4 def foo():
     5     name='sy'
     6     def bar():
     7         print(name)
     8     return bar
     9 
    10 func=foo()
    11 func()
    12 
    13 
    14 例二:
    15 name='yyp'
    16 
    17 def foo():
    18     name='sy'
    19     def bar():
    20         name='tom'
    21         def tt():
    22             print(name)
    23         return tt
    24     return bar
    25 
    26 func=foo()
    27 func()()

    九 递归调用

     1 def calc(n):
     2     print(n)
     3     if int(n/2) ==0:
     4         return n
     5     return calc(int(n/2))
     6  
     7 calc(10)
     8  
     9 输出:
    10 10
    11 5
    12 2
    13 1
     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 import time
     4 
     5 person_list=['alex','wupeiqi','yuanhao','linhaifeng']
     6 def ask_way(person_list):
     7     print('-'*60)
     8     if len(person_list) == 0:
     9         return '没人知道'
    10     person=person_list.pop(0)
    11     if person == 'linhaifeng':
    12         return '%s说:我知道,老男孩就在沙河汇德商厦,下地铁就是' %person
    13     print('hi 美男[%s],敢问路在何方' %person)
    14     print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' %(person,person_list))
    15     time.sleep(3)
    16     res=ask_way(person_list)
    17     # print('%s问的结果是: %res' %(person,res))
    18     return res
    19 
    20 
    21 
    22 res=ask_way(person_list)
    23 
    24 print(res)
    递归问路

    递归特性:

    1. 必须有一个明确的结束条件

    2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

    3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

    链接:堆栈扫盲

     1 data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
     2  
     3  
     4 def binary_search(dataset,find_num):
     5     print(dataset)
     6  
     7     if len(dataset) >1:
     8         mid = int(len(dataset)/2)
     9         if dataset[mid] == find_num:  #find it
    10             print("找到数字",dataset[mid])
    11         elif dataset[mid] > find_num :# 找的数在mid左面
    12             print("33[31;1m找的数在mid[%s]左面33[0m" % dataset[mid])
    13             return binary_search(dataset[0:mid], find_num)
    14         else:# 找的数在mid右面
    15             print("33[32;1m找的数在mid[%s]右面33[0m" % dataset[mid])
    16             return binary_search(dataset[mid+1:],find_num)
    17     else:
    18         if dataset[0] == find_num:  #find it
    19             print("找到数字啦",dataset[0])
    20         else:
    21             print("没的分了,要找的数字[%s]不在列表里" % find_num)
    22  
    23  
    24 binary_search(data,66)
    二分查找

    十 匿名函数

    匿名函数就是不需要显式的指定函数

    1 #这段代码
    2 def calc(n):
    3     return n**n
    4 print(calc(10))
    5  
    6 #换成匿名函数
    7 calc = lambda n:n**n
    8 print(calc(10))

    匿名函数主要是和其它函数搭配使用的呢,如下

    1 l=[3,2,100,999,213,1111,31121,333]
    2 print(max(l))
    3 
    4 dic={'k1':10,'k2':100,'k3':30}
    5 
    6 
    7 print(max(dic))
    8 print(dic[max(dic,key=lambda k:dic[k])])
     1 res = map(lambda x:x**2,[1,5,7,4,8])
     2 for i in res:
     3     print(i)
     4 
     5 输出
     6 1
     7 25
     8 49
     9 16
    10 64

    十一 函数式编程

    函数式编程: 

    http://egon09.blog.51cto.com/9161406/1842475

    11 高阶函数

    满足俩个特性任意一个即为高阶函数

    1.函数的传入参数是一个函数名

    2.函数的返回值是一个函数名

     1 array=[1,3,4,71,2]
     2 
     3 ret=[]
     4 for i in array:
     5     ret.append(i**2)
     6 print(ret)
     7 
     8 #如果我们有一万个列表,那么你只能把上面的逻辑定义成函数
     9 def map_test(array):
    10     ret=[]
    11     for i in array:
    12         ret.append(i**2)
    13     return ret
    14 
    15 print(map_test(array))
    16 
    17 #如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样
    18 def add_num(x):
    19     return x+1
    20 def map_test(func,array):
    21     ret=[]
    22     for i in array:
    23         ret.append(func(i))
    24     return ret
    25 
    26 print(map_test(add_num,array))
    27 #可以使用匿名函数
    28 print(map_test(lambda x:x-1,array))
    29 
    30 
    31 #上面就是map函数的功能,map得到的结果是可迭代对象
    32 print(map(lambda x:x-1,range(5)))
    map函数
    from functools import reduce
    #合并,得一个合并的结果
    array_test=[1,2,3,4,5,6,7]
    array=range(100)
    
    #报错啊,res没有指定初始值
    def reduce_test(func,array):
        l=list(array)
        for i in l:
            res=func(res,i)
        return res
    
    # print(reduce_test(lambda x,y:x+y,array))
    
    #可以从列表左边弹出第一个值
    def reduce_test(func,array):
        l=list(array)
        res=l.pop(0)
        for i in l:
            res=func(res,i)
        return res
    
    print(reduce_test(lambda x,y:x+y,array))
    
    #我们应该支持用户自己传入初始值
    def reduce_test(func,array,init=None):
        l=list(array)
        if init is None:
            res=l.pop(0)
        else:
            res=init
        for i in l:
            res=func(res,i)
        return res
    
    print(reduce_test(lambda x,y:x+y,array))
    print(reduce_test(lambda x,y:x+y,array,50))
    reduce函数
     1 #电影院聚集了一群看电影bb的傻逼,让我们找出他们
     2 movie_people=['alex','wupeiqi','yuanhao','sb_alex','sb_wupeiqi','sb_yuanhao']
     3 
     4 def tell_sb(x):
     5     return x.startswith('sb')
     6 
     7 
     8 def filter_test(func,array):
     9     ret=[]
    10     for i in array:
    11         if func(i):
    12             ret.append(i)
    13     return ret
    14 
    15 print(filter_test(tell_sb,movie_people))
    16 
    17 
    18 #函数filter,返回可迭代对象
    19 print(filter(lambda x:x.startswith('sb'),movie_people))
    filter函数
     1 #当然了,map,filter,reduce,可以处理所有数据类型
     2 
     3 name_dic=[
     4     {'name':'alex','age':1000},
     5     {'name':'wupeiqi','age':10000},
     6     {'name':'yuanhao','age':9000},
     7     {'name':'linhaifeng','age':18},
     8 ]
     9 #利用filter过滤掉千年王八,万年龟,还有一个九千岁
    10 def func(x):
    11     age_list=[1000,10000,9000]
    12     return x['age'] not in age_list
    13 
    14 
    15 res=filter(func,name_dic)
    16 for i in res:
    17     print(i)
    18 
    19 res=filter(lambda x:x['age'] == 18,name_dic)
    20 for i in res:
    21     print(i)
    22 
    23 
    24 #reduce用来计算1到100的和
    25 from functools import reduce
    26 print(reduce(lambda x,y:x+y,range(100),100))
    27 print(reduce(lambda x,y:x+y,range(1,101)))
    28 
    29 #用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb
    30 name=['alex','wupeiqi','yuanhao']
    31 
    32 res=map(lambda x:x+'_sb',name)
    33 for i in res:
    34     print(i)
    总结

    十二 内置函数

     1 字典的运算:最小值,最大值,排序
     2 salaries={
     3     'egon':3000,
     4     'alex':100000000,
     5     'wupeiqi':10000,
     6     'yuanhao':2000
     7 }
     8 
     9 迭代字典,取得是key,因而比较的是key的最大和最小值
    10 >>> max(salaries)
    11 'yuanhao'
    12 >>> min(salaries)
    13 'alex'
    14 
    15 可以取values,来比较
    16 >>> max(salaries.values())
    17 >>> min(salaries.values())
    18 但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
    19 >>> max(salaries,key=lambda k:salary[k])
    20 'alex'
    21 >>> min(salaries,key=lambda k:salary[k])
    22 'yuanhao'
    23 
    24 
    25 
    26 也可以通过zip的方式实现
    27 salaries_and_names=zip(salaries.values(),salaries.keys()) 
    28 
    29 先比较值,值相同则比较键
    30 >>> max(salaries_and_names)
    31 (100000000, 'alex')
    32 
    33 
    34 salaries_and_names是迭代器,因而只能访问一次
    35 >>> min(salaries_and_names)
    36 Traceback (most recent call last):
    37   File "<stdin>", line 1, in <module>
    38 ValueError: min() arg is an empty sequence
    39 
    40 
    41 
    42 sorted(iterable,key=None,reverse=False)
    View Code
  • 相关阅读:
    django控制台输出sql日志
    Find概述
    命令大全
    京东智联云在 Serverless 的探索
    如何优雅地部署一个 Serverless Next.js 应用
    腾讯云 Serverless 保障《创造营》硬糖少女 C 位出道
    Serverless 应用实践及典型案例解析
    LeetCode 数组:62. 不同路径(动态规划 带记忆的递归)
    LeetCode 数组:56.合并区间(数组的自带排序函数 区间合并问题)
    LeetCode 数组:162. 寻找峰值(二分法)
  • 原文地址:https://www.cnblogs.com/Vae1242/p/6941116.html
Copyright © 2020-2023  润新知