python的函数定义

Python基础语法9

练习:打印99乘法表

for b in range(1,10):
    a = 1
    while a <= b:
        print('{}{}{}{}{}'.format(a,'x',b,'=',a * b),end = ' ')
#end=' ',以空格结尾
        a += 1
        if a > b:
            print('\n')
#print('') #用来换行

练习2

'''
一次测评中,老师将 学习小组A 和 学习小组B 的测评成绩(满分 100 分)从低到高记录放进两个列表:
A = [91, 95, 97, 99],B = [92, 93, 96, 98] 。
现在,老师想将两个小组的成绩合并为一个列表,并按照从低到高的顺序排序
'''
A = [91,95,97,99]
B = [92,93,96,98]
total = A + B
print(total)
for num1 in range(8):
    for num2 in range(num1 + 1,8):
        if total[num2] <= total[num1]:
            total[num1],total[num2] = total[num2],total[num1]
print(total)

#法二
list1 = [91, 95, 97, 99]  
list2 = [92, 93, 96, 98]

# 把 A 组成绩赋值给一个新列表,用来存合并的成绩——这个细节要注意!
list3 = list1.copy()
list3.extend(list2)
print(list3)

list3.sort()
print(list3)

'''
上一个练习中,我们完成了两组成绩的合并和排序。
不过,有了新的需求:想知道两组的平均分,以及把低于平均分的成绩也打印出来。
'''
sum = 0
less = []
for i in range(8):
    sum += total[i]
print(sum)
average = sum / 8
print('平均成绩是{}'.format(average))
for t in range(8):
    if total[t] <= average:
        less.append(total[t])
print('低于平均分的成绩有{}'.format(less))

# 法二
# 请你改造这个代码,用更简洁的方式满足老师的需求。
import numpy as np  # 导入 numpy库,as 即为导入的库起一个别称,别称为np
scores1 =  [91, 95, 97, 99, 92, 93, 96, 98]  
sum = 0
scores2 = []
average = np.mean(scores1) 
#for score in scores1:
    #sum = sum + score
    #average = sum/len(scores1)  
    # 上面最好不要去数有几个学生,那样的话,学生数目发生变化就要调代码。
print('平均成绩是:{}'.format(average))

for score in scores1:
    if score < average:
        scores2.append(score) # 少于平均分的成绩放到新建的空列表中
print(' 低于平均成绩的有:{}'.format(scores2))  # 上个关卡选做题的知识。

函数

编写代码要不断追求简洁和易读。换句话说,我们要尽量避免写重复的代码,少复制粘贴,也就是所谓的DRY原则——Don't Repeat Yourself。

  • 函数则是Python里增强代码重用性最有力的工具
  • 之前所写的代码都是立即运行且只能被执行一次,而函数可以让我们整合打包好代码,以便这些代码能够随时被复用,这样能极大地减少代码冗余。
  • 将一个程序用函数拆分成多个独立的子任务来完成,就会让代码结构变得清晰许多

函数的组成

Python中,“喂”给函数一些数据,它就能内部消化,执行相应的功能,最终给你“吐”出你想要的东西,就好比自动贩卖机一样。


常用函数
  • 函数后面都跟了个括号,括号里放的东西,也就是我们需要输入给函数的数据,它在函数中被称作【参数】。【参数】指向的是函数要接收、处理怎样的数据(你也可以把它理解成自变量)。
#例len()函数
a = len('万物的终极答案是42')
print(a)
b = len(['海伯利安','基地','三体'])
print(b)

定义和调用函数

  • 编写函数的第一步,我们需要去定义一个函数


    定义函数
'''以y = 3x + 5 为例子,来定义一个一次函数'''
# 函数名:1. 名字最好能体现函数的功能,一般用小写字母和单下划线、数字等组合
#      2. 不可与内置函数重名(内置函数不需要定义即可直接使用)
def math(x):
# 参数:根据函数功能,括号里可以有多个参数,也可以不带参数,命名规则与函数名相同
# 规范:括号是英文括号,后面的冒号不能丢
    y = 3*x + 5
# 函数体:函数的执行过程,体现函数功能的语句,要缩进,一般是四个空格
    return y
# return语句:后面可以接多种数据类型,如果函数不需要返回值的话,可以省略
  • 第1行:def的意思是定义(define),math是【函数名】(自己取的),再搭配一个英文括号和冒号,括号里面的x是参数(参数名也是自己取)。
  • 第2行:def下一行开始缩进的代码就是函数要实现的功能,也叫【函数体】。这里的功能就是:根据x计算出一个值y。
  • 第3行:return语句是返回的意思,可以指定函数执行完毕后最终会返回什么值或表达式,否则计算机是无法判断出函数最终要输出什么结果的。

定义函数只是将函数的内部功能封装起来,调用函数输入函数名和参数所对应的值,这个过程在函数里叫作参数的传递(pass)

def math(x):
    y =  x ** 2 + x
    return y

a = math(10)
print(a)
print(math(20))
print(math(30))
#定义len()函数
def my_len(words):
    counter = 0
    for i in words:
        counter = counter + 1
    return counter

函数的进阶使用

参数类型

位置参数、默认参数和不定长参数。

def opening():
    print('总有一种味道能温暖你~')
    print('深夜食堂正式开业啦!')
    print('欢迎来自五湖四海的你前来品尝!')

opening()
  • 上面代码定义了一个opening()函数,但是括号里没有带参数,原因是这个函数的功能是打印出固定的三句话,不需要参数的参与,需要强调的是,即便是没有参数,我们在调用函数的时候也不能省略括号,如此例中的opening()。
  • 在这个例子里,也不需要return语句,原因是这个函数直接在屏幕打印出内容,不需要返回值。事实上,没有return语句的函数,Python也会在末尾隐性地加上return None,即返回None值。

def menu(appetizer, course):
    print('一份开胃菜:' + appetizer)
    print('一份主食:' + course)

menu('话梅花生','牛肉拉面')
#如果采用下面这种形式传递,就不需要理会参数位置
menu(course = '牛肉拉面', appetizer = '话梅花生')

  • 上面代码中'话梅花生'和'牛肉拉面'是对应参数的位置顺序传递的,所以appetizer和course被叫作【位置参数】,当有多个参数的时候,我们就必须按照顺序和数量传递,这也是最常见的参数类型。

def  menu(appetizer, course, dessert = '绿豆沙'):
    print('一份开胃菜:' + appetizer)
    print('一份主食:' + course)
    print('一份甜品:' + dessert)

menu('话梅花生','牛肉拉面')
#因为已经默认将'绿豆沙'传递给dessert,调用时无须再传递。
  • 【默认参数】,直接在定义函数的时候给参数赋值。需要注意的是:默认参数必须放在位置参数之后
  • 如果一个函数的某个参数值总是固定的,那么设置默认参数就免去了每次都要传递的麻烦。不过默认参数并不意味着不能改变,试试运行下列结果。

def menu(appetizer, course, dessert = '绿豆沙'):
    print('一份开胃菜:' + appetizer)
    print('一份主食:' + course)
    print('一份甜品:' + dessert)


menu('话梅花生','牛肉拉面')
menu('话梅花生','牛肉拉面','银耳羹')
#银耳羹对应参数dessert
  • 一个萝卜一个坑,因为前两个位置参数已经有对应的值传递,Python会自动将'银耳羹'传递给参数dessert,替换了默认参数的默认值。

def menu(*barbeque):
    return barbeque

order = menu('烤鸡翅','烤茄子','烤玉米')
#括号里的这几个值都会传递给参数barbeque

print(order)
print(type(order))
  • 不限定死数量,这时候【不定长参数】就能派上用场,即传递给参数的数量是可选的、不确定的。它的格式比较特殊,是一个星号*加上参数名

  • 函数返回的是这样的结果:('烤鸡翅', '烤茄子', '烤玉米'),我们用type()函数可以知道这种数据类型叫作元组(tuple)

  • 和列表一样,元组是可迭代对象,这意味着我们可以用for循环来遍历它,这时候的代码就可以写成:

def menu(*barbeque):
    for i in barbeque:
        print('一份烤串:' + i)

menu('烤香肠', '烤肉丸')        
menu('烤鸡翅', '烤茄子', '烤玉米')
# 不定长参数可以接收任意数量的值
#print()分解
print(*objects, sep = ' ', end = '\n', file = sys.stdout, flush = False)
# sep控制多个值之间的分隔符,默认是空格
# end控制打印结果的结尾,默认是换行)

返回多个值

要返回多个值,只需将返回的值写在return语句后面,用英文逗号隔开即可。

import random 
appetizer = ['话梅花生','拍黄瓜','凉拌三丝']
def coupon(money):
    if money < 5:
        a = random.choice(appetizer)
        return a
    elif 5 <= money < 10:
        b = random.choice (appetizer)
        return b, '溏心蛋'

result = coupon(6)
# result是一个元组
print(result[0])
print(result[1])
# result是一个元组
for i in result:
    print(i)
# 我们也可以同时定义多个变量,来接收元组中的多个元素
dish, egg = coupon(7)
# 元组的两个元素分别赋值给变量dish和egg
print(dish)
print(egg)
'''
('凉拌三丝', '溏心蛋')
<class 'tuple'>
'''
  • <class 'tuple'>表示返回的数据类型又是我们刚才提到的元组。在这个例子中,该元组是由两个元素构成的,我们可以用多种方式提取

多函数间的配合

变量作用域

  • 报错代码
rent = 3000

def cost():
    utilities = int(input('请输入本月的水电费用'))
    food_cost = int(input('请输入本月的食材费用'))
    variable_cost = utilities + food_cost
    print('本月的变动成本费用是' + str(variable_cost))

def sum_cost():
    sum = rent + variable_cost
    print('本月的总成本是' + str(sum))

cost()
sum_cost()
#报错信息指出问题出在第10行,sum_cost()函数内的变量variable_cost没有被定义
  • 这里涉及一个变量作用域的问题:程序中的变量并不是在哪个位置都可以被使用的,使用权限决定于这个变量是在哪里赋值的。
    • 第一点:一个在函数内部赋值的变量仅能在该函数内部使用(局部作用域),它们被称作【局部变量】,如cost()函数里的variable_cost。
    • 第二点:在所有函数之外赋值的变量,可以在程序的任何位置使用(全局作用域),它们被称作【全局变量】,如第一行的rent。


      变量作用域
  • 上述例子中,变量rent是在函数外被赋值的,所以它是全局变量,能被sum_cost()函数直接使用。
  • 变量variable_cost是在cost()函数内定义的,属于局部变量,其余函数内部如sum_cost()无法访问。事实上,当cost()函数执行完毕,在这个函数内定义的变量都会"消失”。

  • 如何解决“局部变量”和”全局变量“之间的矛盾
    • 第一种方法最取巧:把局部变量都放在函数外,变成全局变量。
    • 函数内修改的方法,global语句可以将局部变量声明为全局变量 。
#法一
rent = 3000
utilities = int(input('请输入本月的水电费用'))
food_cost = int(input('请输入本月的食材费用'))
variable_cost = utilities + food_cost 
# 以上均为全局变量
print('本月的变动成本是' + str(variable_cost))

def sum_cost():
    sum = rent + variable_cost
    print('本月的总成本是' + str(sum))

sum_cost()
#法二
rent = 3000

def cost():
    global variable_cost
    utilities = int(input('请输入本月的水电费用'))
    food_cost = int(input('请输入本月的食材费用'))
    variable_cost = utilities + food_cost
    print('本月的变动成本是' + str(variable_cost))

def sum_cost():
    sum = rent + variable_cost
    print('本月的总成本是' + str(sum))

cost()
sum_cost()
  • global语句一般写在函数体的第一行,它会告诉Python,“我希望variable_cost是个全局变量,所以请不要用这个名字创建一个局部变量”。所以sum_cost()函数内部现在可以直接使用声明后的全局变量variable_cost。

函数的嵌套

即在一个函数内部调用其他函数

rent = 3000

def cost():
    utilities = int(input('请输入本月的水电费用'))
    food_cost = int(input('请输入本月的食材费用'))
    variable_cost = utilities + food_cost
    print('本月的变动成本是' + str(variable_cost))
    return variable_cost

def sum_cost():
    sum = rent + cost()
    print('本月的总成本是' + str(sum))

sum_cost()
  • cost()函数运行结束后会返回变量variable_cost,而sum_cost()函数内部调用了cost(),所以调用sum_cost()的时候,cost()函数也会执行,并得到返回值variable_cost。
  • sum = rent + cost() 的结果就是sum = rent + variable_cost。最后调用函数时,也只需调用sum_cost()即可。

def div(num1, num2):
    growth = (num1 - num2) / num2
    percent = str(growth * 100) + '%'
    return percent

def warning():
    print('Error: 你确定上个月一毛钱都不赚不亏吗?')

def main():
    while True:
        num1 = float(input('请输入本月所获利润'))
        num2 = float(input('请输入上月所获利润'))
        if num2 == 0:
            warning()
        else:
            print('本月的利润增长率:' + div(num1,num2))
            break

main()
  • div()函数会计算并返回利润率,warning()函数是打印出一句提示,它们都被嵌套在main()主函数里,当满足不同的条件时,这两个子函数会被调用。
  • 虽然定义了三个函数,但最后只需调用main()函数即可。


    调用过程

练习

'''
发放奖金的要求如下:

    工作时长不满六个月,发放固定奖金500元。
    工作时长在六个月和一年之间(含一年),发放奖金120元*月数(如8个月为960元)
    工作时长在一年以上,发放奖金180元*月数 (如20个月为3600元) 

我们可以定义两个函数,第一个函数功能为根据工作月数返回奖金额,第二个函数功能为打印出'该员工来了XX个月,获得奖金XXX元'。
'''
def pay(month):
    if 0 < month < 6:
        pay = 500
    elif 6 <= month <= 12:
        pay = 120 * month
    elif 12 < month:
        pay = 180 * month
    return pay

def condition():
    print('{}来了{}个月,获得奖金{}元'.format(name,month,pay(month)))

global name,month
name = input('请输入员工的姓名:')
month = int(input('请输入员工的工作时间:'))

condition()

参考代码

def bonus(month):
    if month < 6:
        money = 500
        return money
    elif 6 <= month <= 12:
        money = 120 * month
        return money
    else:
        money = 180 * month
        return money

def info(name, month):
    gain = bonus(month)
    print('%s来了%s个月,获得奖金%s元' % (name, month, gain)) 

info('大聪',14)

练习:抽奖代码

# 查看注释,运行代码。
import random
import time

# 将抽奖程序封装成函数
def choujiang(q,w,e):  # 定义一个抽奖函数,带有3个参数,也就是3位候选人
    luckylist = [q,w,e]  # 定义一个中奖名单的列表
    a = random.choice(luckylist)  # 在中奖名单里面随机选择
    print('开奖倒计时',3)
    time.sleep(1)
    print('开奖倒计时',2)
    time.sleep(1)
    print('开奖倒计时',1)
    time.sleep(1)
    image = '''
    /\_)o<
    |      \\
    | O . O|
    \_____/
    '''
    print(image)
    print('恭喜'+ a +'中奖!')
    
choujiang('虚竹','萧峰','段誉')  # 调用函数
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343