【Python函数基础到进阶分享一】函数、函数参数、变量作用域

公众号后台回复“图书“,了解更多号主新书内容

作者:老杨啊小强

来源: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购书活动
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值