python 函数

光用python提供的内置函数是满足不了开发需求的,我们需要把一些重复的代码逻辑封装起来定义成一个函数,以便于我们调用,于是就有了自定义函数

自定义函数

语法

def:关键字

funcname:函数的名字

args:参数

return:返回值

def funcname(args):  
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args) #函数体,也就是函数要做什么事
    return 123

好,你一脸懵逼,不要紧,举个栗子:

def funcname(args):
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args)  #函数要做什么事
    return 123

调用函数,直接用函数的名字里面加上要传的参数:

funcname("sb")   #调用函数,将sb传到args的位置

  

输出结果: 

函数和变量就是一回事

return就是函数被调用返回的结果,需要赋值给变量保存下来,还是上面的例子:

def funcname(args):
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args)
    return 123

res=funcname("sb")  #将调用的返回值赋值给res保存下来
print(res)  

再看输出结果:

是不是return的123出来了?

函数一碰到return就会终止,并把return返回的值作为它的一个返回结果,如果赋值给一个变量了,就会把这个值保存下来,如果不赋值,就没有人拿

def funcname(args):
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args)
    return 123
    print("==========")
    print("==========")  #碰到return就会终止,后面的不会执行
  
funcname("sb")

  

看下结果:return后的没有被执行

为什么要有返回值?如果不加返回值呢?

举个栗子:

def funcname(args):
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args)
 #没有return
res=funcname("sb") print(res)

看下结果:

没有返回值,python会自动返回None

因为函数通常要做某一个功能,无论执行多少行代码,最终都要完成一件事, 得到一个结果,return就是把这个结果给别人去用

返回值:

1.没有返回值---------python会默认返回None

2.一个返回值---------返回的就是return后定义的那一个值,该返回啥就返回啥

3.多个返回值----------返回的是一个元组

举个例子:

def funcname(args):
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args)
    return 1,2,3,4    #多个返回值
res=funcname("sb")
print(res)

看下结果:

返回的是一个元组

类似于去超市买东西,可以不买东西出来,可以买一个东西出来,可以买许多东西出来,比如说杜蕾斯,香皂,润滑油,皮鞭等,就要有多个返回值

返回值可以使任意的类型,比如:字符串。列表,元组,字典

举个例子:返回值里套一个元组的方式

def funcname(args):
    '''
    文档注释
    :param args:
    :return:
    '''
    print('hello',args)
    return 1, 2, 3, 4, 5, 6, ('a', 'b')
res=funcname("sb")
print(res)

看下结果:

返回值里就是一个元组套了一个元组

函数的三种定义方式:

第一种:

无参函数:(就是没有参数)

def av():
     print('你喜欢那个AV女优')

定义没有参数,调用也不用参数

def av():
     print('你喜欢那个AV女优')
av()

输出结果: 

有参函数:

def av(x,y,z):
    print('你想上哪个?',x,y,z)

定义有参数,调用也必须有参数

def av(x,y,z):
    print('你想上哪个?',x,y,z)

av("苍井空","波多野结衣","吉泽明步")

输出结果:

空函数:

 def f3():
     pass

 f3()

 这种函数写不写参数不是重点,重点是pass

比如说开发一个ftp功能

def put():
    '''
    file upload
    :return:
    '''
    pass

def get():
    '''
    file download
    :return:
    '''
    pass

def cd():
    '''
    change directory
    :return:
    '''
    pass

比如get函数有了灵感,就可以把get函数写了一遍,哪个有用写哪个, 没写的以后看到注释可以再替换pass

pass就是什么也不干的意思,在各个地方都可以用,比如if

比如说你put函数没来得及写,但是你同事着急用,这期间你怀孕了请假要去堕胎,这时候你同事可以做一个判断,对你同事没有影响

a=1
if a > 1:
    print('===')   #如果a大于1,你同事可以写自己的功能
else:
    put()

  

函数定义的的三种调用形式

先定义一个函数,求两个值最大的值,return可以任何形式,这里我们用三元表达式的方式

def my_max(x,y):
    return x if x > y else y

第一种调用形式:语句形式

什么叫语句:print就是一个语句

什么叫表达式:1+1;2*1就是表达式

def my_max(x,y):
    return x if x > y else y
my_max(1,2)

这就是语句形式,没有任何运算,也没有任何等式

通常用于没有返回值的调用 ,有返回值得调用通常用表达式的形式

第二种调用形式:表达式的形式

可以将返回值保存下来

def my_max(x,y):
    return x if x > y else y
res=my_max(1,2)
print(res)

可以用返回值进行运算

def my_max(x,y):
    return x if x > y else y

res=10*my_max(1,2)  #用10乘以返回值
print(res)

输出结果

第三种调用方式:作为参数

求三个数的最大的值

def my_max(x,y):
    return x if x > y else y

res=my_max(10,my_max(11,12))
print(res)

先用11和12比较,然后把12作为参数传给下一个,用12和10比较,原理就是在求10 11 12这三者的最大值

  

形参和实参

形式参数

def foo(x,y):
    print(x)
    print(y)

其中x,y就是形式参数,没有被调用,就只是两个名字,根本不占用空间,别人一调用它,才会占用空间,在函数的内部产生内存占用,实际上就是把实参的值传给形参

在python中,名字没有任何储值功能,任何的赋值都是绑定一个名字到一个值

实际参数

foo(1,2)

1和2就是实际参数

实际参数是真实占用内存空间的,形式参数只有被调用,被传值了,它才占用内存空间 

实参给形参传值的过程就是一个变量名的绑定过程

参数的动态性:(不受限制)

可以传浮点型

def foo(x,y):
    return x+y

foo(1.2,3)

输出结果:

可以传字符串

def foo(x,y):
    return x+y


print(foo("a","b"))

输出结果:

这么做有好处也坏处:

好处:在定义函数时变得非常简单,非常灵活 

坏处:调用时候容易出错,懵逼了?看下面例子:

举个栗子:

我们传1和a试一试

def foo(x,y):
    return x+y

print(foo(1,"a"))

看下结果:

what?报错了?告诉你数字和字符串不能相加

那怎么解决呢?在实际工作中,不可能完成限制功能,只能曲线救国,有三种方法

解决动态性问题:

第一种:(推荐)

就是写好文档注释

def foo(x,y):
    '''
    :param x:int  #告诉别人x必须是int
    :param y:int #告诉别人y必须是int
    :return:
    '''
    return x+y

print(foo(1,"a"))

别人在用的时候先help一下,一看就知道这个函数怎么用了

def foo(x,y):
    '''
    :param x:int  #告诉别人x必须是int
    :param y:int #告诉别人y必须是int
    :return:
    '''
    return x+y

print(help(foo))

输出结果:

加上文档注释并没有对函数起到限制作用,如果非法传参还是会报错

第二种:(很多人这样去做,但高手一般不会这么做)

def foo(x,y):
    if type(x) is int and type(y) is int: #当x是int和y是int类型时,才会返回
        return x+y

函数的主要功能是加法,中间加了个if,跟功能一毛钱关系都没有只是为了报错采取的一个措施,相当于代码的擦屁股纸,你也可以这么做,见仁见智

第三种:(更加骚气)

def foo(x:int,y:int)->int: #解释一下x是int类型,y是int类型,返回值是int类型
    return x+y

print(foo(1,2))

:int只是一种注释,语法没毛病,没有影响,不会报错,只是调用了另一种叫__annotations__注释:

def foo(x:int,y:int)->int:
    return x+y
print(foo.__annotations__)
print(foo(1,2))

看一下结果:

 解释一下x是int类型,y是int类型,返回值是int类型

高手一般觉得第一种牛逼!

形参和实参的使用:

在使用的角度

实参的使用

实参给形参传值有两种方式

先定义一个函数吧 

def foo(x,y):
     print(x)
     print(y) 

第一种:

按照位置(顺序)传值

举个栗子:

foo(1,2)

输出结果:

 

foo(2,1)

 输出结果:

 

按位置定义的实参受位置影响

2.按照关键字传值

一个key对应一个value

foo(y=2,x=1)

x已经定义等于1,y已经定义等于2,所以先打印1,再打印2

这个位置没关系,不受位置影响

注意问题一:针对同一个形式参数,你可以按照位置或者按照关键字传值,但是只能用一种方式,不能重复给一个参数传值

举个栗子:

foo(1,x=1,y=2)

输出结果:

注意问题二:按关键字传值必须在按位置传值的右边

foo(x=1,2)

乍一看,没毛病,来看一下输出

 

 x=1是关键字,2是位置,关键字传值必须在按位置传值的右边,所以报错 

形参的使用

形参一共有四种形式:

位置参数,默认参数,*args可变参数,**kwargs

先定义一个示例函数:

def foo(x,y,z):
    print(x)
    print(y)
    print(z)

  

1.位置参数

特性:多一个不行,少一个不行,必须传值

可以按位置传值,也可以按关键字传值

举个栗子:

foo(1,2,3)

 多一个少一个都会报错,这里不进行演示了,看一下按照位置传参

foo(x=1,z=2,y=3)

 输出结果

 

2.默认参数

在定义形参是给它一个值

定义已经传值,在调用时可以不用传值,如果非要传,会覆盖掉,针对任何形式参数,都有两种传值方式

def foo(x,y=2):
    print(x)
    print(y)
foo(1) 

 y已经被定义成了2,所以2不用传值

def foo(x,y=2):
    print(x)
    print(y)

foo(1,3)

 y已经定义了2,非要传给y一个3,那么他会覆盖

按照位置来传参

def foo(x,y=2):
    print(x)
    print(y)

foo(x=1,y=5)

1.通常把变化比较小的参数定义成默认参数

假如注册信息男的多的话

 def register(user,age,gender='male'):
     print(user)
     print(age)
     print(gender)

register('egon',18)

2.默认参数必须在位置参数右边

def foo(x=1,y):
pass

  

3.默认参数一定要定义成一个不可变类型

def foo(x,l=[]):
    l.append(x)
    return l

print(foo(1)) #[1]
print(foo(2)) #[2]
print(foo(3))

记住要等于一个明确的不可变类型

4.默认参数在定义时就已经被赋了一个明确的值了,后期的变化对其无效

name='cangjingkong'
def foo(x,y=name):
    print(x)
    print(y)

name='av'
foo(1)

后期重新定义name对其无效,因为一开始就被赋值了

 

  

原文地址:https://www.cnblogs.com/hui520/p/6407016.html