09-函数基础

目录

函数声明

函数的文档说明

函数参数

形参和实参

位置参数

默认参数

关键字参数

不定长参数

函数返回值

基本使用

默认返回值

返回多个值

函数嵌套

作用域

LEGB

global

nonlocal

匿名函数

函数名的使用


函数声明

声明一个函数,也就是创建一个函数,可以理解为将一段可以重复使用的代码通过关键字def包裹起来。具体的语法格式如下:

'''
def 函数名(参数列表):
    '''
    # 函数说明文档,告诉别人这个函数的作用
    params: 参数
    return: 结果
    '''
    # 实现特定功能的多行代码
    [return [返回值]]
'''

定义了函数之后,就相当于有了一个具有某些功能的代码。函数的声明并没有执行函数中的代码块,想要执行函数体,需要进行函数调用,一个函数可以调用多次。函数调用语法:

函数名()

每次调用函数时,函数都会从头开始执行,当这个函数中的代码执行到最后或者遇到关键字return时,意味着调用结束了。

def foo():
    print("foo函数")


foo()   # foo函数

debug模式运行:

# 函数的声明
def bar():
    print("bar1")
    print("bar2")
    print("bar3")


# 函数的声明
def foo():
    print("foo1")
    print("foo2")
    print("foo3")


# 函数调用,一个函数可以调用多次,每次都是从第一行开始执行
foo()
# foo1
# foo2
# foo3

# 函数调用
bar()
# bar1
# bar2
# bar3

# 函数调用
foo()
# foo1
# foo2
# foo3

函数的文档说明

可以使用函数的文档说明,来提示使用者,当前函数的用法或者效果。

def triangle():
    "打印一个5行的三角形图案"
    line = 5
    for i in range(line):
        print(" " * (line - i), end="")
        print("*" * (i * 2 + 1))


# 通过help可以看到函数的文档信息
help(triangle)
# Help on function triangle in module __main__:
#
# triangle()
#     打印一个5行的三角形图案

print(triangle.__doc__)
# 打印一个5行的三角形图案

针对函数的使用,如果我们使用的编辑器是ide工具,一般都会对函数本身使用说明文档,进行提示:

针对函数的使用,如果我们使用的编辑器是ide工具,一般都会对函数本身使用说明文档,进行提示:
1. 我们可以通过鼠标悬放在函数名上方就可以看到函数的说明文档了。
2. 我们还可以通过Ctrl+鼠标左键,就可以直接跳转到函数声明位置(有可能是当前文件,也可能是python内置的python文件位置)。
3. 当我们如果跳转到了其他文件,希望能快速返回之前的鼠标点击位置,可以使用alt+方向键(← 和 →)
   如果同一个文件下,继续使用Ctrl+鼠标左键

如果我们使用的不是IDE工具,但是又想要了解函数的声明文档,可以使用以下2种方式:

# 1. 使用help函数打印指定函数的使用文档。
help(函数名) 

# 2. 通过print打印指定函数的__doc__属性
print(函数名.__doc__)

函数参数

形参和实参

函数的参数可以使函数的功能更加强大,让函数变得更加灵活:

"""案例1"""
def cal_sum(temp):  # temp 函数形式参数,简称形参。
    ret = 0
    for i in range(1,temp+1):
        ret+=i
    print(ret)

cal_sum(100)   # 函数实际参数,简称实参。
cal_sum(101)   


"""案例2"""
def add():
    x = 10
    y = 20
    print(x+y)

def add(x, y):  # 形参
    print(x + y)

# 调用add函数 # 将调用过程中传入的值称之为实际参数,简称实参
add(5, 6)  # 将5赋值给x,将6赋值给了y ,函数体将x+y,即5+6计算出来,打印
# 调用add函数
add(10, 5)  # 将10赋值给x,将6赋值给了y ,函数体将x+y,即10+5计算出来,打印

代码执行过程:Live Programming Mode - Python Tutor - Visualize Python and JavaScript code

在函数的定义阶段 括号内写的变量名,叫做该函数的形式参数,简称形参。

在函数的调用阶段,括号内实际传入的值,叫做实际参数,简称实参。该例中,temp就是的函数形式参数,而每次调用根据需要传入的值,比如100,101都是实参。

形参就相当于变量名,而实参就相当于变量的值,函数调用传参的过程 就是给形参变量名赋值的过程。

函数参数只有在函数调用阶段有效,函数运行结束,参数作为垃圾被内存释放(也就是删除)。

位置参数

调用函数时传入实际参数的数量和位置都必须和定义函数时保持一致。

# 例1
def add(x,y): # x,y是形参,用来接收实参

    print(x+y)

add(2,3) # 2,3 是实际参数,分别传递给形参x,y

# 例2
def add(x,y,z): 
    print(x+y)

add(2,3) # 缺少一个实际参数传递给z

# 例3
def add(x,y):
    print(x+y)

add(2,3,4) # 缺少一个形式参数接收4

默认参数

Python 允许为参数设置默认值,即在定义函数时,直接给形式参数指定一个默认值。这样的话,即便调用函数时没有给拥有默认值的形参传递参数,该参数可以直接使用定义函数时设置的默认值。

def print_stu_info(name,age,gender="male"):

    print("学员姓名:",name)
    print("学员年龄:",age)
    print("学员性别:",gender)

print_stu_info("张三",23)
# 学员姓名: 张三
# 学员年龄: 23
# 学员性别: male
def print_user_info(name, age, gender="男"):
    print("学员姓名:", name)
    print("学员年龄:", age)
    print("学员性别:", gender)


print_user_info("小明", 16)
print("* " * 30)
print_user_info("小红", 16, "女")

# 学员姓名: 小明
# 学员年龄: 16
# 学员性别: 男
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
# 学员姓名: 小红
# 学员年龄: 16
# 学员性别: 女

当定义一个有默认值参数的函数时,有默认值的参数必须位于所有没默认值参数的后面,否则报错!

关键字参数

关键字参数可以避免牢记参数位置的麻烦,令函数的调用和参数传递更加灵活方便。

关键字参数是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。

def print_stu_info(name,age,height,weight,job):

    print("学员姓名:",name)
    print("学员年龄:",age)
    print("学员身高:",height)
    print("学员体重:",weight)
    print("学员工作:",job)


print_stu_info("张三",23,"180cm","80kg","销售")
# 学员姓名: 张三
# 学员年龄: 23
# 学员身高: 180cm
# 学员体重: 80kg
# 学员工作: 销售
print_stu_info(name="张三",height="180cm",weight="90kg",job="销售",age=23)
# 学员姓名: 张三
# 学员年龄: 23
# 学员身高: 180cm
# 学员体重: 90kg
# 学员工作: 销售
print_stu_info("张三",height="180cm",weight="90kg",job="销售",age=23)
# 学员姓名: 张三
# 学员年龄: 23
# 学员身高: 180cm
# 学员体重: 90kg
# 学员工作: 销售

使用位置参数和关键字参数混合传参的方式,需要注意,混合传参时关键字参数必须位于所有的位置参数之后。

不定长参数

"""在工作中,有时候就会有些函数,就要接收个数不确定的参数。这时候,就可以使用不定长参数来完成。
不定长参数有2种写法:
1. 在形参的位置参数左边使用*表示,接收0~多个位置实参,这种情况下,*号左边的形参,在函数内部就是一个元组
2. 在形参的位置参数左边使用**表示,接收0~多个关键字参数,这种情况下,**号左边的形参,在函数内部就是一个字典
"""
"""*args"""
def add(*args):
    print(args)
    print(type(args))
    ret = 0
    for i in args:
        ret += i
    print(ret)


add(12, 23, 45)
# (12, 23, 45)
# <class 'tuple'>
# 80


"""**kwargs"""
def print_stu_info(**kwargs, ):
    print(kwargs)


print_stu_info(name="张三", height=190)
# {'name': '张三', 'height': 190}

 练习代码:

def func(*args):
    print(args)


func()  # ()
func(1)  # (1,)
func(1, 2)  # (1, 2)
func(1, 2, 3, 4, 5, 6, 7, 8, 9)  # (1, 2, 3, 4, 5, 6, 7, 8, 9)
def func(**dict_args):
    print(dict_args)


func()  # {}
func(a=1)  # {'a': 1}
func(x=1, y=2)  # {'x': 1, 'y': 2}
func(x=1, y=2, w=1, name=1, age=16, mobile="133123456")
# {'x': 1, 'y': 2, 'w': 1, 'name': 1, 'age': 16, 'mobile': '133123456'}

同时使用*args**kwargs:

def print_stu_info(name, age=18, *args, **kwargs):
    print(name, age)
    print(args)
    print(kwargs)

print_stu_info("yuan", 20, "China", "Beijing", height="188cm", weight="60kg")
# yuan 20
# ('China', 'Beijing')
# {'height': '188cm', 'weight': '60kg'}
def func1(*args, **kwargs):
    print(args)
    print(kwargs)


func1(10, 5, 10, 5, a=1, b=2, c=5)
# (10, 5, 10, 5)
# {'a': 1, 'b': 2, 'c': 5}
"""有了不定长形参以后,也可以在形参中继续使用位置参数和默认参数

形参的书写顺序:位置形参 > 默认形参 > 元组不定长形参  > 字典不定长形参

实参的书写顺序:位置实参 > 关键字实参"""

"""
调用函数时,我们如果参数较多,可以使用不定长实参:
可以使用*号把元组,列表,打散成位置实参
也可以使用**号把字典打散成关键字实参
"""
student_list = [
    {"name": "小名", "age": 17, "sex": True, "mobile": "1331234567"},
    {"name": "小白", "age": 27, "sex": False, "mobile": "1361234567"},
]


def func3(name, age, mobile, sex=False):
    """打印学生信息"""
    print(f"name={name}")
    print(f"age={age}")
    print(f"sex={sex}")
    print(f"mobile={mobile}")


# 打印小白的信息
func3(student_list[1]["name"], student_list[1]["age"], student_list[1]["mobile"])
# name=小白
# age=27
# sex=False
# mobile=1361234567


# 上一行代码,太长了,针对上面的代码,其实就是把字典中所有的数据传递给函数内部
stu = student_list[1]
func3(name=stu["name"], age=stu["age"], mobile=stu["mobile"])

# 使用星星打散,可以让上面代码可以缩写成一句
stu = student_list[1]
func3(**stu)  # 就是上面代码的简写 func3(name=stu["name"], age=stu["age"], mobile=stu["mobile"])



def func4(x, y, z):
    print(max([x, y, z]))


# list = [10, 2, 21]
# func4(list[0], list[1], list[2])

# 使用星星打散,可以让一个元组/列表使用逗号展开
list = [10, 2, 21]
func4(*list)  # 等同于func4(list[0], list[1], list[2])

"""
虽然有了不定长实参,但是如果函数声明时,使用的是位置形参,则不定长实参的数量一定要和位置形参的数量对应!!!
"""

注意点:

1、参数arg*args**kwargs三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)这个顺序,否则程序会报错。

2、不定长参数的长度可以为零。

3、argskwargs其实只是编程人员约定的变量名字,args是 arguments 的缩写,表示位置参数;kwargs 是 keyword arguments 的缩写,表示关键字参数。

函数返回值

到目前为止,我们创建的函数都只是对传入的数据进行了处理,处理完了就结束。但实际上,在更多场景中,我们还需函数将处理的结果反馈回来。通过关键字return语句可以返回任意类型的数值。

基本使用

def add(x,y):

    return  x+y # return是函数的终止语句

ret = add(2,3)
print(ret) # 5

默认返回值

在 Python 中,有一个特殊的常量 None(N 必须大写)。和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。None 是 NoneType数据类型的唯一值(其他编程语言可能称这个值为 null、nil 或 undefined),也就是说,我们不能再创建其它 NoneType类型的变量,但是可以将 None 赋值给任何变量。

Python一个函数中如果没有return语句或者return后没有具体值,都默认返回None,比如print()函数就没有返回值。

返回多个值

return可以返回多个值,python会将多个值放在一个元组中,以元组形式返回。

def login(user, pwd):
    flag = False

    if user == 'yuan' and pwd == 123:
        flag = True

    return flag, user


# ret = login("yuan",123)
# print(ret)  # (True, 'yuan')

flag, user = login("yuan", 123)

if flag:
    print("{}登陆成功!".format(user))
else:
    print("用户名或者密码错误!")

函数嵌套

def foo():
    def bar():
        print("bar功能")

    print("foo功能")
    bar()
    print(123)

foo()
# foo功能
# bar功能
# 123

# bar()  # 嵌套函数无法在外界使用。

作用域

所谓作用域(Scope),就是变量的有效范围,变量可以在哪个范围以内使用。

有些变量可以在整段代码的任意位置使用,有些变量只能在函数内部使用。

LEGB

字母英语释义简称作用空间
LLocal(function)当前函数内的作用域局部作用域局部
EEnclosing Functions Locals外部嵌套函数的作用域嵌套作用域局部
GGlobal(module)函数外部所在的命名空间全局作用域全局
BBuilt In(python)Python内置模块的命名空间内建作用域内置

 因为作用域的问题,所以按不同作用域可以把变量划分为2种:局部变量与全局变量。

  • 局部变量,函数内部声明的变量。默认情况下,只有在函数运行时局部变量才会出现在内存中,当函数执行结束,内存中的局部变量就会被销毁,所以局部变量无法被当前函数以外的地方使用。

  • 全局变量,函数外部声明的变量,或者在函数内部显式声明为全局变量。默认在任意位置都可以使用,从被声明的位置开始,直到程序结束或者被del关键字删除。

x = 100
def foo():
    x = 12
    def bar():
        x = 1
        print(x)
    bar()
foo()   # 1

global

count = 1


def a():
    count = 'a函数里面'

    def b():
        global count  # 告诉python,当前函数中使用的count,是顶级作用域的
        print(count)
        count = 2

    b()
    print(count)


a()
print(count)

# 1
# a函数里面
# 2

nonlocal

count = 1


def a():
    count = 'a函数里面'

    def b():
        nonlocal count  # 告诉python,当前函数中使用的count,不是b作用域的而是,外部作用域的
        print(count)
        count = 2

    b()
    print(count)


a()
print(count)
# a函数里面
# 2
# 1

以下代码会报错:

"""了解一下即可"""
num = 10
def func1():
    print(f"func1作用域, num={num}")
    def func2():
        num += 20 # num = num + 20  # 赋值运算,为什么会报错?因为加法赋值属于先加后赋值,因此导致当前作用域会认为,num+20的这个过程中,num是一个局部变量,但是实际上num是在加法运算之后才出现的,所以报错了。
        print(f"func2作用域, num={num}")
    func2()
    print(f"func1作用域, num={num}")
func1()
print(f"全局作用域, num={num}")

匿名函数

lambda 表达式,又称匿名函数,常用来表示内部仅包含 1 行表达式的函数。

如果一个函数的函数体仅有 1 行表达式,则该函数就可以用 lambda 表达式来代替。

lambda 表达式的语法格式如下:

name = lambda [list] : 表达式

其中,定义 lambda 表达式,必须使用 lambda 关键字;[list] 作为可选参数,等同于定义函数是指定的参数列表;value 为该表达式的名称。

def add(x, y):
    return x + y


print(add(2, 3))    # 5

print((lambda x, y: x + y)(2, 3))   # 5

可以这样理解 lambda 表达式,其就是简单函数(函数体仅是单行的表达式)的简写版本。相比函数,lambda 表达式具有以下 2 个优势:

  • 对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁;

  • 对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高程序执行的性能。

list = [1, "2", "C", "D", "A"]
# list.sort() # 会报错,因为列表中的成员类型不一样。

list = [1, "2", "C", "D", "A"]
# list.sort()

list.sort(key= lambda x: str(x))
print(list)  # [1, '2', 'A', 'C', 'D']

函数名的使用

python中函数与其他数据类型一样同属于一等公民(first-class elements,也叫一等对象)。

"""总而言之,就是你能把函数像普通变量一样任意地使用。包括赋值给变量以及作为其它函数的参数和返回值。
所以,所谓的“一等公民”是指代满足下述条件的程序实体:
1、可赋值给变量,让变量代表它运行。
2、可作为函数的参数。
3、可作为函数结果返回。
4、可包含在数据结构中,例如可以包含在列表等数据类型中作为成员存在。

因此,整数、浮点数、字符串、列表、字典、元组、函数、类本身、类型本身以及模块等都是对象。
因为都是对象,所以 Python 中的函数才和整数、字符串、列表、字典和元组等对象的地位是平等的,成为了“一等公民”。"""
def add(x, y):
    return x + y


def sub(x, y):
    return x - y


def div(x, y):
    return x / y


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


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


ret = calc(10, 20, add)
print(ret)  # 30

ret = calc(10, 20, sub)
print(ret)  # -10
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值