python之函数

本文详细介绍了Python函数的基础概念,包括函数定义、参数传递、变量作用域、递归调用等内容,并探讨了高级主题如高阶函数、装饰器及内置函数的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://blog.youkuaiyun.com/github_27109687/article/details/72974540 Test_huhy博客

特别说明:本篇博客都是基于python3.5环境进行操作说明。
  本篇博客内容主要包括函数的定义、函数的参数、全局变量和局部变量、函数的返回值、递归调用、高阶函数、匿名函数、python的内置函数和装饰器等等。

一、函数的定义

  函数就是封装代码,该代码可实现某种功能,在其他地方需要用到的时候,直接调用该函数就行。函数就是方法,方法就是函数。
  函数即变量。如果只是一个函数名的话,它就是一个普通变量,这个变量里面存的是这个函数里面的代码而已,返回的是一个存放的地址;如果加上()就是调用这个函数。
  函数的命名规则:一般用小写字母和单下划线、数字等组合,不要使用Python关键字和单个字符作为命名。详细的各类Python命名规则请参考-Python技术博文:http://mp.weixin.qq.com/s/rMx45cJ0odUKt2_ndocnKw(值得收藏的好文章!)
  函数的定义使用def关键字,后面跟着函数名,最后再跟上一个函数体。定义的格式如下代码所示:

#函数名
def my_open():
    #函数体
    fw =open('a.txt','a+')
    fw.seek(0)
    fw.read()

my_open()#调用函数,读文件

#如果想定义一个什么事都不做的空函数,可以用pass语句
def nop_null():
    pass

二、函数的参数

  函数在调用的时候,可以传入形参和实参。函数的四种形参类型分别包括位置参数(也叫必填参数)、默认值参数、非固定参数(备注:参数个数不固定)。其中非固定参数有两种,一种是可变参数,一种就是关键字参数。还要说明的一点,如果有多个位置参数的话,位置又不确定的情况下,可以使用位置参数的名称来指定调用,这种调用方式叫做关键字传参。

1、形参和实参

形参:就是函数接收的参数,同时形参只是在函数内部有效。
实参:调用函数传入的参数,实参可以是常量、变量、元组、字典、表达式、函数等。在进行函数调用时,它们都必须有确定的值,以便把这个值传给形参。
举个简单的例子,如下代码所示:

def all(a,b):#这里的a,b就是形参
    print('%d+%d=%d'%(a,b,a+b))

all(3,4)#3,4就是实参

2、位置参数

位置参数就是必填参数,调用的时候一定要传的。比如下方的代码:

def reg(name,age):
    #其中name,age就是必填参数,也就是位置参数
    print('name is %s,age is %s'%(name,age))

reg('小明',23)

3、默认值参数

默认值参数是非必填参数,调用的时候可不传。如果给默认值参数传值的话,它就会使用你传入的值,否则就使用默认值。

def reg(name,sex='未知'):
    #其中sex就是默认值参数
    print('name is %s,sex is %s'%(name,sex))

reg('小明')#调用的时候,sex可不传,默认sex未知
reg('小红','女')

4、可变参数

可变参数也叫参数组,也是非必填的参数。参数个数不固定,它接收到的是一个元组。它把调用函数时传进去的每一个参数都放到一个元组里。简单的代码例子如下:

#单个可变参数例子

def reg(*args):
    #args不是固定的,可以任意取名称,只要前面加上‘*’就行,比如:*huhy
    print(args)

reg('小明')
reg('小明',23,'女')
reg()
#多种参数组合的例子
def other(name,age,country='china',*args):
    print(name)
    print(age)
    print(country)
    print(args)
other('xiaom',56,'美国','china',89,'北京')
#输出的结果:
#xiaom
#56
#美国
#('china', 89, '北京')

5、关键字参数

关键字参数,也是一个非必填参数。它接收的是一个字典,调用得用key-value形式或者通过传入字典进行调用,但是传入字典调用的时候,字典前要加’**’。简单的代码例子如下所示:

dict={'name':'小明','age':17,'addr':'北极星'}
def kw(**kwargs):#kwargs不是固定的,可任意取
    print(kwargs)
kw(name='小明',age=18,sex='男')
kw()
kw(**dict)#传入字典dict调用

参数总结

  • 参数组合:在Python中定义函数,如果必填参数、默认值参数、可变参数和关键字参数一起组合使用的话,请注意参数必须按照必填参数、默认值参数、可变参数、关键字参数的顺序来定义,否则会报错。
def reg(name,age=18,*args,**kwargs):
    print(name)
    print(age)
    print(args)
    print(kwargs)

reg('小明')
reg('小明',35,'python','xuxi',addr='北极星')
  • 通过关键字参数调用,指定参数传值。这种传参可以不关心参数位置,位置可以打乱。如果位置参数和关键字参数调用混用的时候,位置参数必须写在前面。简单代码例子如下所示:
def reg(name,age,sex,addr):
    print(name)
    print(age)
    print(sex)
    print(addr)
#关键字参数调用
reg(age=56,addr='北极星',name='小明',sex='未知')
reg('小欧',sex='男',addr='北极星',age=45)
  • 一般参数比较多且不确定参数的个数的情况下,形参可以考虑使用可变参数或关键字参数。

二、函数的返回值

  • 执行遇到return会立即结束函数,否则会从上到下执行完函数的所有代码再结束;
  • 函数可以没有返回值,如果函数的返回值在其他函数或者函数外面有用到的话,则需要return;若不需要则不用return,默认返回None。
  • 函数return多个值的话,如果一个变量接收的话,它会把多个值放到一个元组里面去。
#举一个例子:
def add(a,b):
    return a+b

def say_num(sum):
    print(sum)
res=add(30,60)#调用有返回值的函数,返回值90
say_num(res)#调用无返回值的函数,默认返回None

三、全局变量和局部变量

  • 在函数里面定义变量叫局部变量,它只能在函数里面用。在函数外,该局部变量就不能使用了。
  • 在函数外面定义的变量叫全局变量,在函数内也可以使用。
  • 如果想在函数里面修改全局变量的值,那么在函数里,要用global关键字声明该变量。同时注意:如果修改int、string类型的变量,必须得写global;如果是修改字典、list、文件对象等类型的变量,不能加global。(建议:尽量少这样使用
  • 变量要先定义后使用,一遍定义变量写在最前面
#下面举多个代码例子说明:

def add():
    a=2
    print(a)
c=a+1 #a是局部变量,外面不能使用,则该段函数会报错:'a' is not defined

#未申明全局变量
a=999
def add():
    a=2
    print(a)
add()#调用函数,打印2
print(a)#打印999

#申明全局变量
a=999
def add():
    global a
    a=2
    print(a)
add()#调用函数,输出结果打印2
print(a)#全局变量a被改变,输出结果打印2

#列表、字典可直接使用全局变量,不需要申明global
list=[1,6,7,90]
def add():
    list.append(5)
    print(list)
add()#调用函数,打印的输出结果:[1,6,7,90,5]

四、递归调用

  一个函数在内部自己调用自己本身就是递归调用。默认最大的递归次数是999次,这个限制可以调整。
递归调用的特性:

  1. 必须有一个明确的结束条件
  2. 递归效率不高,要少用递归
  3. 每次进入更深一层递归时,问题规模相比上一次递归都应有减少
#举个简单的代码例子:
def select_option():
    option=input('请输入选择1、2、3:')
    if option !='exit': #只有当输入exit才会结束递归调用
        select_option() #递归调用
select_option()

#若想修改最大递归次数,通过如下代码进行设置:
import sys
sys.setrecursionlimit(1500)

五、高阶函数

  如果一个函数的入参是一个函数名的话,那这个函数就是一个高阶函数。

#举个简单的代码例子

def a(x):#求一个数的平方
    return x*x
def add(x,y,z):#高阶函数,参数z是要传入一个函数名
    res =z(x)+z(y)#想把x,y传给z这个函数,然后把返回值相加
    return res
print(add(3,2,a))

六、函数的作用域

  函数的作用域遵循就近原则,从函数里往函数外找。如果自己函数里有,就用自己函数里的;如果自己的函数里面没有的话,就去它父级函数里找。

#举个简单的代码例子:

name='python'
def warpper():
    name='小米'
    print(name)
    def deco():
        # name='小红'
        print(name)
        def hhh():
            name='小白'
            print(name)
        hhh()
    deco()
warpper()
#输出结果:小米 小米 小白

七、装饰器

  • 装饰器就是函数里面嵌套定义一个函数,其实装饰器由函数嵌套+高阶函数组成,装饰器作用就是在不改变原来的函数的调用方式和入参情况下,给函数增加新功能。实际生活的例子:比如淘宝浏览商品和添加购物车两个功能。浏览器商品无需登录,添加购物车需要登录,这个例子就可以用装饰器。
#比如计算一个函数运行的时间,例子如下所示:

#利用高阶函数
import time
def run():#原函数
    print('开始吧~~~')
    time.sleep(2)
def run_time(func):#新函数,增加统计时间的功能
    start_time=time.time()
    func()
    end_time=time.time()
    print("运行时间",end_time-start_time)
run_time(run)#改变了调用方式,而不是运行run()
#利用装饰器的方法
def timeer(func):
     def run_time():
         start_time=time.time()
         func()
         end_time=time.time()
         print("运行时间",end_time-start_time)
     return run_time #timeer()这个函数其实就是返回里面的函数名而已

@timeer   #相当于run=timeer(run),得到的run其实等于run_time,调用run就是调用run_time
def run():
    print('开始吧~~~')
    time.sleep(2)
run() #不改变了原有的调用方式
  • 由于被装饰的原函数可能有很多种,有的可能会传参数,有的可能不传参数,所有为了处理各种情况,可以使用可变参数和关键字参数来接收所有的参数func(*args,**kwargs)。
#简单的代码例子:
import time
def timmer(func):
    def run_time(*args,**kwargs):
        #其中args,kwargs用来接收传入函数的参数
        start_time=time.time()
        res=func(*args,**kwargs)#获取返回值
        end_time=time.time()
        print("运行时间",end_time-start_time)
        print(res)
    return run_time

@timmer
def run():#原函数
    print('开始吧~~~')
    time.sleep(2)
@timmer
def run2(*args,**kwargs):#第二个原函数
    print(args)
    print(kwargs)
    time.sleep(2)
    return args,kwargs
@timmer
def run3(name,age):#第三个原函数,进行装饰
    print(name)
    print(age)
    time.sleep(2)

run()
run2('小子')
run2('小明',addr='香港')
run3('大头儿子',5)

八、内置函数

其中filter()和map()内置函数> 更详细的分析解释可参考moxwose的博客:http://nimbleit.blog.51cto.com/1461447/730031

print(all([1,2,3,4]))#判断可迭代的对象里面的值是否都为真
print(any([0,0,0,0,0]))#判断可迭代的对象里面的值是否有一个为真
print(bin(10))#十进制转二进制
#下面这些函数都是强制类型转换
print(bool('5OH'))#把一个对象转换成布尔类型,非空非0为真
int()#整型
float()#小数
str()#字符串
dict()#字典
list()#列表
set()#集合
tuple()#元组

#isinstance()方法
a='eyy'
b=[1,2,3,4]
c=(1,2,3,4)
d={}
print(isinstance(a,str))#判断a是不是str类型
print(isinstance(b,list)) #判断b是不是list类型
print(isinstance(c,tuple))#判断c是不是元组
print(isinstance(d,dict))#判断d是不是字典

def func():
    pass
print(callable(func()))#判断传入的对象是否可调用

print(chr(98))#打印数字对应的ascii
print(ord('b'))#打印字符串对应的ascii码
print(dict(a=1,b=2))#转换字典
print(dir(dict(a=1,b=2)))#打印传入对象的可调用方法

print(eval('1+2'))
#执行python代码,只能执行简单的,定义数据类型和运算
print(exec('def a():pass'))#执行python代码

resultlst = filter(func, seq)
#根据前面的函数func处理逻辑,依次处理后面可迭代对象seq里面的每个元素,如果func返回值为true,则保存下seq里相对应的原元素,而并非保存func返回值;如果func返回值为false,则丢弃该原元素。记住:filter方法本身返回的是seq元素的列表子集,resultlst是filter类型。

map(func, seq)
#根据前面的函数处理逻辑,依次处理后面可迭代对象里面的每个元素,保存前面函数返回的所有返回值结果
#filter/map()例子:
def funa(num):
    a=int(num)
    return a*a
a_filter_object=filter(funa, [0,1, 2, 3, 4])
filter_list = [item for item in a_filter_object]#filter object是一个迭代器,可通过这种方式转换成列表
print(filter_list)
print(list(filter(funa, [0,1, 2, 3, 4])))#第二种加list()方式,直接转换成列表
#以上输出结果都是:[1, 2, 3, 4]
print(list(map(funa, [0,1, 2, 3, 4])))
#输出结果:[0, 1, 4, 9, 16]


print(globals())#返回程序内所有的变量,返回的是一个字典,函数里面的局部变量不会返回
print(locals())#返回局部变量
print(max(111,12,13,14,16,19))#取最大值
print(round(11.1198,2))#取几位小数,会四舍五入
print(sorted([2,31,34,6,1,23,4],reverse=True))#排序,reverse=False是升序,reverse=True是降序,若不写默认是升序

dic={1:2,3:1,5:6,7:8}
print(sorted(dic.items()))#按照字典的key排序
print(sorted(dic.items(),key=lambda x:x[1]))#按照字典的value排序

九、匿名函数

  如果程序只是执行一次,不需要定义函数名,节省内存中变量定义空间的话,就可以使用匿名函数。Python使用lambda关键字创建匿名函数定义。更多相关匿名函数的详解可参考-杰瑞26的博客文章:http://blog.youkuaiyun.com/jerry_1126/article/details/40105135

#使用def定义函数的方法
def add(x,y):
    return x+y
s=add(1,2)
print(s)

#使用lambda定义函数的方法
s=lambda x,y:x+y
print(s(1,2))

十、小技巧

(1)__init__.py作用

  文件夹下加入init.py这个文件是用区分普通文件夹和包,在python2里面如果要导入其他目录下的python文件,就需要在这个文件下面建一个__init__.py。python3里可以不建就能导入其他目录下的python文件。

(2)if __name__ == ‘__main__’作用

  该作用:只有在运行自己这个python文件的时候才会执行这个if里面的代码语句,别的模块导入该文件的时候,不会执行该段代码。

if __name__ == '__main__':
    xxxx(代码语句)

(3)函数名作为字典值

为了简化if-else多次判断,简化代码,可以使用python中的dict来实现,简单的例子如下所示:

#if-else 方法实现不同的选择进入不同的函数,如下:
def add_product():
    print('a增加商品功能')
def del_product():
    print('删除商品功能')
def query_product():
    print('查询商品功能')
def exit_user():
    print('退出系统')

def main():
    option=input('请输入A-D:')
    if option=='A':
        add_product()
    elif option=='B':
        del_product()
    elif option=='C':
        query_product()
    elif option=='D':
        exit_user()
    else:
        print('请重新输入')
        main()
if __name__=='__main__':
    main()

#使用函数名作为字典值的方法实现不同的选择调用不同的函数,如下:
def add_product():
    print('a增加商品功能')
def del_product():
    print('删除商品功能')
def query_product():
    print('查询商品功能')
def exit_user():
    print('退出系统')

def main():
    menu = {
        'A': add_product,  # 添加商品,字典的值直接就是函数名
        'B': del_product,  # 删除商品
        'C': query_product,  # 查询商品
        'D': exit_user  # 退出系统
    }
    option=input('请输入A-D:')
    if option in menu:
        menu[option]()#调用相应的函数
    else:
        print('请重新输入')
        main()
if __name__=='__main__':
    main()

(4)模块、包的概念

  模块就是python文件,一个.py文件就是一个模块;包是一个文件夹,下面必须要有init.py文件~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值