一、背景

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

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

腚眼一看上述代码,if条件语句下的内容可以被提取出来公用,如下:

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

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

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

函数式编程最重要的是增强代码的重用性和可读性

二、定义和使用

def 函数名(参数):
       
    ...
    函数体
    ...
    返回值

函数的定义主要有如下要点:

  • def:表示函数的关键字
  • 函数名:函数的名称,日后根据函数名调用函数
  • 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
  • 参数:为函数体提供数据
  • 返回值:当函数执行完毕后,可以给调用者返回数据。

1. 返回值

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

以上要点中,比较重要有参数和返回值:

def 发送短信():
       
    发送短信的代码...
   
    if 发送成功:
        return True
    else:
        return False
   
   
while True:
       
    # 每次执行发送短信函数,都会将返回值自动赋值给result
    # 之后,可以根据result来写日志,或重发等操作
   
    result = 发送短信()
    if result == False:
        记录日志,短信发送失败..
				

2、参数

  • 普通参数
  • 默认参数
  • 动态参数

普通参数

# ######### 定义函数 ######### 

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

# ######### 执行函数 ######### 
#  'wupeiqi' 叫做函数func的实际参数,简称:实参
func('wupeiqi')

默认参数

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

# 指定参数
func('wupeiqi', 19)
# 使用默认参数
func('alex')

注:默认参数需要放在参数列表最后

动态参数

def func(*args):

    print(args)


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

# 执行方式二
li = [11,2,2,3,3,4,54]
func(*li)
def func(**kwargs):

    print(args)


# 执行方式一
func(name='wupeiqi',age=18)

# 执行方式二
li = {'name':'wupeiqi', age:18, 'gender':'male'}
func(**li)
def func(*args, **kwargs):

    print(args)
    print(kwargs)

三、局部变量和全局变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。 当全局变量与局部变量同名时: 在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。

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 calc(n):
    print(n)
    if int(n/2) ==0:
        return n
    return calc(int(n/2))
 
calc(10)
 
输出:
10
5
2
1
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
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)

递归问路

递归特性:

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

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

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

五、匿名函数

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

#这段代码
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

六、内置函数

  1. map
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函数
  1. filter
#电影院聚集了一群看电影bb的sb,让我们找出他们
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))


--------------

name_dic=[
    {'name':'alex','age':1000},
    {'name':'wupeiqi','age':10000},
    {'name':'yuanhao','age':9000},
    {'name':'linhaifeng','age':18},
]

res = filter(lambda x:x['age'] <= 18,name_dic)
print(list(res))
filter函数

3.reduce

l = [1,2,3,100]
def gn(x,y):
    return x*y

def reduce_test(sd,lis,init=None):
    if init is None:
        res = lis.pop(0)
    else:
        res = init
    for i in lis:
        res = sd(res,i)
    return res

print(reduce_test(gn,l,100))

------------------------
from functools import reduce

res = reduce(lambda x,y:x+y,l,100)
print(res)

总结:

  • map:理序列中的每个元素,得到的结果是一个‘列表’,该‘列表’元素个数及位置与原来一样
  • filter遍历序列中的每个元素,判断每个元素得到布尔值,如果是True则留下来
  • reduce:处理一个序列,然后把序列进行合并操作
# print(abs(1)) #绝对值
# print(all([1,23,''])) #是否都为真
# print(all(''))  #为真
# print(any([1,3,''])) #只要有一个为真,即为真
# print(bin(10))#10进制->2进制
# print(hex(12))#10进制->16进制
# print(oct(12))#10进制->8进制

#空、NONE、0、的布尔值为false,其余都为true
# print(bool(''))

# name = '你好'
# print(bytes(name,encoding='utf-8')) #转换为字节,并指定字符编码格式
# print(bytes(name,encoding='utf-8').decode('utf-8'))


# print(divmod(10,3)) #做除法,显示商和余数,可用于分页判断

#可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型
# name = 'lingxd'
# print(hash(name))
# print(hash(name))
#
# print(help(all))

# print(isinstance(1,int)) #判断 数据类型是否正确
# print(isinstance(1,str))

# print(globals()) #全局变量
# print(locals()) #局部变量

# l = [1,2,34]
# print(max(l)) #输出最大值
# print(min(l)) #输出最小值

# print(list(zip(('a','b','c'),(1,2,3))))
#
# p = {'name':'lingxd','age':25,'gender':'man'}
# print(list(zip((p.keys()),(p.values()))))
#
# print(list(zip((['a','b']),('12345'))))

# l={'alex_age':18,'wupei_age':20,'zsc_age':100,'lhf_age':30}
#
# print(max(zip((l.values()),(l.keys()))))

# people=[
#     {'name':'alex','age':1000},
#     {'name':'wupei','age':10000},
#     {'name':'yuanhao','age':9000},
#     {'name':'linhaifeng','age':18},
# ]
# 
# print(max(people,key=lambda dic:dic['age']))

# print(chr(97))  #转换为字符编码
# print(ord('a'))  #反转字符编码
#
# l = [1,2,3,4,5]
# print(list(reversed(l)))  #反转,不会修改原数据
#
# print(pow(3,2)) #相当于3**2
# print(pow(3,2,2)) #相当于3**2 %2取余数

# print(round(3.6)) #四舍五入
#
# l = 'lingxd'
# s1 = slice(1,3)  #相当于切片操作,定义切片
# print(l[s1])

# l = [3,2,5,9,11]
# print(sorted(l))  #排序,从小到大
#
# people=[
#     {'name':'alex','age':1000},
#     {'name':'wupei','age':10000},
#     {'name':'yuanhao','age':9000},
#     {'name':'linhaifeng','age':18},
# ]
#
# print(sorted(people,key=lambda dic:dic['age']))
# name_dic={
#     'abyuanhao': 11900,
#     'alex':1200,
#     'wupei':300,
# }
#
# print(sorted(zip((name_dic.values()),(name_dic.keys()))))


# l=[1,2,3,4]
# print(sum(l))  #求和
# print(sum(range(5)))

# print('123',type('123')) #显示类型

# s = '123'
# if type(s) is str:
#     s = int(s)
#     res = s+1
#     print(res)

# def heh():
#     s = 'heheh'
#     print(locals())
#     print(vars())
# 
# heh()
# 
# print(vars(type))