公众号后台回复“图书“,了解更多号主新书内容
作者:老杨啊小强
来源:Python数据科学修炼之路
引言:
谚语有云:“不积跬步,无以至千里;不积小流,无以成江海。”
大佬的牛逼,往往来自朴实无华的基础,越简单越实用。
菜鸟程序员,调用函数,一行一行写代码
牛皮程序员,自定义函数,一块一块写代码
大神程序员,封装类模块,一篇一篇写代码
....
今天,让我们一起,积累函数基础,从 面向过程 向 面向对象 编程出发:
1
函数
函数的概念 ●●
函数:是组织好的,可重复使用的,用来实现单一,或者相关联功能的代码段;函数能提高应用的模块性,和代码的重复使用率。
说白了,有个功能你要重复实现,多次写你嫌麻烦,就把他编写成函数,达到一次编写,多次使用的效果。
比如:你想计算数列的和,如果不用已有的sum()函数,一般你都可能都是这样:
计算1+2+3+···+1000
计算1+3+5+···+11+···
计算2+4+6+···+10+···
# 定义函数
def sum_func(lst):
s=0
for i in range(len(lst)):
s=s+lst[i]
return s
# 传递参数,调用函数
sum_func([1,2,3,4,5])
15
sum_func([10,4,6,90,100])
210
这个函数定义好了,你下次要计算某数列的和,只要调用函数,传入参数即可,不用每次写一堆。
这这是个简单的例子,Python本身有很多函数可以调用,也可以自定义函数,实现个性化需求,那如何定义一个函数呢?
自定义函数
规则:
def 函数名([参数列表]):
```注释```
函数体
1、函数代码块以 def 关键词开头,后接函数名和圆括号
def hello():
“”“该函数输出 hello”“”
print('hello world')
2、任何传入的参数和自变量必须放在圆括号当中。
3、函数体的第一行一般可用来存放对该函数的解释性信息。,严格缩进。
4、函数必须以冒号结尾
5、括号内的参数为形参,调用时候传递的参数为实参。
说明:(自定义斐波拉契数列函数)
2
函数的参数
在python中,函数的参数有很多种:普通参数或者位置参数,默认参数、可变参数、关键字参数、重命名关键字参数。下面一一说明:
普通参数
普通参数或者位置参数:
以正确的顺序传入函数。调用时的数量必需和声明时的保持一致,如果改变顺序,需要指明形参代表的正确实参。
def people(name,gender):
print("name:",name)
print("gender:",gender)
people("jack","男")#按顺序传入参数
name: jack
gender: 男
people("男","jack") #不按顺序传入,发生错位
name: 男
gender: jack
people(gender="男",name="jack") #按照参数名传入,可以不考虑参数顺序
name: jack
gender: 男
people("jack","男","US") #没有定义形参,传入实参时发生错误
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-31-afd194388421> in <module>
----> 1 people("jack","男","US")
TypeError: people() takes 2 positional arguments but 3 were given
默认参数
默认参数调用的时候,可以给他赋值可以不赋值,简化了函数调用,具有很大的灵活性。
注意:
1、默认参数只能在餐胡列表的最右端,任何一个默认参数右边不能有非默认参数。
2、默认参数必须是不变对象,如果可变可能掉坑里。
# 默认参数
def people(name,gender,city="China"):
print("name:",name)
print("gender:",gender)
print("city:",city)
#默认参数city="China",传入实参时,忽略默认参数,也会正常赋值并体现
people("jack","男")
name: jack
gender: 男
city: China
people("jack","男",city="b")#默认参数,可以改变定义时候的值,赋于新值
name: jack
gender: 男
city: b
默认参数虽好,可不要“贪杯哦”,小心掉坑里!!!
# 默认参数必须指定不可变对象
def demo(item,l=[]):
l.append(item)
return l
# 函数功能:给一个列表,末尾追加“end”,测试两次,貌似没问题
demo("end",[1,2,3])
[1, 2, 3, 'end']
demo("end002",[1,2,3])
[1, 2, 3, 'end002']
demo("end003") #咦~,和想的不一样??
['end003']
demo("end004")
['end003', 'end004'] #不应该是['end004']吗?
掉坑里了,原因是默认参数必须指定不可变对象
# 重新定义:
def demo(item,l=None):
if l is None:
l=[]
new_l=l[:]
new_l.append(item)
return new_l
#调用demo
print(demo("end",[1,2,3]))
print(demo("end002",[1,2,3]))
print(demo("end003"))
print(demo("end004"))
--------------------------------------------
out:
[1, 2, 3, 'end']
[1, 2, 3, 'end002']
['end003']
['end004']
可变参数 *args
1、可变参数就是传入的参数个数可变,可以是1个,2个,任意个,还可以是0个。
2、可变参数在参数前面加1个*,接收的是一个tuple类型。
3、可变参数可以直接传入,如func(1,2,3),这时候不加*;可以组装成list或者tuple,再通过*args传入,如:func(*(1,2,3))
例:给定a,b,c···,计算a^2+b^2+c^2+···
def csum(*number):
sum=0
for i in number:
sum=sum+i**2
return sum
csum(1,2,3,4) #返回 30
# 如果已经是一个列表或者元祖,在前面加*表示将序列解包
num=[1,2,3]
print(csum(*num)) # 返回 14
num2=(3,4,5)
print(csum(*num2)) # 返回 50
num={1:"a",2:"b",3:"c"}
print(csum(*num.keys())) # 返回 14
# print(csum(*num.values())) #字符不能运算
# 序列解包和位置参数一起使用
csum(1,*(2,3),4) # 返回 30
关键字参数 **kw
可变参数在函数调用的时候,自动组装成一个tuple;
而关键字参数在调用的时候,这些关键字在函数内部自动组装成一个dict。
关键字参数的作用是:扩展函数的功能。如果除了必填项,选填项可以用关键字参数来自动补充
#定义关键字参数**kw,“kw”可以是你喜欢的任何名字(kkww,keyword...),但是习惯于kw
def people(name,gender,**kw):
print("name:",name)
print("gender:",gender)
print("other:",kw)
people("jack","M",age=45) #age=45,返回字典{'age': 45}
----------------------------------------------------------
out:
name: jack
gender: M
other: {'age': 45}
people("jack","M",age=45,city="shanghai")
----------------------------------------------------------
out:
name: jack
gender: M
other: {'age': 45, 'city': 'shanghai'}
# 上面复杂的写法可以简化
other={'age': 45, 'city': 'shanghai'}
people("jack","M",**other)
----------------------------------------------------------
out:
name: jack
gender: M
other: {'age': 45, 'city': 'shanghai'}
命名关键字参数
命名关键字参数,以*分割,后面的是命名参数,
如果有可变参数*agers,则不需要*分割
如果没有*分割,后面的被认为是位置参数
# 命名关键字参数,以*分割,后面的是命名参数,如果有可变参数*agers,则不需要*分割
#001 一个*分割,后面的是命名参数
def people1(name,age,*,city,job): #一个*分割
print(name,age,city,job)
people1("jack",24,city="beijing",job="doctor") #调用people1,返回jack 24 beijing doctor
#002 有可变参数*arg,后的是命名参数,这时候不需要*分割
def people2(name,age,*arg,city,job): # *arg 后的是命名关键字参数
print(name,age,city,job)
people2("jack",24,city="beijing",job="doctor") #people2 返回jack 24 beijing doctor
#003 *arg 是规范写法,*arg可以命名为任意你喜欢,你开心的词
def people3(name,age,*ttt,city="beijing",job):
print(name,age,city,job)
people3("jack",24,job="doctor") #people3 返回jack 24 beijing doctor
混合使用各种参数
# 各种参数的混合使用(可以用,但是不建议)
def f1(a,b,c=0,*kk,**mm):
print("a={0},\nb={1},\nc={2},\nargs={3},\nkw={4}".format(a,b,c,kk,mm))
f1(1,2) # 调用
--------------------------------------------------------------
out:
a=1,
b=2,
c=0,
args=(),
kw={}
f1(1,2,7,"a","b",x=99,y=10) # 传入参数,调用函数
-----------------------------------------------------------
out:
a=1,
b=2,
c=7,
args=('a', 'b'),
kw={'x': 99, 'y': 10}
args=[1,2,3,4]
kw={"abc":"123","qwe":"345"}
f1(11,22,*args,**kw) # 传入参数,调用函数
-----------------------------------------------------------
out:
a=11,
b=22,
c=1,
args=(2, 3, 4),
kw={'abc': '123', 'qwe': '345'}
作业:
稍微改改下面函数,实现多数相乘
def proc(x,y):
return x*y
思路:可变参数。
3
函数变量的作用域
变量的作用域
1、变量的作用域:变量起作用的范围。
2、局部变量:在函数内部定义的普通变量只在函数内部起作用,函数结束后,局部变量自动删除。
3、全局变量:通过关键词global来定义:
a、一个变量已经在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内使用global将其声明为全局变量。
b、如果一个变量在含糊外没有设定,在函数内部也可以直接将一个变量定义为全局变量,该函数执行后,将增加一个新的全局变量。
4、除了全局变量和局部变量,Python还支持使用nonlocal关键字定义一种介于二者之间的变量。nonlocal声明的变量会引用距离最近的非全局作用域变量,要求声明的变量已经存在,关键字nonlocal不会创建形变量。
def demo():
global x #声明全局变量x
x=3
y=4
print(x,y)
demo() #调用 返回3 4
x #查看x的值,返回3,
y #查看y的值,因为y在函数内定义y=4,外部并没有定义,所以报错:y没定义。
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-9063a9f0e032> in <module>
----> 1 y
NameError: name 'y' is not defined
各变量访问的LEGB顺序:Local==>Enclosing==>Global==>Builtin
# 变量访问的LEGB顺序:Local==>Enclosing==>Global==>Builtin
x=3
def outer():
y=5
#这个自定义函数和内置函数名字相同,会在当前作用域和更内层作用域中影响内置函数map()的正常使用
def map():
return "我是一个假的map函数"
def inner():
x=7
y=9
#最内层的作用域,局部变量x,y被优先访问
#局部作用域,闭包作用域内都不存在函数max,最后的内置作用域(builtin)内搜索到max函数
#当前作用域中不存在map,但在外部的闭包作用域内搜索到,并没有调用内置函数map
print("inner:",x,y,max(x,y),map())
inner()
#在当前的作用域(闭包、enclosing)内,y可以直接访问
#当前作用域不存在x,继续到全局作用域(global)去搜索
#当前作用域中不存在max,外层全局作用域也不存在,最后再内置作用域(builtin)内搜索到max
#当前作用域中有个map,直接调用了,并没有调用内置函数map
print("outer:",x,y,max(x,y),map())
outer()
#当前作用域中有x=3,可以直接访问,但不存在y
#优于当前作用域处于全局作用域,按照python变量搜索的顺序,会继续在内置作用域搜索
#不会去搜索enclosing和local作用域,但在内置作用域也不存在y,代码引发异常
print("outside:",x,y,max(x,y))
---------------------------------------------------------------
out:
inner: 7 9 9 我是一个假的map函数
outer: 3 5 5 我是一个假的map函数
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-b76c55fb4632> in <module>
21 print("outer:",x,y,max(x,y),map())
22 outer()
---> 23 print("outside:",x,y,max(x,y))
24
NameError: name 'y' is not defined
参考文献链接:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017261630425888
https://mp.weixin.qq.com/s/GQUhcUkG8PXec53_2zQapA
THEEND
◆ ◆ ◆ ◆ ◆
当当网开学季活动来袭,满100减50的基础上,实付满200的基础上使用优惠码DYU6NM可以再减40,相当于400-240,
使用方法如下:
步骤一,挑选心仪的图书至购物车点击结算
步骤二,点击优惠券/码处
步骤三,输入优惠码DYU6NM (注意全部要大写)
需要注意的是:优惠码全场自营图书可用(教材、考试类除外)
更多详情可以扫描下方二维码或点击小程序:
点击阅读原文,即可参与当当400-240购书活动