Python中的函数

python中的函数与js中函数功能一样封装共用逻辑,增加代码可复用性,但是复杂性远远高于JavaScript,在本篇文章中我将分六大方面来跟大家聊下函数:

  1. 定义函数
  2. 函数返回值
  3. 空函数
  4. 函数参数的类型检查
  5. 多值返回
  6. 函数参数

         函数参数又分3个部分:

            (1)默认值参数

            (2)可变参数

            (3)收集关键字参数

 

 

1、定义函数及返回值:

在Python中定义一个函数,要使用def语句(在js用function),依次写入函数名、括号、括号中的参数和冒号,函数返回值用return语句返回:

def fn_name (param):
    print(param)
fn_name('lxc') # 函数调用

上边代码,如果没有返回值 则不需要用return。

下边代码,是有返回值,我们把返回值存到一个变量里,接着打印出来。

def fn_name (param):
    return param
name = fn_name('lxc') # 函数调用
print(name)

注意点:

1、return语句的意思是终止语句返回结果

2、如果没有return语句,函数执行完毕,返回的是None(在js中,默认返回的是undefined);

3、执行return之后,后边语句将不会执行!!!

 

3、空函数

定义一个空函数一般是暂时没想好怎么写逻辑代码,占位用的:

def fn_name ():
    pass

上边代码,代码块先用pass站位,程序也会运行,如果代码块为空,会报错!

pass还可以用在if条件语句中:

if True:
    pass

 

4、参数类型检查   isinstance( )

在Python中,可用内置函数 isinstance( ),判断变量是否是某个数据类型的实例。

def name_fn (param):
    if isinstance(param,(int)):
        print("您输入的参数%s类型正确" % (param)) # 您输入的参数10类型正确
    else:
        raise TypeError('param is bad!')
name_fn(10)

python中的类型检查isinstance()类似于js中的instanceof(),只不过是写法不一样

var arr = [];
console.log(arr instanceof Array) // true

这里要说明下,python中,函数中传入一个错误的参数类型,如果不做类型校验也不会报错,在开发中添加参数类型校验如果传入错误类型,函数就可以抛出错误,会更加利于排错!关于错误和异常处理我在后边文章中将详细聊。

5、返回多值

函数也可以返回多个值,但是返回的类型是元祖tuple

def name_fn (param,param1,param2):
    return param,param1,param2
print(name_fn(1,2,3)) # (1,2,3)
print(type(name_fn(1,2,3))) # <class 'tuple'>

注意点:

1、函数返回多个值,类型是tuple

2、返回一个值时,值是什么类型就是什么类型

补充:

下边我们来看下,多值返回一个元组,如何来用呢?如何取值呢?

def fn(x,y):
    return x,y
result = fn(1,2)
print(result[0]) # 1
print(result[1]) # 2

上边代码,许多人会这样取值,时间久了,你会忘记result[0]到底是什么值;

def fn(x,y):
    return x,y
result_one,result_two = fn(1,2)
print(result_one) # 1
print(result_two) # 2

上边代码,写法是不是更明了了,在python中叫做序列解包(类似于ES6中的结构赋值)。

下边我们来看下序列解包:

a,b,c = 1,2,3
print(a,b,c) # 1 2 3

也可以这样写:

param = 1,2,3
print(param) # (1,2,3)
print(type(param)) # <class 'tuple'>
a,b,c = param
print(a,b,c) # 1 2 3

上边代码,param = 1,2,3   会返回一个元组,在python中叫做序列封包

下边代码,如果右边变量数量与左侧不符,将会报错!!!

param = 1,2,3
a,b = param
print(a,b) #报错 ValueError: too many values to unpack (expected 2)

********6、函数参数********

下边我们主要说下默认值参数、动态参数

(1)默认值参数:

了解过ES6小伙伴都知道默认值参数,在python中默认值参数与 js中 的类似,当没传参数时,函数内将会使用默认值参数:

def default_param (param = 1):
    print(param)
default_param() # 1

上边代码,调用函数时未传递参数,输出的是默认值参数

(2)当默认值参数为可变类型时,应注意:

def default_param (list = []):
    list.append(1)
    print(list)
default_param() # [1]
default_param() # [1,1]
default_param() # [1,1,1]

上边代码,默认值参数是一个空列表list,第一次还是正常,当第二、三次在调用时,list已经不是空列表,这是因为列表list是可变的,每次调用函数,list都会被改变!!!

解决办法:把默认值换成不可改变的类型即可(如:数字int、字符串str、元组tuple),如果默认值非要定义一个空列表,可以这样写:

def default_param (list = None):
    if list == None:
        list = []
        print(list)
    else:
        print(list)
default_param() # []
default_param() # []

上边代码,None是一个不可变对象,当调用函数时,如果未传参数,list将会是None空值类型,在函数内部,我们让列表list指向一个空列表,无论调用多少次,都是空列表[ ]。

 

***可变参数***:

先来回顾下ES6中处理可变参数(不定参数),是用扩展运算符(...variable),而python中处理不定参数与js有很大不同,使用 *号

def default_param (*params):
    print(type(params)) # params 类型是一个元组 <class 'tuple'>
    for i in params:
        print(i,end='--') # [1, 2]--1--lxc--(1, 2)--
default_param([1,2],1,"lxc",(1,2))

上边代码,在调用函数时,我们传入了列表[1,2]、数字1、字符串'lxc'、元组(1,2) params类型是一个元组,上边我们讲过函数返回多个值时,也会返回一个元组;我们用for循环依次把参数输出出来!!!( 最后end意思是以什么方式连接参数,默认以\n换行来输出结果的, 可以类比js中的数组join方法,此方法默认是以逗号形式把数组转化为字符串)

补充:

可变参数可以放在形参中的任何位置,但是如果形参中有位置参数,则必须使用默认值参数,或者是实参中定义关键字参数,否则会报错:

def fn(*a,b):
    print(a)
    print(b)

fn(1,2,3,4) TypeError: fn() missing 1 required keyword-only argument: 'b'
#在是实参中定义关键字参数
def fn(*a,b):
    print(a) #(1, 2, 2)
    print(b) #3
fn(1,2,2,b=3)
#也可以在形参中定义默认值参数
def fn(*a,b=4):
    print(a) #(1, 2, 2, 3)
    print(b) #4
fn(1,2,2,3)

不在函数中使用可变参数:

*a,b = range(10)
print(a) #[0, 1, 2, 3, 4, 5, 6, 7, 8]
print(b) # 9

 

 

***收集关键字参数***:

1、收集关键字参数与可变参数类似,把余下的赋值语句(必须是赋值语句才行)统一放入一个字典当中,有两个 星号* ,而可变参数是把剩余的参数统一放入一个元组中。

用代码说下:

def default_param (name,age,**keyword):
    print(name) # 'lxc'
    print(age) # 20
    print(keyword) #{'height':'170','say':'hehe'}
default_param('lxc',20,height="170",say="hehe")

上边代码,前两个参数name和age正常传入,接下来剩下的两个参数是赋值语句 height="170" 和 say="hehe",我的理解是,解释器会做两件事 :

                  (1)把余下的赋值语句统一放入一个字典中,等号两边分别对应key-valuie;

                  (2)把由赋值语句组成的字典,赋值给 有两个星号后边的参数(上边是keyword),所以我们输出keyword就是由赋值语句组成的字典

可以结合上边可变参数,来理解收集关键字参数!!!

(3)形参中的默认值参数必须要放到普通参数的后边:

def fn (a,b = 1):
    print(a) # 1
    print(b) # 2
fn(1,2)

下边写法报错,因为没有把默认值参数放到最后:

def fn (a,b = 1,c):
    pass
fn(1,2,3)

下边代码,前两个参数是必须传递的位置参数,其他参数如果不传会使用默认参数,当然也可以在实参中指定修改哪一个默认参数。。。

def fn (name,age,grade='高三四班',school='莱阳一中',):
    print('%s,年龄:%d,%s,在读学校:%s' % (name,age,grade,school))
fn('吕星辰',20)  # 吕星辰,年龄:20,高三四班,在读学校:莱阳一中
fn('鸡小西',21) # 鸡小西,年龄:21,高三四班,在读学校:莱阳一中
fn('牛二',18,school='烟台一中') # 牛二,年龄:18,高三四班,在读学校:烟台一中

***可变参数和关键字参数作为实参***

如果你明白了可变参数收集关键字参数,那么接下你会有更深刻的理解,当他们作为实参来用的时候,也就是逆向参数

逆向参数收集需要在传入的列表 或元祖之前加上星号*,在字典参数之前添加两个星号。

来看一段代码:

dict = {'name':'lxc','age':20}
def default_param (name,age):
    print(name) # 'lxc'
    print(age) # 20
default_param(**dict)

上边参数,收集关键字参数作为实参来用,可以直接输出字典中key所对应的的value值(需注意:形参中的参数需要与字典中的key统一!!!) 

dict = {'name':'lxc','age':20}
def default_param (**dict_alias):
    print(dict_alias) # {'name':'lxc','age':20}
default_param(**dict)

上边代码,可对外边dict字典,实现深层拷贝,如果修改里边字典dict_alias中的数值,不会影响到外边dict!!!

再看下可变参数:

tuple = (1,2,3)
def defult_param (a,b,c):
    print(a)
    print(b)
    print(c)
defult_param(*tuple)

上边参数,可变参数作为实参来用,形参只需要与元组中的参数数量一致即可!!!

补充:

1、为函数提供文档:

我们还可以为函数编写说明文档,把一段字符串放在函数声明之后,函数体之前,那么这段字符串将会被当做函数的一部分。

可以通过 help( )函数 查看说明文档,也可以用过函数的 _ _ doc _ _属性 访问函数的说明文档:

def fn():
    '''
    这个fn是一个演示函数,没有意义
    :return:
    '''
    pass
fn()
help(fn)
#输出:
# Help on function fn in module __main__:
# 
# fn()
#     这个fn是一个演示函数,没有意义
#     :return:

#输出
print(fn.__doc__)
# 这个fn是一个演示函数,没有意义
# :return:

 

2、函数的参数传递机制:

在python中,函数参数传递机制都是 “值传递” 。所为值传递就是将实际参数值的副本(复制品)传入函数,而值本身不会收到影响。(可理解为js中的原始值)

def fn(a,b):
    a,b = b,a
    print(a) # 2
    print(b) # 1
a = 1
b = 2
fn(a,b)
print(a) # 1  
print(b) # 2

继续往下看,当值类型是引用值时的情况:

def fn(d):
    d['a'],d['b'] = d['b'],d['a']
    print(d) # {'a': 2, 'b': 1}
d = {'a':1,'b':2}
fn(d)
print(d) # {'a': 2, 'b': 1}

上边代码,在函数内部修改了字典中的值,结果外边字典里边也跟着改变了!

其实,d变量作为参数传入到fn函数,同样采用值传递方式,但是d变量只是一个引用变量(也就是一个指针),它保存了字典对象的地址,当把d变量赋值给fn参数后,也就是让fn参数也保存这个地址(指向这个地址),通俗点说,d变量和函数参数的d变量(副本)同时指向了同一个地址,系统复制的是d变量,并不是赋值字典本身。所以字典本身发生改变,两个变量也跟着改变了。(与js中的引用值一样)

还要着重强调下,上边代码中,外边d变量和fn函数里边的d变量是两个变量,只不过同时指向了一个地址而已,下边代码,我们把函数里边的d变量重新赋值,看下结果:

def fn(d):
    d = None
    print(d) # None
d = {'a':1,'b':2}
fn(d)
print(d) # {'a': 1, 'b': 2}

上边代码,函数内部变量重新赋值,结果外界d变量不受任何影响。。。再次证明主程序中的d变量和fn函数中的d变量是两个变量。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值