1、函数

1.1、编程的方式:

(1)面向对象 -->华山派  -->独门秘籍:类   -->定义关键字:class
(2)面向过程 -->少林派  -->独门秘籍:过程  -->定义关键字:def
(3)函数式编程    -->逍遥派  -->独门秘籍:函数  -->定义关键字:def

1.2、函数是什么?

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

2.3、函数语法定义:

函数语法:
def 函数名(参数1,参数2,参数3,...):
    '''注释'''
    函数体
    return 返回的值

python演示:
def auth(user,password):
    '''
        auth function
        :param user: 用户名
        :param password: 密码
        :return: 认证结果
    '''
    if user == 'kim' and password == '123':
        return 0
    else:
        return 1
user = input("用户名:").strip()
pwd = input("密码:").strip()
res=auth(user,pwd)
print(res)

执行结果:
用户名:kim
密码:123
0

2.4、函数返回值

无return->None
return 1个值->返回1个值
return 逗号分隔多个值->元组
要想获取函数的执行结果,就可以用return语句把结果返回

注意:

函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
如果未在函数中指定return,那这个函数的返回值为None

什么时候该有返回值?
    调用函数,经过一系列的操作,最后要拿到一个明确的结果,则必须要有返回值
    通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果
什么时候不需要有返回值?
    调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值
    通常无参函数不需要有返回值

2.5、函数的参数

形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应该与形参一一对应)
实参:实际参数,调用函数时传给函数的参数,可以是变量,常量,表达式,函数,传给形参。
区别:形参是虚拟的,不占用内存空间,形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据单向传送,实参传给形参,不能形参传给实参。

★★★★★关键参数是不能写在位置参数前面的!!!!!!

def test1(x,y):
    print(x,y)
test1(1,2)-->位置调用,和形参一一对应
test1(x=1,y=2)-->关键字调用,与形参顺序无关

****************************************
默认参数:
def test1(x,y=2): -->y有默认值为2
    print(x,y)  
test1(1,3)

默认参数特点:调用参数的时候,默认参数非必须传递
默认参数用途:默认安装值,端口等

参数组:
*args-->接收多个参数,以元组的方式进行存储
**kwargs-->接受N个关键字参数,以字典的方式进行存储

2.6、总结:

#1、位置参数:按照从左到右的顺序定义的参数
        位置形参:必选参数
        位置实参:按照位置给形参传值

def test1(x,y):
    print(x,y)
test1(1,2) #位置参数
test1(x=4,y=6) #关键字参数
执行结果:
1 2
4 6

#2、关键字参数:按照key=value的形式定义的实参
        无需按照位置为形参传值
        注意的问题:
                1. 关键字实参必须在位置实参右面
                2. 对同一个形参不能重复传值
#3、默认参数:形参在定义时就已经为其赋值
        可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
        注意的问题:
                1. 只在定义时赋值一次
                2. 默认参数的定义应该在位置形参右面
                3. 默认参数通常应该定义成不可变类型

def test2(x,y=3): #默认参数y的值为3
    print(x,y)
test2(2)
test2(2,6)
执行结果:
2 3
2 6

#4、可变长参数(*args,**kwargs):
        可变长指的是实参值的个数不固定
        而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它

def test3(*args): #可变长参数,使用*args接收N个位置参数,并且以元组的方式存储
    print(args)
test3(1,2,3,4,5,6)
执行结果:(1, 2, 3, 4, 5, 6)

def test4(name,*args): #可变长参数和位置参数混合使用
    print(name,args)
test4('alex',4,5,6)
test4(1,*[1,2,3])
执行结果:
alex (4, 5, 6)
1 (1, 2, 3)

def test5(x,y,**kwargs): #**kwargs接受N个关键字参数,以字典的方式进行存储
    print(x,y)
    print(kwargs)
test5(1,2,c=3,d=4,e=5)
test5(1,y=2,**{'a':1,'b':2,'c':3})
执行结果:
1 2
{'d': 4, 'e': 5, 'c': 3}
1 2
{'a': 1, 'b': 2, 'c': 3}

def test6(*args,**kwargs):
    print(args)
    print(kwargs)
test6(5,6,7,a=1,b=5) #位置参数必须在关键参数的前面,否则会报错
执行结果:
(5, 6, 7)
{'a': 1, 'b': 5}

3、全局与局部变量

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

school="oldboy" --->全局变量school
def change_name(name):
    #global school -->强制修改全局变量,需要进行申明:global 变量名,最好别用此方法
    school="MaGe linux"
    print("before change:",name,school)
    name="Alex li" #局部变量,只在函数体内生效,这个函数就是此变量的作用域
    print("after change:",name)

name="alex"
change_name(name)
print(name)
print(school)
执行结果:
before change: alex MaGe linux
after change: Alex li
alex
oldboy

★★注意:在列表,字典,集合,类等特殊类型变量在函数体内是可以进行修改的,如下演示:
names = ["Alex","Jack","Rain"]
def change_name():
    names[0] = "哈哈"
    print("inside :",names)
change_name()
print(names)
执行结果:
inside : ['哈哈', 'Jack', 'Rain']
outside : ['哈哈', 'Jack', 'Rain']

4、函数递归

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

def calc(n):
    print(n)
    if int(n / 2) == 0:
        return n
    return calc(int(n / 2))
calc(10)
执行结果:
10
5
2
1

5、函数式编程介绍

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。

Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

一、定义

简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。

主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式:

  (1 + 2) * 3 - 4

传统的过程式编程,可能这样写:

  var a = 1 + 2;

  var b = a * 3;

  var c = b - 4;

函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:

  var result = subtract(multiply(add(1,2), 3), 4);

这段代码再演进以下,可以变成这样

add(1,2).multiply(3).subtract(4)

这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:

merge([1,2],[3,4]).sort().search("2")

因此,函数式编程的代码更容易理解。

###13.10、高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

def add(x,y,f):
    return f(x)+f(y)
res = add(3,-6,abs)  #abs本身为一个函数,取绝对值
print(res)
执行结果:
9

6、函数练习:

1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作

2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
def count(msg):
    res={
        'num':0,
        'string':0,
        'space':0,
        'other':0
    }
    for s in msg:
        if s.isdigit():
            res['num']+=1
        elif s.isalpha():
            res['string']+=1
        elif s.isspace():
            res['space']+=1
        else:
            res['other']+=1
    return res
res=count('hello world ! 123')
print(res)

3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。

4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
def check_list(msg):
    while type(msg) == list:
        if len(msg) >2:
            msg=msg[0:2]
        return msg
print(check_list([1,2,3,4,5,6,7]))

5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
def check_list2(seq):
    seq=seq[::2]---------->从头遍历到尾,步长为2
    return seq
print(check_list2([1,2,3,4,5]))

6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
方法一:
def check_dict(seq):
    d={}
    for k, v in seq.items():
        if len(v) > 2:
            d[k] = v[0:2]
    return d
print(check_dict({'k1':'abcdef','k2':[1,2,3,4],'k3':('a','b','c')}))
执行结果:
{'k2': [1, 2], 'k1': 'ab', 'k3': ('a', 'b')}

方法二:
def check_dict(seq):
    d={}
    for i in seq:
        if len(seq[i]) > 2:
            d[i] = seq[i][0:2]
    return d
print(check_dict({'k1':'abcdef','k2':[1,2,3,4],'k3':('a','b','c')}))
执行结果:
{'k2': [1, 2], 'k1': 'ab', 'k3': ('a', 'b')}