python——函数

定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

特性:

  1. 减少重复代码
  2. 使程序变的可扩展
  3. 使程序变得易维护

一、语法定义

def say_hi():
    print("hello world")


say_hi()  # 调用函数

二、函数的参数

def calc(x, y):
    res = x**y
    return res  # 返回函数执行结果


c = calc(2, 3)  # 结果赋值给c变量
print(c)
View Code

形参

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

实参

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

默认参数

看如下代码:

def stu_register(name,age,country,course):
    print("----注册学生信息------")
    print("姓名:",name)
    print("age:",age)
    print("国籍:",country)
    print("课程:",course)

stu_register("王山炮",22,"CN","python_devops")
stu_register("张叫春",21,"CN","linux")
stu_register("刘老根",25,"CN","linux")
View Code

发现 country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是 中国, 这就是通过默认参数实现的,把country变成默认参数非常简单:

def stu_register(name,age,course,country="CN"):

这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。

另外,你可能注意到了,在把country变成默认参数后,我同时把它的位置移到了最后面,为什么呢?

这就要谈到 “关键参数”了。

关键参数

正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),但记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后。

 

def stu_register(name, age, course='PY' ,country='CN'):
    print("----注册学生信息------")
    print("姓名:", name)
    print("age:", age)
    print("国籍:", country)
    print("课程:", course)
View Code

 

调用时
可以这样写:

stu_register("王山炮",course='PY', age=22,country='JP' )

但不能这样:

stu_register("王山炮",course='PY',22,country='JP' )

关键参数不可以放在未知参数之前,否则会报错。

也不能这样:

stu_register("王山炮",22,age=25,country='JP' )

相当于给age两次赋值,会报错。


非固定参数

 

若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数:*args,**kwargs。

def stu_register(name, age, *args):  # *args 会把多传入的参数变成一个元组形式
    print(name, age, args)


stu_register("Henry", 22, "IT", "2018-05-08")


输出:
Henry 22 ('IT', '2018-05-08')
View Code

 

def stu_register(name,age,*args,**kwargs):  # *kwargs 会把多传入的参数变成一个dict形式
    print(name,age,args,kwargs)


stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")

输出:
Jack 32 ('CN', 'Python') {'sex': 'Male', 'province': 'ShanDong'}  # 后面这个('CN', 'Python')就是args,{'sex': 'Male', 'province': 'ShanDong'}就是kwargs
View Code

返回值
函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回

def stu_register(name, age, course='PY', country='CN'):
    print("----注册学生信息------")
    print("姓名:", name)
    print("age:", age)
    print("国籍:", country)
    print("课程:", course)
    if age > 22:
        return False
    else:
        return True


registriation_status = stu_register("王山炮",22,course="PY全栈开发",country='JP')

if registriation_status:
    print("注册成功")
else:
    print("too old to be a student.")
View Code
  • 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,因此,可以理解为 return 语句代表着函数的结束
  • 如果未在函数中指定return,那这个函数的返回值为None

全局与局部变量

  • 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
  • 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数。
  • 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。
  • 可以在函数里面可以调用外面的全局变量,但不能修改全局变量。
  • 两个同级的独立的函数中相同名字的变量是互不相干的,不会存在相互调用等现象。
name = "Alex"


def change_name(name):
    print("before change:", name)
    name = "Jack"
    print("after change", name)


change_name(name)

print("在外面看看name改了么?",name)


输出:
before change: Alex
after change Jack
在外面看看name改了么? Alex
View Code

在程序运行完后,name的值依然没有改变,那么有没有办法让它改变呢??
当然有啦!改变它的作用域就可以了。

作用域

  在python中,一个函数就是一个作用域,函数定义完成或作用域就已经生成。

如何在函数里修改全局变量:

name = "Alex"


def change_name():
    global name  # 将name改为全局变量
    print("before change:", name)
    name = "Jack"
    print("after change", name)


change_name()
print("在外面看看name改了么?", name)

输出:
before change: Alex
after change Jack
在外面看看name改了么? Jack
View Code

在函数内部将name定义为全局变量,这样就可以改变它的值了。
其他作用域示例:

names = ["luara", "jason", "henry"]


def change_name():
    names = ["luara", "jason"]
    print("after change:", names)
change_name()
print("outer:", names)

输出:
after change: ['luara', 'jason']
outer: ['luara', 'jason', 'henry']
View Code
names = ["luara", "jason", "henry"]


def change_name():
    del names[2]
    print("after change:", names)


change_name()
print("outer:", names)

输出:
after change: ['luara', 'jason']
outer: ['luara', 'jason']
View Code

从以上两个程序运行结果发现,第二个程序的names被改变了,为什么呢?
原因是:与之前讲的深浅copy一个道理,一个列表就有一个自己的内存地址,而其里面的元素又有它们自己单独的内存地址,在函数内对列表整体进行修改时,不会影响外层的names,但对列表内的元素进行操作时,便会影响外层的names。类似的还有字典、类、集合等。

age = 19


def func1():
    age = 73

    def func2():
        print("func2:", age)
    return func2  # 返回一个函数名


val = func1()  # val获取到了func2的内存地址
print(val)
val()  # 此时相当于执行func2()

输出:
<function func1.<locals>.func2 at 0x0000000001E59AE8>  # 打印了func2的内存地址
func2: 73
View Code

嵌套函数
  在一个函数体内用“def”定义了另外一个函数就叫嵌套函数。

def func1():
    print("alex")

    def func2():
        print("eric")


func1()

输出:
alex
View Code

发现内层的函数func2没有执行,因为程序没有调用它,一个函数如果没有被调用,它是永远不会执行的。

def func1():
    print("alex")

    def func2():
        print("eric")


    func2()  # 调用func2


func1()  # 调用func1


输出:
alex
eric
View Code

 

age = 19


def func1():
    age = 73
    print("func1:", age)

    def func2():
        print("func2:", age)

    func2()

    
func1()

输出:
73
73
View Code
age = 19


def func1():

    def func2():
        print("func2:", age)
    age = 73
    func2()


func1()

输出:
func2: 73
View Code

在函数执行过程中,如果在自己内部没有找到age,它就会去它的外面一层找,若找到了就打印,若没有找到,就会接着再往外寻找,直到找到为止。
所以说,嵌套函数是从内到外,逐层寻找

匿名函数

  不需要显示的指定函数名的函数就叫匿名函数。

语法:

lambda 参数:表达式

如下代码:

def calc(x, y):
    return x * y


print(calc(2, 3))

可以用匿名函数改写为:

calc = lambda x,y: x * y
print(calc(2, 3))

匿名函数三元运算:

calc = lambda x, y: x if x > y else y
print(calc(3, 1))

匿名函数主要与其他函数搭配使用:

res = list(map(lambda x: x**2, [1, 2, 3, 4]))
print(res)

输出:
[1, 4, 9, 16]

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

def add(x, y, f):
    return f(x) + f(y)  # 相当于abs(4) + abs(-9)


res = add(4, -9, abs)
print(res)

输出:
13
View Code

只需满足以下任意一个条件,即是高阶函数:

  • 接收一个或多个函数名作为参数输入
  • return 返回另外一个函数(返回值中包含函数名)

 递归函数

如果一个函数在内部调用自身本身,这个函数就是递归函数。

递归函数示例:n的阶乘,这是我认为最能直观理解递归执行过程的示例

def fact(n):
    if n == 1:
        return 1  # 当n=1时结束递归
    return n * fact(n-1)


res = fact(5)
print(res)
View Code

函数执行过程:

在n=1之前,函数将一直被挂起,直到遇到结束条件,函数再一层一层返回。

传入一个数,只执行5次就结束:

def calc(n, count):
    print("n:{},   count:{}".format(n, count))
    if count < 5:
        return calc(n/2, count+1)
    else:
        return n  # 如果count>5 就返回当前的n值


res = calc(188, 0)
print("程序结束时的n值:", res)

输出:
n:188,   count:0
n:94.0,   count:1
n:47.0,   count:2
n:23.5,   count:3
n:11.75,   count:4
n:5.875,   count:5
程序结束时的n值: 5.875
View Code

递归特性:

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

堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html

递归函数实际应用案例,二分查找

# 使用二分法查找列表中的某个数据
li = [2, 3, 6, 44, 34, 78, 67, 77, 90, 345, 67, 39, 100, 104, 209, 56, 789, 290, 62]


def find(li1, num):
    print(li1)
    n = int(len(li1)/2)  # 列表长度折半
    if n >= 1:  # 列表元素大于1
        if num < li1[n]:  # 数字在列表左边
            print("the number is in the left of the list")
            return find(li1[0:n], num)
        elif num > li1[n]:  # 数字在列表右边
            print("the number is in the right of the list")
            return find(li1[n+1:], num)
        elif num == li1[n]:
            print("find the number:", li1[n])
    else:
        if num == li1[n]:
            print("find the number:", li1[n])
        else:
            print("the number is not existed!")


li.sort()  # 列表元素排序
print(li)
find_num = int(input("input the number you want to find:"))
find(li, find_num)
View Code

内置函数

内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii

 

 

 

 

 

 

 

posted @ 2018-05-09 11:53  随风飘-挨刀刀  阅读(197)  评论(0编辑  收藏  举报
Top