Python基础知识06-函数,递归,内置函数

一、为何使用函数

背景提要:在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下:

while True:
    if cpu利用率 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
    if 硬盘使用空间 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接  
    if 内存占用 > 80%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接

改进:把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下:

def 发送邮件(内容)
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接   
while True:
    if cpu利用率 > 90%:
        发送邮件('CPU报警')
    if 硬盘使用空间 > 90%:
        发送邮件('硬盘报警')
    if 内存占用 > 80%:
        发送邮件('内存报警')

对于上述的两种实现方式,第二次必然比第一次的重用性和可读性要好,其实这就是函数式编程和面向过程编程的区别:

  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”

二、定义函数的方法

函数是逻辑结构化和过程化的一种编程方法;函数式编程最重要的是增强代码的重用性和可读性。

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

1、返回值

  函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者,没有返回值的函数也称为过程。

#!/usr/bin/env python
#_*_ coding:utf-8 _*_

def test01():
    msg='hello The little green frog'
    print msg
def test02():
    msg='hello WuDaLang'
    print msg
    return msg
t1=test01()
t2=test02()
print 'from test01 return is [%s]' %t1
print 'from test02 return is [%s]' %t2
#结果
'''
hello The little green frog
hello WuDaLang
from test01 return is [None]
from test02 return is [hello WuDaLang]
'''

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

2、参数

函数的有三中不同的参数:

  1、普通参数:

# ######### 定义函数 #########
# name 叫做函数func的形式参数,简称:形参
def func(name):
    print name

# ######### 执行函数 #########
#  'wupeiqi' 叫做函数func的实际参数,简称:实参
func('zhangsan')
'''
1、形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2、实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
3、位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)
'''

  2、默认参数:

def func(name, age=18):
    print "%s:%s" % (name, age)

func('zahngsan', 19)    # 指定参数
func('lisi')    # 使用默认参数
#注:默认参数需要放在参数列表最后

  3、动态参数:传列表、字典

#动态参数一
def func(*args):        #将参数包装成列表传入函数
    print args

func(11,33,4,4454,5)    # 执行方式一

li = [11,2,2,3,3,4,54]  # 执行方式二
func(*li)
#结果
'''
(11, 33, 4, 4454, 5)
(11, 2, 2, 3, 3, 4, 54)
'''

#动态参数二
def func(**kargs):      #将参数包装成字典传入函数
    print kargs

func(name = 'zhangsan', age = 18)                           # 执行方式一
li = {'name':'zhangsan', 'age':18, 'gender':'male'}     # 执行方式二,字典必须先定义好
func(**li)
#结果
'''
{'age': 18, 'name': 'zhangsan'}
{'gender': 'male', 'age': 18, 'name': 'zhangsan'}
'''

#动态参数三
def func(*args, **kwargs):
    print args
    print kwargs
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
 
 
msg = MIMEText('邮件内容', 'plain', 'utf-8')
msg['From'] = formataddr(["武沛齐",'wptawy@126.com'])
msg['To'] = formataddr(["走人",'424662508@qq.com'])
msg['Subject'] = "主题"
 
server = smtplib.SMTP("smtp.126.com", 25)
server.login("wptawy@126.com", "邮箱密码")
server.sendmail('wptawy@126.com', ['424662508@qq.com',], msg.as_string())
server.quit()
发送邮件实例

三、函数是第一类对象

在python中所有的名字都没有储值功能,函数是第一个对象。

def foo():
    print("yyp")
foo()
# 输出结果:
yyp

可以当做参数

def foo():
    print "tom"
def func(msg):
    print msg
    msg()
func(foo)
#输出结果:
<function foo at 0x00000000020D3E18>
tom

可以当做返回值

def foo():
    print "tom"
def func(msg):
    return msg
f=func(foo)
print f
f()
#输出结果:
# <function foo at 0x0000000002423E18>
# tom

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

def foo():
    return "tom"
func_dic={'foo':foo()}
print func_dic.get('foo')
#输出结果:
#tom 

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

四、局部变量和全局变量

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

  • 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
  • 当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
name='lhf'                      #全局变量
def change_name():
    print('我的名字',name)
change_name()

def change_name():
    name='帅了一笔'             #局部变量
    print('我的名字',name)
change_name()
print(name)

def change_name():
    global name
    name='帅了一笔'
    print('我的名字',name)
change_name()
print(name)

五、前向引用之-函数即变量

def action():
    print 'in the action'
    logger()
action()
#报错NameError: global name 'logger' is not defined

def logger():
    print 'in the logger'
def action():
    print 'in the action'
    logger()
action()

六、嵌套函数和作用域

name = "yyp"
def change_name():
    name = "yyp2"
    def change_name2():
        name = "yyp3"
        print("第3层打印",name)
    change_name2() #调用内层函数
    print("第2层打印",name)
change_name()
print("最外层打印",name)

作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变,此时,在最外层调用change_name2()会出错。

#例一:
name='yyp'
def foo():
    name='sy'
    def bar():
        print(name)
    return bar
func=foo()
func()
例二:
name='yyp'
def foo():
    name='sy'
    def bar():
        name='tom'
        def tt():
            print(name)
        return tt
    return bar
func=foo()
func()()

七、递归调用

递归特性:

  • 必须有一个明确的结束条件
  •  每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

  链接:堆栈扫盲

def calc(n):
    print(n)
    if int(n/2) ==0:
        return n
    return calc(int(n/2))
calc(10)
#输出:
# 10
# 5
# 2
#!/usr/bin/env python
#_*_ coding:utf-8 _*_

import time

person_list=['alex','wupeiqi','yuanhao','linhaifeng']
def ask_way(person_list):
    print('-'*60)
    if len(person_list) == 0:
        return '没人知道'
    person=person_list.pop(0)
    if person == 'linhaifeng':
        return '%s说:我知道,老男孩就在沙河汇德商厦,下地铁就是' %person
    print('hi 美男[%s],敢问路在何方' %person)
    print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' %(person,person_list))
    time.sleep(3)
    res=ask_way(person_list)
    # print('%s问的结果是: %res' %(person,res))
    return res
res=ask_way(person_list)

print(res)
递归问路
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]

def binary_search(dataset, find_num):
    print(dataset)
    if len(dataset) > 1:
        mid = int(len(dataset) / 2)
        if dataset[mid] == find_num:  # find it
            print("找到数字", dataset[mid])
        elif dataset[mid] > find_num:  # 找的数在mid左面
            print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:  # 找的数在mid右面
            print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
            return binary_search(dataset[mid + 1:], find_num)
    else:
        if dataset[0] == find_num:  # find it
            print("找到数字啦", dataset[0])
        else:
            print("没的分了,要找的数字[%s]不在列表里" % find_num)

binary_search(data, 66)
二分查找

八、冒泡算法

需求:请按照从小到大对列表 [13, 22, 6, 99, 11] 进行排序

思路:相邻两个值进行比较,将较大的值放在右侧,依次比较!

#第一步
li = [13, 22, 6, 99, 11]

for m in range(4):     # 等价于 #for m in range(len(li)-1):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

#第二步
li = [13, 22, 6, 99, 11]

for m in range(4):     # 等价于 #for m in range(len(li)-1):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

for m in range(3):     # 等价于 #for m in range(len(li)-2):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

for m in range(2):     # 等价于 #for m in range(len(li)-3):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp

for m in range(1):     # 等价于 #for m in range(len(li)-4):
    if li[m]> li[m+1]:
        temp = li[m+1]
        li[m+1] = li[m]
        li[m] = temp
print li

#第三步
li = [13, 22, 6, 99, 11]

for i in range(1,5):
    for m in range(len(li)-i): 
        if li[m] > li[m+1]:
            temp = li[m+1]
            li[m+1] = li[m]
            li[m] = temp
冒泡算法

九、匿名函数

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

def calc(n):
    return n**n
    print(calc(10))
#换成匿名函数
calc = lambda n:n**n
print(calc(10))

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

l=[3,2,100,999,213,1111,31121,333]
print(max(l))
dic={'k1':10,'k2':100,'k3':30}
print(max(dic))
print(dic[max(dic,key=lambda k:dic[k])])

res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
    print(i)
#输出
#1
#25
#49
#16
#64

十、函数式编程

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

  • 函数的传入参数是一个函数名
  • 函数的返回值是一个函数名
# 普通条件语句
if 1 == 1:
    name = 'zhangsan'
else:
    name = 'lisi'

# 三元运算
name = 'zhangsan' if 1 == 1 else 'lisi'
三元运算
# ###################### 普通函数 ######################
# 定义函数(普通方式)
def func(arg):
    return arg + 1

# 执行函数
result = func(123)

# ###################### lambda ######################
# 定义函数(lambda表达式)
my_lambda = lambda arg: arg + 1

# 执行函数
result = my_lambda(123)
lambda表达式

map

遍历序列,对序列中每个元素进行操作,最终获取新的序列。

li = [11, 22, 33]
new_list = map(lambda a: a + 100, li)
每个元素增加100
li = [11, 22, 33]
sl = [1, 2, 3]
new_list = map(lambda a, b: a + b, li, sl)
两个列表对应元素相加
array=[1,3,4,71,2]
ret=[]
for i in array:
    ret.append(i**2)
print(ret)

#如果我们有一万个列表,那么你只能把上面的逻辑定义成函数
def map_test(array):
    ret=[]
    for i in array:
        ret.append(i**2)
    return ret
print(map_test(array))

#如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样
def add_num(x):
    return x+1
def map_test(func,array):
    ret=[]
    for i in array:
        ret.append(func(i))
    return ret
print(map_test(add_num,array))

#可以使用匿名函数
print(map_test(lambda x:x-1,array))

#上面就是map函数的功能,map得到的结果是可迭代对象
print(map(lambda x:x-1,range(5)))
map函数

filter

 对于序列中的元素进行筛选,最终获取符合条件的序列

#filter第一个参数为空,将获取原来序列
li = [11, 22, 33]
new_list = filter(lambda arg: arg > 22, li)
获取列表中大于12的所有元素集合
#!/usr/bin/env python
#_*_ coding:utf-8 _*_

#电影院聚集了一群看电影bb的傻逼,让我们找出他们
movie_people=['alex','wupeiqi','yuanhao','sb_alex','sb_wupeiqi','sb_yuanhao']
def tell_sb(x):
    return x.startswith('sb')

def filter_test(func,array):
    ret=[]
    for i in array:
        if func(i):
            ret.append(i)
    return ret
print(filter_test(tell_sb,movie_people))

#函数filter,返回可迭代对象
print(filter(lambda x:x.startswith('sb'),movie_people))
filter函数

reduce

对于序列内所有元素进行累计操作

# reduce的第一个参数,函数必须要有两个参数
# reduce的第二个参数,要循环的序列
# reduce的第三个参数,初始值

li = [11, 22, 33]
result = reduce(lambda arg1, arg2: arg1 + arg2, li)
获取序列所有元素的和
#!/usr/bin/env python
#_*_ coding:utf-8 _*_

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函数

map,filter,reduce小结

#!/usr/bin/env python
#_*_ coding:utf-8 _*_

#当然了,map,filter,reduce,可以处理所有数据类型

name_dic=[
    {'name':'alex','age':1000},
    {'name':'wupeiqi','age':10000},
    {'name':'yuanhao','age':9000},
    {'name':'linhaifeng','age':18},
]
#利用filter过滤掉千年王八,万年龟,还有一个九千岁
def func(x):
    age_list=[1000,10000,9000]
    return x['age'] not in age_list

res=filter(func,name_dic)
for i in res:
    print(i)

res=filter(lambda x:x['age'] == 18,name_dic)
for i in res:
    print(i)

#reduce用来计算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))
print(reduce(lambda x,y:x+y,range(1,101)))

#用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb
name=['alex','wupeiqi','yuanhao']
res=map(lambda x:x+'_sb',name)
for i in res:
    print(i)
总结

十一、内置函数

#!/usr/bin/env python
#_*_ coding:utf-8 _*_

字典的运算:最小值,最大值,排序
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}

迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex'

可以取values,来比较
>>> max(salaries.values())
>>> min(salaries.values())
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao'

也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys()) 

先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, 'alex')
View Code

 

posted @ 2017-09-06 11:40  amonos  阅读(186)  评论(0编辑  收藏  举报