14-Python基础知识学习---函数基础

定义函数

  函数是带有名称的代码块,用于完成具体的工作,通过调用函数可以执行其中定义的特定任务。如果需要在程序中多次执行同一项任务,这时候就无需反复编写完成该任务的代码,只要执行该任务的函数,让Python执行其中的代码即可。

  函数的使用必须遵循 "先定义,后使用" 的原则。函数的定义就相当于事先将函数体代码保存起来,然后将内存地址赋值给函数名,函数名就是对这段代码的引用,这个变量的定义是相似的。简单的函数定义的语法如下:

def 函数名(参数1,参数2,...):
    函数体
    return 值
  • def:该关键词用来告诉Python要定义一个函数
  • 函数名:函数名指向函数内存地址,是对函数体代码的引用( 函数的命名应该反映出函数的功能
  • 括号:括号内用来定义参数, 参数是可有可无的,且无需指定参数的类型
  • 冒号:括号后面需要加上冒号,然后在下一行开始编写函数体的代码
  • 函数体:由语句和表达式组成
  • return值:定义函数的返回值, return是可有可无的
def say_hello():
    '''
        作者:FQYY
        描述:定义了一个打印消息的函数
        返回值:无
        参数:无
    '''
    print("Hello World")

定义函数的时候发生的事情:

  1. 申请内存空间保存函数的代码
  2. 将上述的内存地址绑定到函数名
  3. 定义函数的时候不会执行函数体的代码,但是会检测函数体的语法

  函数的调用使用 函数名() 的方式,只有在函数调用的时候才会执行函数体代码:

def say_hello():
    '''
        作者:FQYY
        描述:定义了一个打印消息的函数
        返回值:无
        参数:无
    '''
    print("Hello World")


say_hello()  # Hello World

调用函数的时候发生的事情:

  1. 通过函数名找到函数内存地址
  2. 加括号就是在触发函数体代码的执行

  函数可以调用多次:

def say_hello():
    '''
        作者:FQYY
        描述:定义了一个打印消息的函数
        返回值:无
        参数:无
    '''
    print("Hello World")


say_hello()  # Hello World
say_hello()  # Hello World

  当函数体代码为 pass 的时候表示什么都不做,称之为空函数 。在程序设计的开始,往往是先想好程序都需要完成什么功能,然后将所有的功能都列举出来用pass充当函数体占位符。这使得程序的体系结构立见、代码清晰且可读性强。后期可以根据编程任务去选择性的实现上述功能来替换掉pass,从而提高开发的效率:

def connect():
    '''
    链接数据库
    '''
    pass

返回值

  函数并不总是用来直接显示输出的,有时候也需要处理一些数据并返回一个或者多个值:

def get_message():
    '''
        返回一个字符串
    '''
    return "Hello World"


print(get_message()) # Hello World

  当省略return语句或者return后面没有值的时候,函数的返回值是None:

def getMessage():
    return


def sayHello():
    pass


print(getMessage()) # None
print(sayHello())   # None

  函数的返回值是没有类型限制的:

# 返回字符串
def returnString():
    return "Hello World"
    
    
# 返回数字
def returnNumber():
    return 12
    
    
# 返回列表
def returnList():
    return [1, 2, 3, 4]
    
    
# 返回字典
def returnDic():
    return {"name": "张三", "age": 12}
    
    
# 返回元祖
def returnTuple():
    return (1, 2, 3)
    
    
# 或者
def returnValue():
    return 1, 2, 3

  return是一个函数结束的标志,函数内可以有多个return语句,但是只执行一次return语句就结束了:

def getMessage():
    return "Hello World"
    return "Hello Python"


print(getMessage()) # Hello World

传递参数

  在定义函数的时候可以传递参数,函数的参数分为形参和实参:

  • 形参:在定义函数的时候括号内声明的参数。形参本质就是一个变量名,用来接受外部传来的值
  • 实参:调用函数时括号内传入的值,值可以是变量、常量、表达式或者三者的组合
def say_hello(username):
    print("Hello {}".format(username))

say_hello("Jack")

  在上面的案例中,username 就是一个形参,而在调用函数的时候传入的 Jack 就是一个实参,即在调用函数的时候将 Jack 传递给了 username

注意: 在调用有参数函数时,实参(值)会赋值给形参(变量名)。在Python中,变量名与值只是单纯的绑定关系,而对于函数来说这种绑定关系只有在调用函数的时候生效,函数调用结束后就解散。

  在函数定义的时候可以包含多个形参,因此调用函数的时候也可以包含多个实参,向函数传递实参的方法很多,下面介绍的是几个常见的函数传递方法。

位置参数

  位置参数是基于参数的顺序,要求实参的顺序和形参的顺序相同:

def greet_user(username, age):
    print("My name is {}, I'm {} years old".format(username, age))


greet_user("Jack", 16)
greet_user("Tom", 18)

关键字参数

  每个实参都是由变量名和值组成,因为直接在实参中将名称和值关联起来,所以向函数传递实参的时候不会发生混淆。关键字参数让你无需考虑函数调用中的实参的顺序,还清楚地指出了函数调用中各个值的用途:

def greet_user(username, age):
    print("My name is {}, I'm {} years old".format(username, age))


greet_user(username="Jack", age=16)
greet_user(age=18, username="Tom")

  使用关键字参数的时候需要注意下面几点:

  • 使用关键字实参的时候,务必准确地指定函数定义的形参名
  • 必须保证关键字参数在位置参数后面
  • 不可以对一个形参重复赋值
def printInfo(username, age, gender):
    print("name: {}, age: {}, gender: {}".format(username, age, gender))
    
printInfo(username="Jack", age=18, sex="man")
# TypeError: printInfo() got an unexpected keyword argument 'sex'

printInfo(username="Jack", 18, gender="man")    
# SyntaxError: positional argument follows keyword argument


printInfo(username="Jack", age=18, gender="man", gender="woman")    
# SyntaxError: keyword argument repeated

默认值

  编写函数的时候可以给每个参数指定默认值,如果在调用函数的时候给这些形参指定了实参,Python将使用传递的实参值,否则将使用形参的默认值:

def greet_user(username, age=20):
    print("My name is {}, I'm {} years old".format(username, age))


greet_user(username="Jack", age=19) # My name is Jack, I'm 19 years old
greet_user(username="Tom")  # My name is Tom, I'm 20 years old

注意:有默认值的形参必须放在没有默认值的形参的后面。

可变长度的参数

  有时候预先不知道要接受多少个实参,Python允许函数从调用语句中传递任意数量的实参。

可变长度的位置参数

  如果在最后一个形参名前面加上 "*" ,那么在调用函数的时候,所有多出来的位置实参都会被该参数接收,并且会以元祖的形式保存下来( 即便只收到一个值 ,Python 也会将实参封装到一个元祖中 ):

def find_user(*user):
    print(user)


find_user("Jack")
find_user("Jack", "Tom")
# ('Jack',)
# ('Jack', 'Tom')

  如果想要让函数接受不同类型的参数,必须在函数定义中将可变长度的形参放在最后,Python会先匹配位置实惨和关键字实惨,再将余下的实参都收集到最后一个形参中:

def func_user(num1, *numbers):
    print(num1)
    print(numbers)
    
    
func_user(12,12,32,23)
# 12
# (12, 32, 23)

  也可以将一个列表传递给可变参数:

def func_user(num1, *numbers):
    print(num1)
    print(numbers)
    
    
func_user(1, *[2, 3, 4])
# 1
# (2, 3, 4)

  传入列表的时候在前面加上 "*" 的意思是将列表中的值进行解压,然后赋值给可变参数。如果这里不加就会将列表当作一个整体传递给可变参数:

def func_user(num1, *numbers):
    print(num1)
    print(numbers)
    
    
func_user(1, [2, 3, 4])
# 1
# ([2, 3, 4],)

可变长度的关键字实惨

  如果在最后一个形参名前加 "**" ,那么在调用函数时,所有多出来的关键字参数都会被该形参接收,并且会以字典的形式保存下来:

def func_user(first_name, last_name, **user_info):
    print(first_name)
    print(last_name)
    print(user_info)
    
    
func_user("Stephen", "Curry", local="American", age=32)
# Stephen
# Curry
# {'local': 'American', 'age': 32}

  也可以将字典传递给可变参数:

def func_user(first_name, last_name, **user_info):
    print(first_name)
    print(last_name)
    print(user_info)
    
    
info = {"local": "American", "age": 32}
func_user("Stephen", "Curry", **info)
# Stephen
# Curry
# {'local': 'American', 'age': 32}

  如果在传入字典的时候没有在字典前面加上 "**" ,那么该字典就是只是一个普通的位置参数了,这个时候运行程序就会报错:

def func_user(first_name, last_name, **user_info):
    print(first_name)
    print(last_name)
    print(user_info)
    
    
info = {"local": "American", "age": 32}
func_user("Stephen", "Curry", info)
# TypeError: func_user() takes 2 positional arguments but 3 were given

命名关键字参数

  在定义了可变长度的关键字参数后就可以传入任意的关键字参数,但如果函数体代码的执行就需要依赖与某个key,此时就必须在函数内进行判断:

def func_user(first_name, last_name, **user_info):
    if "gender" in user_info:
        pass

  如果想要限定函数的调用者必须以 key=value 的形式传入一些值,在Python3中可以在定义形参的时候使用一个 "*" 作为分隔符号,在这个 "*" 之后的形参称之为 命名关键字参数 。对于这类参数,在函数调用的时候必须按照 key=value 的形式为其传值,且必须得传值:

def printInfo(name, age, *, gender, salary):
    pass
    
    
printInfo('lili', 18, gender='male', salary=12) # 正确使用
printInfo('lili', 18, 'male', 12) 
# # TypeError: printInfo() takes 2 positional arguments but 4 were given
printInfo('lili', 18, gender='male') 
# TypeError: printInfo() missing 1 required keyword-only argument: 'salary'

  命名关键字参数也可以有默认值:

def printInfo(name, age, *, gender="male", salary):
    pass
    
    
printInfo('lili', 18, salary=12)

注意: 这里的形参 gender='male' 属于命名关键字参数的默认值,因而即便是放到形参 salary 之前也不会有问题。

  如果形参中已经创建了一个可变长度的参数,那么命名关键字参数就不再需要一个单独的 "*" 作为分隔符:

def printInfo(name, age, *info, gender="male", salary):
    pass
    
    
printInfo('lili', 18, 1,salary=12)

组合参数

  前面介绍的所有的参数都可以任意组合使用,但定义的顺序必须是: 位置参数、默认参数、*定义的可变参数、命名关键字参数、**定义的可变参数

def printInfo(name, age=20, *args, gender="male", **kwargs):
    print(name, age, args, gender, kwargs)
    
    
printInfo("Jack", *[1,2,3], salary=20)
# Jack 1 (2, 3) male {'salary': 20}

注意: *args、**kwargs中的args和kwargs可以被替换成其它的名称,但使用args、kwargs是约定俗成的。

列表参数

  在函数中是可以修改列表的,也就是说如果将列表传入到函数中,那么在函数中对列表的操作会影响到列表本身:

user = ["Tom", "Jack", "Clair"]
del_user = []


def func_del_user(old_user, new_user):
    while old_user:
        new_user.append(old_user.pop())


func_del_user(user, del_user)

print(user) # []
print(del_user) # ['Clair', 'Jack', 'Tom']

注意: python传递的是内存地址。

  如果不想修改原列表,可以使用下面的方法:

user = ["Tom", "Jack", "Clair"]
del_user = []


def func_del_user(old_user, new_user):
    while old_user:
        new_user.append(old_user.pop())


func_del_user(user[:], del_user)

print(user) #  ["Tom", "Jack", "Clair"]
print(del_user) # ['Clair', 'Jack', 'Tom']

函数类型提示

  在Python3.5之后,可以对函数的参数和返回值设置类型提示:

def register(name:str, age:int=18)->int:
    print(name)
    return 1

你可能感兴趣的:(14-Python基础知识学习---函数基础)