Python函数入门(08函数定义&参数&返回值)

Python基础语法文章导航:

  1. Python基础(01初识数据类型&变量)
  2. Python基础(02条件&循环语句)
  3. Python基础(03字符串格式化&运算符&进制&编码)
  4. Python基础(04 基础练习题)
  5. Python数据类型(day05整型&布尔类型&字符串类型)
  6. Python数据类型(06列表&元组)
  7. Python数据类型(07集合&字典&浮点型&None)
  8. Python文件操作01(自动化测试文件相关操作)

目录

一.函数的定义

二.函数的参数

1.参数

2. 默认参数(定义时使用)

3.动态参数(定义时使用)       

 4.函数返回值

 三. 参数内存地址相关

四. 函数的返回值的内存地址

 五.参数的默认值(面试题)

 六. 动态参数

 七.函数和函数名

1. 函数做元素

2. 函数名赋值

 3. 函数名做参数和返回值

八.返回值和print

九.作用域

1.函数作为作用域

2.全局和局部

3.global关键字

 总结:


一.函数的定义

        函数,可以当做是一大堆功能代码的集合。

def 函数名():
    函数内编写代码
    ...
    ...
    
函数名()

        什么时候用到函数:

                有重复代码,用函数增加代码的重用性。

def send_email():
    # 10行代码

print("欢迎使用计算机监控系统")
if CPU占用率 > 90%:
    send_email()

if 硬盘使用率 > 99%:
    send_email()
    
if 内存使用率 > 98%:
    send_email()
...

                代码太长,用函数增强代码的可读性。

def calculate_same_num_rule():
    """判断是否是豹子"""
    pass

def calculate_same_color_rule():
    """判断是否是同花"""
    pass

def calculate_straight_rule():
    """判断是否顺子"""
	pass

def calculate_double_card_rule(poke_list):
    """判断是否对子"""
	pass

def calculate_single_card_rule():
    """判断是否单牌"""
    pass



# 1. 生成一副扑克牌
card_color_list = ["红桃", "黑桃", "方片", "梅花"]
card_nums = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]  # A
all_card_list = [[color, num] for color in card_color_list for num in card_nums]

# 2.洗牌
random.shuffle(all_card_list)

# 3.给玩家发牌
...
# 4.判断牌是:豹子?同花顺?顺子?对子?单点?

calculate_same_num_rule()
calculate_same_color_rule()
calculate_straight_rule()
...

二.函数的参数

使用python发邮件,然后再由此引出函数的参数。

  • 注册邮箱

  • 基础配置

    • 授权码

    • SMTP服务器: smtp.126.com

  • 代码发送邮件

        基于函数的参数(将代码中动态部分提取到参数位置,让函数可以充分被重用)。以后邮件发送的代码可参考这块,理解即可。

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

def send_email(email):
    # ### 1.邮件内容配置 ###
    # 邮件文本
    msg = MIMEText("认真工作了吗", 'html', 'utf-8')
    # 邮件上显示的发件人
    msg['From'] = formataddr(["匿名上班人", "wptawy@126.com"])
    # 邮件上显示的主题
    msg['Subject'] = "邮件主题"

    # ### 2.发送邮件 ###
    server = smtplib.SMTP_SSL("smtp.126.com")
    server.login("wptawy@126.com", "WIYSAILOVUKPQGHY")
    server.sendmail("wptawy@126.com", email, msg.as_string())
    server.quit()

v1 = "424662508@qq.com"
send_email(v1)
v2 = "424662509@qq.com"
send_email(v2)
v3 = "wupeiqi@live.com"
send_email(v3)

1.参数

        形式参数

        在定义函数时,如果在括号中添加变量,我们称它为函数的形式参数:

# ###### 定义有三个参数的函数(a1/a2/a3一般称为形式参数-形参) #####
def func(a1,a2,a3):
    print(a1+a2+a3)

# 执行函数并传入参数(执行函数传值时一般称为实际参数-实参)
func(11,22,33)

        位置传参

def add(n1,n2):
    print(n1+n2)
    
add(1,22)

        关键字传参

def add(n1,n2):
    print(n1+n2)
    
add(n1=1,n2=22)

2. 默认参数(定义时使用)

def func(a1, a2, a3=10):
    print(a1 + a2 + a3)


# 位置传参
func(8, 19)
func(1, 2, 99)

# 关键字传参(位置和关键混合时,关键字传参要在后面)
func(12, 9, a3=90)
func(12, a2=9, a3=90)
func(a1=12, a2=9, a3=90)

3.动态参数(定义时使用)       

 (1)*

def func(*args):
    print(args) # 元组类型 (22,)   (22, 33)  (22,33,99,)   ()

# 只能按照位置传参
func(22)
func(22,33)
func(22,33,99)
func()

(2)**

def func(**kwargs):
    print(kwargs)  # 字典类型 {"n1":"武沛齐"}  {'n1': '武沛齐', 'age': 18}  {"n1":"武沛齐","age":"18","email":"xxxx"}   {}

# 只能按关键字传参
func(n1="武沛齐")
func(n1="武沛齐", age=18)
func(n1="武沛齐", age=18, email="xx@live.com")
func()

(3)*,**

        执行函数,并传入参数的时候:元组形式是*的实参,字典形式是**的实参

def func(*args,**kwargs):
    print(args,kwargs) 
func(22,33,99)
func(n1="武沛齐",age=18)
func(22,33,99,n1="武沛齐",age=18)
func()

#(22, 33, 99) {}
# () {'n1': '武沛齐', 'age': 18}
# (22, 33, 99) {'n1': '武沛齐', 'age': 18}
# () {}

        字符串格式化时的format功能,就用到位置传参和关键字传参的形式

v1="我叫{},今年{},性别{}".format("晓鹏",26,"女")
print(v1)
v2="我叫{name},今年{age},性别{sex}".format(name="晓鹏",age=26,sex="女")
print(v2)

        注意事项

# 1. ** 必须放在 * 的后面
def func1(*args, **kwargs):
    print(args, **kwargs)

# 2. 参数和动态参数混合时,动态参数只能放在最后。
def func2(a1, a2, a3, *args, **kwargs):
    print(a1, a2, a3, args, **kwargs)

# 3. 默认值参数和动态参数同时存在
def func3(a1, a2, a3, a4=10, *args, a5=20, **kwargs):
    print(a1, a2, a3, a4, a5, args, kwargs)  #11 22 33 44 20 (55, 66, 77) {'a10': 123}
func3(11, 22, 33, 44, 55, 66, 77, a5=10, a10=123)  #a4有位置传参,覆盖原来的默认值参数

 4.函数返回值

(1)返回值可以是任意类型,如果函数中没写return,则默认返回None

def func():
    value = 1 + 1
    
ret = func()
print(ret) # None
def func():
    return [1,True,(11,22,33)]

result = func()
print(result)

         当在函数中写 returnreturn None ,执行函数获取的返回值都是None。

def func():
    value = 1 + 1
    # return  # 或
    return None

ret = func()
print(ret) # None

(2)return后面的值如果有逗号,则默认会将返回值转换成元组再返回。

def func():
    return 1,2,3

value = func()
print(value) # (1,2,3)

(3)函数一旦遇到return就会立即退出函数(终止函数中的所有代码)

def func():
    print(1)
    return "结束吧"
    print(2)
ret = func()
print(ret)

#1
#结束吧
def func():
    print(1)
    for i in range(10):
        print(i)
        for j in range(100):
            print(j)
	        return
	print(2)
    
result = func()
print(result)

# 输出
1
0
0
None

 三. 参数内存地址相关

        如果想要查看下某个值的在内存中的地址?

v1 = "武沛齐"
addr = id(v1)
print(addr) # 140691049514160

        记住一句话:函数执行传参时,传递的是内存地址。

def func(data):
    print(data, id(data))  # 武沛齐  140247057684592

v1 = "武沛齐"
print(id(v1))  # 140247057684592
func(v1)

四. 函数的返回值的内存地址

def func():
    data = [11, 22, 33]
    return data

v1 = func()
print(v1) # [11,22,33]

上述代码的执行过程:

  • 执行func函数

  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址。

  • return data 返回data指向的内存地址

  • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)

  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v1指向的函数内部创建的那块内存地址。

 五.参数的默认值(面试题)

        原理:Python在创建函数(未执行)时,如果发现函数的参数中有默认值,则在函数内部会创建一块区域并维护这个默认值。

def func(a1,a2=18):
    print(a1,a2)

#执行函数未传值时,则让a2指向 函数维护的那个值的地址。
func("root")   #root 18

#执行函数传值时,则让a2指向新传入的值的地址。
func("admin",20)   #admin 20

        在特定情况【默认参数的值是可变类型 list/dict/set】 & 【函数内部会修改这个值】下,参数的默认值 有坑 。坑的点:如果发现函数的参数中有默认值,则在函数内部会创建一块区域并维护这个默认值。如果执行函数的实参(按照位置传参,对应函数的参数中也有默认值),则优先按照实参新创建一块区域 维护新的默认值,然后去进行执行函数。

# 在函数内存中会维护一块区域存储 [1,2,666,666,666] 100010001
def func(a1,a2=[1,2]):
    a2.append(666)
    print(a1,a2)

# a1=100
# a2 -> 100010001
func(100) # 100  [1,2,666]

# a1=200
# a2 -> 100010001
func(200) # 200 [1,2,666,666]

# a1=99
# a2 -> 1111111101
func(99,[77,88]) # 99 [77,88,666]

# a1=300
# a2 -> 100010001
func(300) # 300 [1,2,666,666,666]

 大坑:就是操作之后立马进行输出,输出的话输出的是内存地址对应的值。

# 在内部会维护一块区域存储 [1, 2, 10, 20,40 ] ,内存地址 1010101010
def func(a1, a2=[1, 2]):
    a2.append(a1)
    return a2

# a1=10
# a2 -> 1010101010
# v1 -> 1010101010
v1 = func(10)
print(v1) # [1, 2, 10]

# a1=20
# a2 -> 1010101010
# v2 -> 1010101010
v2 = func(20)
print(v2) # [1, 2, 10, 20 ]

# a1=30
# a2 -> 11111111111        [11, 22,30]
# v3 -> 11111111111
v3 = func(30, [11, 22])
print(v3) #  [11, 22,30]

# a1=40
# a2 -> 1010101010
# v4 -> 1010101010
v4 = func(40)
print(v4) # [1, 2, 10, 20,40 ] 

 深坑:完成所有操作之后进行输出,输出的话输出的是内存地址对应的值。

# 内存中创建空间存储 [1, 2, 10, 20, 40] 地址:1010101010
def func(a1, a2=[1, 2]):
    a2.append(a1)
    return a2

# a1=10
# a2 -> 1010101010
# v1 -> 1010101010
v1 = func(10)


# a1=20
# a2 -> 1010101010
# v2 -> 1010101010
v2 = func(20)

# a1=30
# a2 -> 11111111111   [11,22,30]
# v3 -> 11111111111
v3 = func(30, [11, 22])

# a1=40
# a2 -> 1010101010
# v4 -> 1010101010
v4 = func(40)

print(v1) # [1, 2, 10, 20, 40]
print(v2) # [1, 2, 10, 20, 40]
print(v3) # [11,22,30]
print(v4) # [1, 2, 10, 20, 40] 

 六. 动态参数

        在定义函数时可以用***,其实在执行函数时,也可以用

(1)形参固定,实参用*和**

def func(a1,a2):
    print(a1,a2)
 
func( 11, 22 )
func( a1=1, a2=2 )

func( *[11,22] )
func( **{"a1":11,"a2":22} )
#11 22
# 1 2
# 11 22
# 11 22

(2)形参用***,实参也用***

def func(*args,**kwargs):
    print(args,kwargs)
    
func( 11, 22 )
func( 11, 22, name="武沛齐", age=18 )

# 小坑,([11,22,33], {"k1":1,"k2":2}), {}
func( [11,22,33], {"k1":1,"k2":2} )

# args=(11,22,33),kwargs={"k1":1,"k2":2}
func( *[11,22,33], **{"k1":1,"k2":2} ) 

# 值得注意:按照这个方式将数据传递给args和kwargs时,数据是会重新拷贝一份的(可理解为内部循环每个元素并设置到args和kwargs中)。

# (11, 22) {}
# (11, 22) {'name': '武沛齐', 'age': 18}
# ([11, 22, 33], {'k1': 1, 'k2': 2}) {}
# (11, 22, 33) {'k1': 1, 'k2': 2}

 (3)使用format字符串格式化时,可以这样:

v1 = "我是{},年龄:{}。".format("武沛齐",18)
v2 = "我是{name},年龄:{age}。".format(name="武沛齐",age=18)

v3 = "我是{},年龄:{}。".format(*["武沛齐",18])
v4 = "我是{name},年龄:{age}。".format(**{"name":"武沛齐","age":18})

 七.函数和函数名

        函数名其实就是一个变量,这个变量只不过代指的函数而已。

        注意:函数必须先定义才能被调用执行(解释型语言)。

# 正确
def add(n1,n2):
    return n1 + n2

ret = add(1,2)
print(ret) 

1. 函数做元素

        既然函数就相当于是一个变量,那么在列表等元素中可以把函数当做元素。注意:函数同时也可被哈希,所以函数名通知也可以当做 集合的元素、字典的键。

def func():
    return 123

data_list = ["武沛齐", "func", func , func() ]

print( data_list[0] ) # 字符串"武沛齐"
print( data_list[1] ) # 字符串 "func"
print( data_list[2] ) # 函数 func
print( data_list[3] ) # 整数 123

res = data_list[2]()
print( res ) # 执行函数 func,并获取返回值;print再输出返回值。

print( data_list[2]() ) # 123

情景1,例如:要开发一个类似于微信的功能:

def send_message():
    """发送消息"""
    pass

def send_image():
    """发送图片"""
    pass

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片")
choice = input("输入选择的序号")

if choice == "1":
    send_message()
elif choice == "2":
    send_image()
else:
    print("输入错误")

        改成字典的形式:

def send_message():
    """发送消息"""
    pass

def send_image():
    """发送图片"""
    pass

function_dict = {
    "1": send_message,
    "2": send_image
}

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片")
choice = input("输入选择的序号") # "1"

func = function_dict.get(choice)
if not func:
    print("输入错误")
else:
    # 执行函数
    func()

情景2,例如:某个特定情况,要实现发送短信、微信、邮件。

def send_msg():
    """发送短信"""
    pass

def send_email():
    """发送图片"""
    pass

def send_wechat():
    """发送微信"""
    
# 执行函数
send_msg()
send_email()
send_wechat()
def send_msg():
    """发送短信"""
    pass

def send_email():
    """发送图片"""
    pass

def send_wechat():
    """发送微信"""
    pass
    
    
func_list = [ send_msg, send_email, send_wechat ]
for item in func_list:
    item()

        上述两种情景,在参数相同时才可用,如果参数不一致,会出错。所以,在项目设计时就要让程序满足这一点,如果无法满足,也可以通过其他手段时间,例如:

情景3:

def send_message(phone,content):
    """发送消息"""
    pass


def send_image(img_path, content):
    """发送图片"""
    pass


def send_emoji(emoji):
    """发送表情"""
    pass


def send_file(path):
    """发送文件"""
    pass


function_dict = {
    "1": [ send_message,  ['15131255089', '你好呀']],
    "2": [ send_image,  ['xxx/xxx/xx.png', '消息内容']],
    "3": [ send_emoji, ["😁"]],
    "4": [ send_file, ['xx.zip'] ]
}

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片;3.发送表情;4.发送文件")
choice = input("输入选择的序号") # 1

item = function_dict.get(choice) # [ send_message,  ['15131255089', '你好呀']],
if not item:
    print("输入错误")
else:
    # 执行函数
    func = item[0] # send_message
    param_list = item[1] #  ['15131255089', '你好呀']
    
    func(*param_list) # send_message(*['15131255089', '你好呀'])

情景4:

def send_msg(mobile, content):
    """发送短信"""
    pass


def send_email(to_email, subject, content):
    """发送图片"""
    pass


def send_wechat(user_id, content):
    """发送微信"""
    pass


func_list = [
    {"name": send_msg, "params": {'mobile': "15131255089", "content": "你有新短消息"}},
    {"name": send_email, "params": {'to_email': "wupeiqi@live.com", "subject": "报警消息", "content": "硬盘容量不够用了"}},
    {"name": send_wechat, "params": {'user_id': 1, 'content': "约吗"}},
]

#  {"name": send_msg, "params": {'mobile': "15131255089", "content": "你有新短消息"}},
for item in func_list:
    func = item['name'] # send_msg
    param_dict = item['params'] # {'mobile': "15131255089", "content": "你有新短消息"}
    func(**param_dict) # send_msg(**{'mobile': "15131255089", "content": "你有新短消息"})

2. 函数名赋值

        将函数名赋值给其他变量,函数名其实就个变量,代指某函数;如果将函数名赋值给另外一个变量,则此变量也会代指该函数,例如:

def func(a1,a2):
    print(a1,a2)

xxxxx = func

# 此时,xxxxx和func都代指上面的那个函数,所以都可以被执行。
func(1,1)
xxxxx(2,2)

        对函数名重新赋值,如果将函数名修改为其他值,函数名便不再代指函数,例如

def func(a1,a2):
    print(a1,a2)

# 执行func函数
func(11,22)

# func重新赋值成一个字符串
func = "武沛齐"

print(func)

         注意:由于函数名被重新定义之后,就会变量新被定义的值,所以大家在自定义函数时,不要与python内置的函数同名,否则会覆盖内置函数的功能,例如:

# len内置函数用于计算值得长度
v1 = len("武沛齐")
print(v1) # 3

# len重新定义成另外一个函数
def len(a1,a2):
    return a1 + a2

# 以后执行len函数,只能按照重新定义的来使用
v3 = len(1,2)
print(v3)

 3. 函数名做参数和返回值

         函数名其实就一个变量,代指某个函数,所以,他和其他的数据类型一样,也可以当做函数的参数和返回值。

        参数

def plus(num):
    return num + 100

def handler(func):
    res = func(10) # 110
    msg = "执行func,并获取到的结果为:{}".format(res)
    print(msg) # 执行func,并获取到的结果为:110
   
# 执行handler函数,将plus作为参数传递给handler的形式参数func
handler(plus)

         返回值

def plus(num):
    return num + 100

def handler():
	print("执行handler函数")
    return plus
    
result = handler()
data = result(20) # 120
print(data)

八.返回值和print

这两个函数是完全不同的

  • 在函数中使用print,只是用于在某个位置输出内容而已。

  • 在函数中使用return,是为了将函数的执行结果返回给调用者,以便于后续其他操作。

def f1():
    print(123)

def f2(arg):
    ret = arg()
    return f1

v1 = f2(f1)
v2 = v1()
print(v2)

# 输出
123
123
None

九.作用域

        作用域,可以理解为一块空间,这块空间的数据是可以共享的。通俗点来说,作用域就类似于一个房子,房子中的东西归里面的所有人共享,其他房子的人无法获取。

1.函数作为作用域

        Python以函数为作用域,所以在函数内创建的所有数据,可以此函数中被使用,无法在其他函数中被使用。

def func():
    name = "武沛齐"
    data_list = [11,22,33,44]
    print(name,data_list)
    age = 20
    print(age)

def handler():
    age = 18
    print(age)

func()
handler()

2.全局和局部

        Python中以函数为作用域,函数的作用域其实是一个局部作用域。

# 全局变量(变量名大写)
COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    # 局部变量
    url = "http://www.xxx.com"
    ...
    
def upload():
    file_name = "rose.zip"
    ...

    COUNTRYCITY_LIST是在全局作用域中,全局作用域中创建的变量称之为【全局变量】可以在全局作用域中被使用,也可以在其局部作用域中被使用。

   downloadupload函数内部维护的就是一个局部作用域,在各自函数内部创建变量称之为【局部变量】,且局部变量只能在此作用域中被使用。局部作用域中想使用某个变量时,寻找的顺序为:优先在局部作用域中寻找,如果没有则去上级作用域中寻找

注意:全局变量一般都是大写。

示例1:在局部作用域中读取全局作用域的变量。

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    print(url)
    print(COUNTRY)
    print(CITY_LIST)
    
def upload():
    file_name = "rose.zip"
    print(file_name)
    print(COUNTRY)
    print(CITY_LIST)
    
print(COUNTRY)  #全局变量 对
print(CITY_LIST) #全局变量 对
download()  #全局变量 对
upload() #全局变量 对

print(file_name) # 报错  file_name是upload()的局部变量
print(url) # 报错   url是download()的局部变量

示例2:局部作用域和全局作用域变量同名,优先读局部变量作用域里面变量的值。

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    CITY_LIST = ["河北","河南","山西"]
    print(url)
    print(COUNTRY)
    print(CITY_LIST)
    
def upload():
    file_name = "rose.zip"
    print(COUNTRY)
    print(CITY_LIST)
    
print(COUNTRY)
print(CITY_LIST)
download()
upload()

COUNTRY = "中华人民共和共国"
CITY_LIST = [11,22,33]

download()
upload()

# 输出
中国
["北京","上海","深圳"]
http://www.xxx.com
中国
["河北","河南","山西"]
中国
 ["北京","上海","深圳"]
http://www.xxx.com
中华人民共和共国
["河北","河南","山西"]
中华人民共和共国
[11,22,33]

3.global关键字

         默认情况下,在局部作用域对全局变量只能进行:读取和修改内部元素(可变类型),无法对全局变量进行重新赋值。

        读取

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    print(COUNTRY)
    print(CITY_LIST)
    
download()

         修改内部元素(可变类型)

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    print(CITY_LIST)
    
    CITY_LIST.append("广州")
    CITY_LIST[0] = "南京"
    print(CITY_LIST)
    
download()

# ['北京', '上海', '深圳']
# ['南京', '上海', '深圳', '广州']

         无法对全局变量重新赋值

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
    # 不是对全部变量赋值,而是在局部作用域中又创建了一个局部变量 CITY_LIST 。
    CITY_LIST =  ["河北","河南","山西"]
    print(CITY_LIST)

def upload():
    file_name = "rose.zip"
    print(COUNTRY)
    print(CITY_LIST)
    
download()
upload()

         如果想要在局部作用域中对全局变量重新赋值,则可以基于 global关键字实现,例如:

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
	
    global CITY_LIST
    CITY_LIST =  ["河北","河南","山西"]
    print(CITY_LIST)
    
    global COUNTRY
    COUNTRY = "中华人民共和国"
    print(COUNTRY)

def upload():
    file_name = "rose.zip"
    print(COUNTRY)
    print(CITY_LIST)
    
download()
upload()

#['河北', '河南', '山西']
#中华人民共和国
#中华人民共和国
#['河北', '河南', '山西']

 总结:

         以上为函数的一些基础知识,需进行熟练掌握,方便后续更深一层次对函数的学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值