【Python基础】13. 函数 Function

2018-09-21  本文已影响0人  古月半半

这篇笔记记录的知识点:

  • 函数的基本概念
  • 自定义函数
  • 函数的几种参数

编程的三种方式:
1.OOP 面向对象编程,万物皆对象,以class为主,抽象化
2.POP 面向过程编程,万事皆过程,def定义过程
3.函数式编程,将某种功能封装起来,用的时候直接调用函数名,def定义函数,也叫function/方法/过程/子程序

</br>

函数的基础概念:

</br>

自定义函数

定义函数的格式:

python定义函数使用def关键字,一般格式如下:

def 函数名(参数):
    '''文档字串符(docstring),注释,描述该函数是做什么的'''
    函数体(代码行)         #这个函数要实现的功能代码

函数名的命名规则:

函数的调用

定义了函数之后,就相当于有了一个具有某些功能的代码
但是,函数是不会自动执行的,想要让这些代码能够执行,需要调用它
调用函数很简单的,通过 函数名()即可完成调用:

def test1():                    # 定义函数名
    print("hello!")             # 定义函数的功能
    
test1()                         # 调用函数

函数的文档说明
文档字串符(docstring)描述该函数是做什么的,尽量给自定义函数备注,方便日后查看使用.

def test(a,b):
 '''用来完成对2个数求和'''
     print("%d" % (a+b))

test(11,22)

如果执行,以下代码:

help(test)

能够看到test函数的相关说明:

Help on function test in module __main__:

test(a, b)
    用来完成对2个数求和
(END)

Tips: 使用三引号来构成文档字符串,用来解释该函数的主要功能,这是一个很好的编码习惯.

</br>

函数的参数

实参和形参

实参是一个实实在在存在的参数,是实际占用内存地址的
形参只是意义上的一种参数,在定义的时候是不占内存地址的.

形参:形式参数,不是实际存在,是虚拟变量,在定义函数和函数体的时候使用形参,目的就是在函数调用的时候接收实参(实参个数,类型应与实参一一对应)

实参:实际参数,调用函数时候传给函数的变量,可以是常量,变量,表达式,函数,传给形参

区别:形参是虚拟的,不占用内存空间,形参变量只有在调用时才分配内存单元,实参是一个变量,占用空间,数据传送单向,实参传给形参,不能形参传给实参。

def sum_num(a,b):        #a,b 是形参
    sum_num = a+b
    print(sum_num)
    
sum_num(10,33)           #10,33 是实参

定义时小括号中的参数,用来接收参数用的,称为 “形参”
调用时小括号中的参数,用来传递给函数用的,称为 “实参”
没特别指明,形参和实参必须一一对应,多一个少一个都报错

</br>

常用的几种参数类型:

在Python中可以使用必选参数,默认参数,可变参数,关键字参数,这四类可以一起使用,或者只使用其中某一些.
但是有多种参数,在定义函数和传参的时候,必须要注意参数的置放顺序:
参数的顺序必须是:

<h6 align = "center" >必备参数,可变(不定长)参数*args, 默认(缺省)参数,可变(不定长)参数**kargs,关键字参数 </h6>

1. 必备参数(位置参数)

def func_1(name,sex):
    sex_dict = {1: u'先生', 2: u'女士'}
    print ('hello %s %s, welcome to python world!' %(name, sex_dict.get(sex, u'先生')))
func_1("刘",2)

运行结果:hello 刘 女士, welcome to python world!

2. 默认参数(缺省参数)

def func_2(name,age=18):
    print("我是位置参数:%s"%name,"我是默认参数:%s"%age)

func_2("如花")   #只给name传参,会调用默认参数的值
func_2("如花",28)  #给age传参,会覆盖之前的默认参数

运行结果如下:

我是位置参数:如花 我是默认参数:18
我是位置参数:如花 我是默认参数:28

3. 可变参数(不定长参数)

(1) 包裹位置传递*args
我们传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。

def func(*args):
    ....
    
# func()
# func(a)
# func(a, b, c)

(2)包裹关键字传递**kargs
kargs是一个字典(dict),收集所有关键字参数

def func(**kargs):
    ....

# func(a=1)
# func(a=1, b=2, c=3)

(3) 对于*args**kwargs在函数中我们可以称之为参数组,但是这两个还是有区别的

1:args的功能:------接收N个位置参数,转换成元组tuple形式
2:
kwargs的功能------接收N个关键字参数,转换成字典dict形式
3:位置参数一定要在关键字参数之前,也就是(
args,**kwargs)

(4) *args**kwargs一起用, 功能会更强大
可以两个一起使用:功能更加的强大:会把无参数名臣的封装成一个tuple 把有参数名称的封装成一个字典;并且,arg必须在**kwargs前面

# def show(*args ,**kwargs):
#     print(args,kwargs)
# show(11,22,33,nn=22,kk=33)

值得注意的是虽然*args**kwargs会把我们给他的参数封装成列表和字典,但是如果我们在给定实际参数的时候给的是一个列表或者是字典,只是表示只有一个实参,而不是列表和字典里面的值;如果想要实现这个功能,那么我们就需要在列表或者字典前面加上*或者**就能实现了;

4. 关键字参数

用于函数调用,通过“键-值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。

#以下是用关键字参数正确调用函数的实例 
func_01('tanggu', sex=1)
func_01(1, name='tanggu')
func_01(name='tanggu', sex=1)
func_01(sex=1, name='tanggu')

# 以下是错误的调用方式
func_01(name='tanggu', 1)
func_01(sex=1, 'tanggu')

tips:虽然函数参数类型很多,但不要同时使用太多的组合,否则函数接口的可理解性很差.

</br>

函数的返回值

函数的返回值是函数重要的组成部分。函数的根本在于实现程序的部分功能,所以很多时候我们需要将函数执行后的结果返回给程序再由程序作出进一步的操作。可以说是函数的返回值令函数与函数之间,函数与主程序之间更加紧密的联系起来。

函数的返回值:

def func_2(name,age=18):
    print("我是位置参数:%s"%name,"我是默认参数:%s"%age)


func_2("如花")   #只给name传参
func_2("如花",28)  #给age传参,会覆盖之前的默认参数


def without_return(a,b):  #定义一个没有return的函数
    print(a+b)
    print(a-b)


def with_return(a,b):   #定义一个有return的函数
    return a+b
    return a-b

result1 = without_return(5,10)  #调用上边定义的没有return的函数
result2 = with_return(5,10)     #调运上边定义的有return的函数

print("没有返回值的函数:",result1)
print("有返回值的函数:",result2)

上段代码运行后,结果如下:

15
-5
没有返回值的函数: None
有返回值的函数: 15

[注意:]

接收多个rerun值

理论上,return只能返回一个值; 如果想要返回多个值,可以考虑把多个值放在列表,元祖,字典里边.

def return_value():
    print('返回多个值')
    return [1,3,5]
    #return (1,3,5)
    #return {'a':1,'b':2,'c':3}

result = return_value()
print(result)

上述代码运行结果:

返回多个值
[1, 3, 5]

函数的嵌套调用

def show_msg():
    print("show_msg")# 在函数里面定义的函数就是嵌套函数
    
    def show():   
        print("我是函数体里面的内部函数->>子函数")
    
    show()       # 在函数体里面调用嵌套函数
 
show_msg()      # 调用函数
                # 注意点: 嵌套函数不能再函数外使用,只能在函数内部使用

上述代码运行结果:

show_msg
我是函数体里面的内部函数->>子函数

函数嵌套的小应用: 使用冰箱:

def use_ice_box(eat):
    # 嵌套函数的作用,把函数拆分成不同的功能函数

    # 打开冰箱
    def open_ice_box():
        print("打开冰箱门")

    # 向冰箱放入食物
    def put_eat(eat):
        print("把%s放入冰箱" % eat)

    # 关闭冰箱
    def close_ice_box():
        print("关闭冰箱门")


    open_ice_box()
    put_eat(eat)
    close_ice_box()


use_ice_box("苹果")

局部变量和全局变量,函数的作用域

变量作用域

LEGB原则

局部变量

全局变量和关键字global

num1 = 1     #<--全局变量

def funcA():
    num1 = 3      #<--- 局部变量.可以理解为定义了一个局部变量,只不过局部变量的名字和全局变量的名字相同而已,不是同一个变量
    print("funcA里的变量:",num1)

def funcB():
    print("funcB里的变量:",num1) 

funcA()
funcB()

上述代码运行结果:

funcA里的变量: 3
funcB里的变量: 1

使用关键字global修改全局变量

当内部作用域想修改外部作用域的变量时,要用到global和nonlocal关键字了。
global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。

# 修改全局变
num1 = 1

def funcA():
    global num1    # <-- 表示声明要修改全局变量
    num1 = 3
    print("funcA里的变量:",num1)

def funcB():
    print("funcB里的变量:",num1)

funcA()
funcB()

运行结果:

funcA里的变量: 3
funcB里的变量: 3

在Python中,以上边代码为例,如果在函数内部对全局变量num1进行修改, Python会把变量num1当做是局部变量,为了使全局变量生效,我们可以在函数内使用global关键字进行声明.
如果没有对变量num1进行全局变量申明,运行程序后会报错:UnboundLocalError: local variable 'a' referenced before assignment

nonlocal关键字

nonlocal是在Python3.0中新增的关键字,python2.x不提供支持。
使用nonlocal关键字可以在一个嵌套的函数中修改嵌套作用域中的变量。
示例一:

def FinalResult():
    result = 0
    print("外部函数的变量result的值为:"+ str(result))

    def sumResult():
        result = 12
        print("内部函数的变量result的值为"+str(result))
    sumResult()


FinalResult()

上述示例一代码运行结果如下:

外部函数的变量result的值为:0
内部函数的变量result的值为12

示例二:

def FinalResult():
    result = 0
    #print("外部函数的变量result的值为:"+ str(result))

    def sumResult():
        result = 12
        print("内部函数的变量result的值为"+str(result))

    sumResult()
    print("外部函数的变量result的值为:"+ str(result))


FinalResult()

上述示例二代码运行结果如下:

内部函数的变量result的值为12
外部函数的变量result的值为:0

注意 通过上述示例可以看出, 嵌套在函数FinalResult内部的内嵌函数sumResult中, 我们对变量result的赋值,其实本质是重新创建了一个新的变量,而不是外部函数FinalResultresult=0这条语句的重新赋值.
(2) 通过调换外部函数的print语句调用内部函数sumResult两条语句的先后位置, 可以对比发现, 内部函数的变量赋值,无论什么时候被调用都没有对外部的同名变量造成影响.

示例三:

def FinalResult():
    result = 0

    def sumResult():
        nonlocal result
        result = 12
        print("内部函数的变量result的值为"+str(result))

    sumResult()
    print("外部函数的变量result的值为:"+ str(result))

FinalResult()

上述示例三代码运行结果如下:

内部函数的变量result的值为12
外部函数的变量result的值为:12

注意

[小总结:]
一个变量在函数体外,一个变量在函数体内, 改变量用global.
一个变量在内嵌函数里,一个变量在包裹内嵌函数的外层函数里,改变量nonlocal

多层嵌套函数和函数外同用一个变量,用global申明.

(这段代码为实验,不确定全适用,也有可能方法有点蠢,因为后来发现,貌似可以用return( ̄. ̄))

假设我们有一个变量result,这个变量会在函数体外使用,也会在多层嵌套的函数的某几个层里使用.
我们希望达到的效果是:在任何一个地方修改变量result,所有位置的变量result的值都改变,即在之后无论在函数外还是函数内再调用这个变量result,得到的是最新的result的值.具体实现如下:

示例四:

result = 10     # <== 函数外的变量result
print("函数外的result变量:"+str(result))     #<== 第一条print执行语句

def FinalResult():
    global result    <== 申明result为全局变量, 这里如果不申明, 知result程序默认不是同一个变量,只是同名.
    result = 11

    print("外部函数的变量result的值为:"+ str(result))    # <== 第2条print执行语句
    def sumResult():
       #nonlocal resul     # <== 这里如果用nonlocal,会报错
        global result   #用global申明result为全局变量
        result = 12
        print("内部函数的变量result的值为"+str(result))     # <== 第3条print执行语句


    sumResult()
    print("调用完最里层函数后,再次打印外部函数的变量result的值为:"+ str(result))     #<== 第四条print执行语句


FinalResult()
print("调用完最里层函数后,再次打印函数外的result变量:",result)    #<== 第5条print执行语句

[小总结:]

</br>

函数的拆包 & 交换变量值

拆包

list1 = [2,3,4]
a,b,c =list1   # 拆包的时候需要一一对应,不能多
print(a, b)

tuple1 = ("张三", "李四")
name1, name2 = tuple1
print(name1, name2)

dict1 = {"name": "小新", "age": 5}.values()
value1, value2 = dict1
print(value1, value2)

str1 = "apple"
a, b, c, d, e, = str1
print(a, b, c,d,e)

上述代码运行结果:

2 3
张三 李四
小新 5
a p p l e

[注意:]变量名的数量一定要和容器内元素的数量一模一样,否则会报错.
例: alueError: not enough values to unpack (expected 6, got 5),ValueError: too many values to unpack (expected 4)

交换两个变量的值

num1 = 1
num2 = 2

num3 = num1
num1 = num2
num2 = num3
print(num1, num2)
num1 = 1
num2 = 2

num1, num2 = num2, num1
print(num1, num2)

多函数程序的基本使用流程

一般在实际开发过程中,一个程序往往由多个函数)组成,并且多个函数共享某些数据,这种场景是经常出现的,因此下面来总结下,多个函数中共享数据的几种方式:

  1. 使用全局变量
  2. 使用函数的返回值、参数
  3. 函数嵌套调用
  1. 使用全局变量
score = 100
# 修改全局变量数据的函数
def modify():
    # 声明修改全局变量
    global score
    # 修改全局变量
    score = 90
    print("modify:", score)

# 获取全局变量修改后的数据
def show():
    # 获取全局变量的数据
    print("获取全局变量修最新的数据:", score)

modify()
show()

上述代码运行后的结果:

modify: 90
获取全局变量修最新的数据: 90
  1. 使用函数的返回值、参数
def return_value():
    return "哈哈"
    
def show_info(msg):
    print(msg)
    
# 1.获取函数的返回值
value = return_value()
# 2.把函数的返回值作为其他函数的参数使用
show_info(value)

上述代码的运行结果:

哈哈
  1. 函数嵌套调用
def test1():
    # 通过return将一个数据结果返回
    return 20

def test2():
    # 1. 先调用test1并且把结果返回来
    result = test1()
    # 2. 对result进行处理
    print(result)

# 调用test2时,完成所有的处理
test2()

上述代码运行结果:

20

总结:函数使用注意事项

1. 自定义函数
无参数、无返回值
def 函数名():
    语句
无参数、有返回值
def 函数名():
    语句
    return 需要返回的数值
有参数、无返回值
def 函数名(形参列表):
    语句
有参数、有返回值
def 函数名(形参列表):
    语句
    return 需要返回的数值
2.调用函数

调用的方式为:函数名([实参列表])

3.作用域

参考资料:

扩展阅读:
cnblog-Python进阶-函数默认参数

上一篇下一篇

猜你喜欢

热点阅读