一、函数
1.1 定义函数
1.1.1 定义
def fucntion(parameters):
[comments] #可选参数,对函数进行注释,说明用途等,相对于def要保持缩进
[functionbody] #可选参数,函数被调用后执行的部分,结果可以用return返回,返回的结果可赋给其他变量或用于计算
例如:
def i(a,b,c):
"""
求和函数
"""
i = a + b + c
return i
1.1.2 调用
function(参数值)
例如:
def i(a,b,c):
i = a + b + c
return i
#调用
i(1,2,3)
1.2.3 函数的意义
函数可以减少很多重复的代码。比如,计算Cnm时需要重复计算三次阶乘,非常麻烦:
# 求 Cnm = m!/(n!*(m-n)!)
# 求 m阶乘
num1 = 1
for i in (1,m+1):
num1 *= i
num2 = 1
for j in (1,n+1):
num2 *= j
num3 = 1
for k in (1,m-n+1):
num3 *= k
print(num1//num2//num3)
如果我们将他写成函数,直接调用函数计算就可以了:
def jc(a):
num = 1
for i in (1,a+1):
num *= i
return num
# 调用阶乘函数计算Cnm
Cnm = jc(m)//jc(n)//jc(m-n)
1.2 函数的参数
1.2.1 形式参数、实际参数
定义函数时,函数名后面的参数是形式参数,如上文的 i(a,b,c) ;
调用函数时,函数名后面的参数是实际参数,如上文的 i(1,2,3) 。
如果函数的实际参数是不可变对象,如字符串,元组,调用函数改变形式参数的值(比如def i(a): a+=a),实际参数的值不变。此时进行的是值传递,改变形式参数的值,实际参数不变;
如果函数的实际参数是可变对象,如列表,调用函数改变形式参数的值(比如def i(a): a+=a),实际参数的值会发生改变。此时进行的是引用传递,改变形式参数的值,实际参数也发生改变。
1.2.2 位置参数、关键字参数
函数在调用时,参数的位置和数量必须与定义时一致。
如:
# 定义
def bmi(name,weight,height):
pass
#调用
bmi('张三',70,1.75) # 正确
bmi(70,1.75,'张三') # 错误
除非使用关键字参数,用形式参数的名字来对应实际输入的参数值,如:
#调用
bmi(height='1.75',weight='70',name='张三')
此时可改变顺序。
1.2.3 默认参数
如果调用函数时,某个参数没有指定,会抛出异常。为了避免这个问题,我们可以在定义函数时指定一个默认值。调用函数时如果没有传入参数,可以直接使用定义函数时设置的默认值。例如:
def i(a=0,b=0,c=0)
i = a + b + c
# 调用
print(i()) # 0+0+0 #不指定实际参数时会直接使用默认值
print(i(1)) # 1+0+0
print(i(1,2)) # 1+2+0
print(i(1,2,3)) # 1+2+3
指定了默认值的形式参数,必须在所有参数的最后,否则会产生语法错误。
def bmi(height,weight,name='路人甲'): #正确
1.3 可变参数
在不确定参数个数时,我们可以使用可变参数,分为两种形式:*参数和**参数
1.3.1 *参数
*参数表示可以接收任意多个实际参数,一般有两种使用形式。
1、直接在形式参数前加*,调用函数时就可以指定任意多个实际参数。如:
def total(*i)
total = 0
for values in i:
total += i
return total
# 调用函数时,参数可以是任意个
print(total())
print(total(1))
print(total(1,2,3,4,5,6,7,8))
2、直接用已有的列表作为可变参数,只需要调用列表时在列表名前加*。
list1 = [1,2,3,4,5,6]
# 调用函数
total(*list1)
1.3.2 **参数
**参数表示可以接收任意多个类似键值对一样显式赋值的实际参数,并将其放到一个字典中。通常有两种使用形式。
1、直接在形式参数前加**,调用时就可以指定任意多个键值对:
def color(**fruit):
for key,value in fruit.items(): #遍历字典
print(key,'的颜色是',value)
# 调用函数
color(香蕉='黄色',桃子='红色')
2、直接调用字典,只需要在字典名前加**
fruit = {'香蕉':'黄色','桃子':'红色'}
# 调用字典
color(**fruit)
1.4 变量的作用域
1.4.1 局部变量、全局变量
a = 100
def bb():
b = 70
def cc(): #函数可以嵌套
c = 50
print(a) #1
print(b) #2
print(c) #3
cc()
print(a) #4
print(c) #5
if __name__ == '__main__':
print(a) #6
print(b) #7
问1-7哪个可以成功访问?
1、4、6可以成功访问,因为a是全局变量,作用域是全局,无论是函数内还是函数外,都可以访问。3可以成功访问,因为c是函数cc()的局部变量,作用域是函数cc(),函数外无法访问。2也可以成功访问,因为cc()是bb()的一个嵌套函数,所以对于bb()函数内部的cc()函数来说,b属于嵌套作用域,在嵌套函数内可以访问。
但5,7不能成功访问,因为b是局部变量,函数bb()外不能访问;c是cc()的局部变量,cc()函数外不能访问,但如果cc()有嵌套函数,嵌套函数内可以访问。
所以,全局变量是函数外的变量,可以在全局进行访问,无论是函数内还是函数外。
局部变量是函数内的变量,可在函数内访问,也可以在其嵌套函数中访问,但不能在函数外访问。
1.4.2 查找变量的顺序
Python查找变量时会按照 “局部作用域”(本函数内)、“嵌套作用域”(向上几层的嵌套函数内)、“全局作用域”(函数外)和“内置作用域”的顺序进行搜索;其中“内置作用域”就是Python内置的那些标识符,如input
、print
、int
等都属于内置作用域。
1.4.3 global 局部变全局
全局变量和局部变量重名时,无论对全部变量还是局部变量重新赋值,都不会影响另一个。
def fuc():
a =80
print(a)
a = 100
fuc()
print(a) # a=100
可以使用global函数,将函数内部的局部变量变为全局变量,这样不止可以在函数外访问到该变量,还可以在函数内对部对其值进行修改。
def fuc():
global a
a =80
print(a)
a = 100
fuc()
print(a) # a=80
因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用。因此,在实际开发中,我们应该尽量减少对全局变量的使用。
1.5 匿名函数lambda
匿名函数指没有名字的函数,应用在需要一个函数,又不想费神命名的情况下,通常这种函数只用一次。
格式:
result = lambda[r1,r2,r3...]:expression
result:用于调用lambda表达式
r1,r2,r3...:可选参数,要传递给函数的参数列表,用逗号隔开
expression:必选参数,一个实现函数目的的表达式
举例:
import math
result = lambda r:math.pi*r*r #计算圆的面积
r = 10
print(result(10))
以下引用《Python-100-days》作为结束语❤❤❤❤
说了那么多,其实结论很简单,从现在开始我们可以将Python代码按照下面的格式进行书写,这一点点的改进其实就是在我们理解了函数和作用域的基础上跨出的巨大的一步。
def main():
# Todo: Add your code here
pass
if __name__ == '__main__':
main()
1.6 练习
1.6.1 人民币汇率换算
def money():
"""
函数功能,实现人民币与日元,美元,英镑,欧元,港币的互换,unit_before和unit_after必须有一个是人民币
number:要兑换的金额
unit_before:兑换前的货币类别
unit_after: 要兑换的货币类别
return: 可兑换额
"""
unit_before = input('请输入当前持有的货币类别')
unit_after = input('请输入要兑换的货币类别')
number = float(input('请输入要兑换的金额'))
dictionary = {'人民币:美元':0.1546,
'人民币:日元':16.2935,
'人民币:英镑':0.1126,
'人民币:欧元':0.1284,
'人民币:港币':1.0803,
} # 定义一个汇率字典
if unit_before == '人民币':
key = unit_before+':'+unit_after
rate = dictionary[key]
number_after = number * rate
print('%.2f%s可兑换%.2f%s' % (number, unit_before, number_after, unit_after))
return number_after
elif unit_after == '人民币':
key = unit_after + ':' + unit_before
rate = 1/dictionary[key]
number_after = number * rate
print('%.2f%s可兑换%.2f%s' % (number, unit_before, number_after, unit_after))
return number_after
else:
print('请输入正确的货币类型,本产品只支持人民币和其他货币的兑换')
if __name__ == '__main__':
money()
1.6.2 应用lambda表达式对列表排序
"""
应用匿名函数对学术成绩进行排序,假设学术有数学语文成绩,按总成绩降序排列,总成绩相同按数学降序,数学相同按语文降序,语文相同按名字降序
"""
score = [{"name":'张三',"math":90,"chinese":84},
{"name":'李四',"math":80,"chinese":94},
{"name":'王五',"math":95,"chinese":90},
{"name":'赵六',"math":99,"chinese":72}] #学术信息
#使用sorted进行列表排序,降序
score_rank = sorted(score,key=lambda s:(s["math"]+s["chinese"],s["math"],s["chinese"],s["name"]),reverse=True)
print(score_rank)
1.6.3 实现计算求最大公约数和最小公倍数的函数。
def gcd(a, b):
"""
求两数的最大公约数
"""
list1 = [] #保存公约数
for i in range(1, min(a, b)+1):
if a % i == 0 and b % i == 0:
list1.append(i)
gcd = max(list1)
return gcd
def lcm(a, b):
"""
求两数的最小公倍数
"""
lcm = a * b // gcd(a, b)
return lcm
if __name__ == '__main__':
print(gcd(3, 5))
print(lcm(3, 5))
1.6.4 实现判断一个数是不是回文数的函数。
def is_palindromo(i):
num = i # 因为后面i会进入循环,值会改变,所以用一个变量把初始的i值保存起来
find = 0
while i > 0:
find = i % 10 + find * 10 # 把i反转过来,成为find
i = i // 10
# i=0时结束循环
return find == num # 如果反转后的值等于反转前的值,等式成立,返回True,不成立返回False
if __name__ == '__main__':
print(is_palindromo(12321))
1.6.5 实现判断一个数是不是素数的函数。
def is_prime(i):
if i == 1:
isprime = False
else:
isprime = True
for j in range(2, int(i ** 0.5) + 1): # 看有没有除了数字本身和1之外的因子
if i % j == 0:
isprime = False
break
return isprime
if __name__ == '__main__':
print(is_prime(7))
1.6.6 写一个程序判断输入的正整数是不是回文素数。
from useful import palindromo as pa # 调用刚刚定义的两个函数
from useful import prime as p
if __name__ == '__main__':
i = int(input('请输入一个值,判断它是不是回文素数'))
if pa.is_palindromo(i) and p.is_prime(i):
print('%d是回文素数' % i)
else:
print('%d不是回文素数' % i)
❤---------------------------------------------------------------------------------------------------------------------------❤
当我们将代码中重复出现的和相对独立的功能抽取成函数后,我们可以组合使用这些函数来解决更为复杂的问题,这也是我们为什么要定义和使用函数的一个非常重要的原因。
1.6.7 编写简易计算器模块
1.6.8 生成中国福利彩票
二、模块
2.1 模块类型
在Python中一个扩展名为.py的文件就被称为一个模块(module)。模块包含开发者自定义模块,Python标准库模块和第三方模块。
2.2 自定义模块
团队开发时,使用自定义模块可以避免函数重名的问题。
2.2.1 创建模块
创建模块就是将模块中的相关函数、变量保存在在一个单独文件中,并以“模块名+.py”命名。
2.2.2 导入模块
具体有两种语句:
1、import 模块名 [as 别名]
使用as可以为模块指定一个别名
当调用导入模块中的变量、函数或者类时,需要在变量、函数、类前加“模块名.”,如:
import random as r #别名
a = r.randint(1,6) #调用时,加模块名
2、from 模块名 import 函数、变量、类
可以一次性导入多个定义,也可以使用*导入所有定义。
当调用导入的变量、函数或者类时,不需要需要在变量、函数、类前加“模块名.”,如:
from random import *
a = randint(1,6) #不需要模块名
使用print(dir())可以查看具体导入的定义
print(dir())
注意,当导入的内容存在重名时,后导入的同名变量、函数和类会替换先导入的。所以,当存在重名时,必须使用import语句。导入模块时,模块名不区分大小写。
2.2.3 查看搜索目录
在使用模块时,默认按照以下顺序进行查找:
1、在当前目录下查找
2、在环境变量下的各个目录中查找
3、在Python的默认安装目录下查找
以上所有目录位置保存在sys模块下的path变量中,所以可以通过以下代码查看:
import sys
print(sys.path)
2.2.4 添加搜索目录
当模块不在以上目录中时,导入模块时就会显示ModuleNotFoundError,这时,我们可以把模块所在目录添加到path变量中,通常有三种方法:
1、使用sys.path.append()临时添加。因为是临时添加的,所以添加的目录只在当前文件窗口有效,关闭即失效。
import sys
sys.path.append('E:/program/python/code/demo') #添加
print(sys.path)
2、在Python安装目录下的Lib\site-packages子目录中,创建一个拓展名为.pth的文件,在文件中添加要导入模块的所在目录。创建后,重新打开导入了模块的文件后开始生效,这种方式添加的目录只在当前版本的Python中生效。
3、在PYTHONPATH环境变量中添加新目录,目录之间用分号;分隔。添加环境变量后重新打开导入了模块的文件目录开始生效,这种方式添加的目录在各个Python版本中都有效。
2.3 包
包(package)是一种分层次的目录结构,它将一组功能接近的模块放在同一目录下。既起到规范代码的作用,又避免了模块重名引发的问题。
可以说,模块解决了函数和变量的重名问题,包解决了模块的重名问题,如果说不同模块是不同的.py文件,包就是可以保存不同文件的文件夹。不过每个包下,都必须有一个__init__.py文件。
2.3.1 创建包
1、创建文件夹
2、在文件夹内创建一个名为“__init__.py”的文件,保存
3、创建完成。完成后可以在包中创建相应的模块。
2.3.2 从包中加载模块
使用模块时,有3种方式从包中加载模块:
假设,我们要使用set包中的size模块中的width和height变量;
1、import 包名.模块名;使用函数和变量时,包名.模块名.变量名/函数名/类名
2、from 包名 import 模块名;使用函数和变量时,模块名.变量名/函数名/类名
3、from 包名.模块名 import 变量名/函数名/类名;使用函数和变量时,变量名/函数名/类名
可以 from 包名.模块名 import * 导入所有定义;表示加载模块下不以下划线(_)开头的定义。
2.4 以主程序的形式执行
在将模块和包导入其他文件时,可能会将函数变量外的一部分执行代码一起导入了。如果我们把执行代码放在“if __name__ == '__main__':”下,这部分代码在导入其他文件时将不会执行。
# 以下内容导入其他文件时不会执行,只有在当前文件中才会执行
if __name__ == '__main__':
"""代码内容"""
所以,我们在编写代码时,要习惯在代码的执行部分上先写上“if __name__ == '__main__':”。
2.5 标准模块
Python提供200多个内置的标准模块,此处列举几个常用的,其他的不再赘述:sys、random、math、re、time、calendar。
2.6 第三方模块
2.6.1 安装
cmd,使用pip install 模块名 命令安装指定模块
2.6.2 查看
cmd,使用pip list 命令查看已安装的第三方模块,或Python使用help('module')命令,查看全部标准模块和第三方模块。
2.6.3 模块的导入顺序
当需要导入多个模块时,推荐顺序是:先导入Python标准模块,再导入第三方模块,最后导入自定义模块。