首页 > 编程语言 >一篇文章让你让你对python函数的掌握由基础到高级

一篇文章让你让你对python函数的掌握由基础到高级

时间:2024-06-09 16:31:39浏览次数:17  
标签:一篇 python 作用域 参数 fn print def 函数

python中函数由低级到高级

一 函数基础

1.1 函数简介 function

input print 内置函数——》可以直接使用

可复用性非常差

函数就是存代码的

总结函数的优点:
1.遇到重复功能的时候,直接调用即可,减少代码量
2.提升代码的结构性,分工明确,提高代码的可读性
3.遇到扩展功能的时候,修改比较方便

函数的本质就是一段有特定功能、可重复使用的代码,这段代码已经被提前编写好了,并且为其起了一个“好听”的名字,在后续编写程序中,如果需要同样的功能,直接通过起好的名字就可以调用这段代码

def my_len(s):
    leng = 0
    for i in s:
        leng+=1
    return leng

lengt = my_len('sahdjbaodbnao')
print(lengt)  # 13
lengt1 = my_len('xiaochuan')
print(lengt1) # 9

1.2 函数定义

定义函数:

def 函数名(形参1,形参2....形参n):
    代码块(函数体)
def fn():
    print('这是我的第一个函数')
# 函数中保存的代码不会立刻执行,需要我们用户自己调用函数,代码才会执行

1.3 函数调用

必须遵循先定义再调用

def fn():
    print('这是我的第一个函数')
print(fn) # fn是函数地址函数对象<function fn at 0x000002980AEB7430>
print(type(fn)) # <class 'function'>
调用函数语法:
函数名()

def fn():
    print('这是我的第一个函数')
fn()
fn()
fn()
fn()
fn()

这是我的第一个函数
这是我的第一个函数
这是我的第一个函数
这是我的第一个函数
这是我的第一个函数
def fn():
    print('吃了吗')
    print('睡了吗')
    print('你好')
    print('再见')
fn()
fn()
吃了吗
睡了吗
你好
再见
吃了吗
睡了吗
你好
再见
区分:
fn    函数名
fn()  函数调用

1.4 函数参数

1.4.1 形参和实参
def 函数名(): # 括号里面没东西就叫做无参函数
def 函数名(参数1,参数2...参数n): # 括号里面有东西,这个东西就叫做参数,可以有很多个
函数的参数:在定义函数时,可以在函数名后()中定义数量不等的形参,注意可以有,也可以没有,可以有一个也可以有多个,多个形参之间使用逗号隔开

形参(形式参数):定义形参就相当于在函数内部声明了变量,但是并不赋值,这个变量只是先形式的在函数里使用,但是它没有值

实参(实际参数):在函数定义的时候指定了形参,在调用的时候也必须传递实参,我们的实参会赋值给对应的形参,简单来讲就是有几个形参,我们必须传递几个实参
def fn(a,b):
    print('a=',a)
    print('b=',b)
fn(10,20) # 10,20就叫做实参

a= 10
b= 20
# 定义一个函数,可以用来求任意两个数的和
def sum1(a,b):
    print(a+b)
sum1(22,33)
sum1(1,1)
sum1(111,333)
总结:
在定义函数时那个参数叫形参
调用的时候叫实参
定义了多少个形参就要传递多少个实参
1.4.2 参数的传递方式

形参的传递方式

1.4.2.1 默认值参数
def fn(a,b,c=10):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,3)
a= 1
b= 2
c= 3


def fn(a,b,c=10):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2)

a= 1
b= 2
c= 10

有些参数太常用或者说基本不会去改变它,我们就可以使用默认值参数

实参的传递方式

1.4.2.2 位置参数和关键字参数
1.位置参数
就是将对应位置的实参赋值给对应位置的形参
2.关键字参数
可以不按照形参定义的顺序来传递,而是直接根据参数名来传递参数
def fn(a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(b=1,c=3,a=2)
注意:混合使用关键字和位置参数的时候,位置参数必须写在关键字参数的前面
def fn(a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,c=20)

a= 1
b= 2
c= 20

实参可以传递任意类型

def fn2(a):
    print('a=',a)
# fn2(123)
a = 123
fn2(a)
1.4.3 可变参数

也叫作不定长参数

1.4.3.1 *args

*args可以获得我们所有的实参,将所有的实参都保存到一个元组中,实参传递几个值元组就会有几个元素,它会接收所有的参数

我们把散开的数据,装到一个元组或者是字典里面里面这就可以叫做是装包

好处就是你想传几个就传几个,不传都行

def fn(*a):
    print(a)  # ()
    print(type(a)) # <class 'tuple'>
fn()

def fn(*a):
    print(a)  # (1, 2, 3, 4, 5)
fn(1,2,3,4,5)
# 定义一个函数,求任意个数的和
def sum1(*args):
    result = 0
    for i in args:
        result+=i
    print(result)
sum1(1)  # 1
sum1(1,2)  # 3
sum1(1,2,3)  # 6
sum1(1,2,3,4,52,3,4,5,6) # 80

注意:
1.带*号的形参只能有一个,因为写多了没办法分
2.带*号的参数可以和其他参数配合使用,但是得写在最后面
def fn(a,b,*c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,3,4,5,6,7,8,9)

a= 1
b= 2
c= (3, 4, 5, 6, 7, 8, 9)

def fn(*a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,3,4,5,6,7,8,9,1,1,1,1,1,1,1,1,1,1)  # 报错,*a是无限长的,b和c读取不到值

# 使用下面的写法可以解决可变参数写在前面的情况
def fn(*a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,3,4,5,6,7,8,9,b=44,c=55)

a= (1, 2, 3, 4, 5, 6, 7, 8, 9)
b= 44
c= 55
1.4.3.2 **kwargs

*形参有一个弊端就是只能接收位置参数

**形参可以接收任意关键字参数,会将这些参数统一保存到字典里面,字典的键就是参数的名字,字典的值就是参数的值

def fn(**args):
    print('args=',args)
    print(type(args))
fn(a=1,b=2,c=3)

args= {'a': 1, 'b': 2, 'c': 3}
<class 'dict'>

注意:**形参也是只能有一个,并且必须写在所有参数最后,它必须是最后一个

*args和**kwargs是可以同时使用的
要注意的是,同时使用*args和**kwargs的时候,*args必须写在**kwargs之前
def fn(a,b,*args,**kwargs):
    print('a=',a)
    print('b=',b)
    print('args=',args)
    print('kwargs=',kwargs)
fn(1,2,3,4,5,6,7,8,9,1,5,k=1,w=2,aa=3,rr=4)
1.4.3.3 参数解包

传递实参时,也可以在序列类型参数前面添加星号,这样他会自动将序列中的元素依次作为参数传递

注意:序列中的元素必须和我们函数形参的个数一致

def fn(a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
# t = (1,2,3)
# fn(*t)
fn(*[2,3,4])
# fn(*[2,3,4,5])  # 报错,元素个数必须和形参个数一致

a= 2
b= 3
c= 4
# 注意:字典的解包必须要满足字典的key和参数的名字对上
def fn(a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
d = {'a':10,'b':20,'c':30}
fn(**d)

a= 10
b= 20
c= 30
总结
1.*args适用于接收多余的未命名的位置参数
**kwargs用于接收关键字参数
其中args是一个元组类型
kwargs是一个字典类型
2.*args是把元组中的数据进行解包,也就是把元组中的数据拆成单个的数据
**kwargs是把字典中的数据进行解包,也就是把字典中的数据拆成单个的键值对

二 函数返回值 return

函数执行以后返回的结果

获取返回值:把函数调用当做一个值来输出

return后面是什么,函数的返回结果就是什么

return后面可以是任意的值

返回值可以是任意类型包括函数

def fn():
    def fn2():
        print('hello')
    return fn2
r = fn()  # fn2
print(r) # <function fn.<locals>.fn2 at 0x00000287B1216670>
r() # hello
# 如果我们不给一个函数return,那么这个函数的返回值就是空的,就是None
def fn2():
    pass
print(fn2()) # None
# NoneType只有一个值就是None
print(type(None)) # <class 'NoneType'>
# 如果给一个函数写return但是return后面没有值那么这个函数的返回值也是None
def fn():
    return 
print(fn())  # None
在函数中,return代表函数执行结束,后面的代码不会再执行

总结

return 语句的作用:结束函数调用、返回值、指定返回值
print 和 return的区别是什么:
print仅仅是打印在控制台,把结果打印出来,而return则是将return后面部分作为返回值:作为函数的输出,可以赋值给变量,继续用返回值做其他操作

注意:return语句在同一个函数中可以出现多次,但是只要有一个得到执行,就会直接结束函数的执行

三 作用域与命名空间

3.1 作用域

3.1.1 简介

作用域直白来说就是变量产生作用的区域

程序中就是:指的是变量生效的区域

def fn():
    x = 1  # x定义在函数fn的内部 所以x的作用域就是在函数内部,在函数外部无法访问

print(x) # 无法访问函数内部x


y = 2
def fn():
    x = 1  # x定义在函数fn的内部 所以x的作用域就是在函数内部,在函数外部无法访问
    print('函数内部y=',y)
fn()
print('函数外部y=',y)

函数内部y= 2
函数外部y= 2
3.1.2 全局作用域

全局作用域就是在全局都有效

全局作用域的生命周期:全局作用域在程序执行时创建,在程序执行结束时销毁

哪些位置属于全局作用域?所有函数以外的都是全局作用域
只要代码不是在函数里面都是全局作用域
在全局作用域中定义的变量,都属于是全局变量,全局变量可以在程序的任意位置被访问
# y就是全局变量
y = 2
def fn():
    x = 1  # x定义在函数fn的内部 所以x的作用域就是在函数内部,在函数外部无法访问
    print('函数内部y=',y)
fn()
print('函数外部y=',y)

函数内部y= 2
函数外部y= 2
3.1.3 局部(函数)作用域
函数作用域的生命周期:就是在函数调用时创建,在调用结束时销毁
函数每次调用的时候都会产生一个新的函数作用域
在函数作用域中定义的变量只能在函数内部访问,或者说在函数作用域中定义的变量都可以叫做局部变量
def fn():
    a = 10
    print('a=',a)
fn()
print('a=',a) # 报错,访问不到

可以从小的往大的看,但是不能从大的往小的看

def fn1():
    a = 30
    def fn2():
        print(a)  # 30 可以从里面往外面看
    fn2()
fn1()

def fn1():
    def fn2():
        a = 10
    print(a)  # 报错 不能从外面往里面看
fn1()
def fn1():
    a = 20
    def fn2():
        a = 10
        print(a) # 10
    fn2()
fn1()
使用变量的时候,会优先在当前作用域中寻找该变量,如果有就是用,没有就继续往上级作用域中寻找

global 关键字——》如果希望在函数内部修改全局变量,可以使用global关键字来声明变量

a = 1
def fn():
    a = 2
    print('内部a=',a) # 内部a= 2
fn()
print('外部a=',a) # 外部a= 1

a = 1
def fn():
    global a  # 把变量a声明为全局变量
    a = 2
    print('内部a=',a) # 内部a= 2
fn()
print('外部a=',a)  # 外部a= 2
总结:
1.基本就是 里面能看到外面,但是外面看不到里面
2.如果局部修改全局变量可以加上一个global关键字

3.2 命名空间

就是变量存储的位置

每一个作用域都会有一个对应的命名空间

全局作用域有全局的命名空间

局部作用域有局部的命名空间

命名空间实际上就是一个字典,是一个专门存储变量的字典

locals():获取当前作用域的命名空间,返回一个字典

a = 1
def fn():
    b = 1
    print(locals())  # 函数作用域中的命名空间{'b': 1}
fn()

a = 1
def fn():
    global b  # 把变量b声明给全局了
    b = 1
    print(locals())  # {}
fn()
global  全局 把函数体内部变量声明给全局
a = 1
def fn():
    a = 2
    print('内部a=',a) # 内部a= 2
fn()
print('外部a=',a) # 外部a= 1

a = 1
def fn():
    global a  # 把变量a声明为全局变量
    a = 2
    print('内部a=',a) # 内部a= 2
fn()
print('外部a=',a)  # 外部a= 2

nonlocal  局部 只能在嵌套函数中使用
用来在函数或者其他作用域中使用外层(非全局)变量
def f1():
    a = 1
    def f2():
        a =2
        print('f2中的a=',a) # f2中的a= 2
    f2()
    print('f1中的a=',a)  # f1中的a= 1
f1()

def f1():
    a = 1
    def f2():
        nonlocal a
        a =2
        print('f2中的a=',a)  # f2中的a= 2
    f2()
    print('f1中的a=',a) # f1中的a= 2
f1()
全局 = 大方的人——》我的东西你们都可以用
局部 = 小气的人——》我的东西只有我能用

四 函数进阶

4.1 高级用法

只是让大家知道可以这么去使用,但是不常用

1.函数可以被引用(可以赋值)

def fn():
    print('我是fn')
f = fn
print(f,fn) #<function fn at 0x000001ACA2557430> <function fn at 0x000001ACA2557430>
fn() # 我是fn
f() # 我是fn

2.函数可以作为参数传入另一个函数

def fn():
    print('我是fn')
def fn2(x):
    print(x) # <function fn at 0x000001CB97FF7430>
    x()  # 我是fn
fn2(fn)  

3.可以将函数作为返回值

def fn():
    print('我是fn')
def fn2(x):
    # print(x)
    return x
x = fn2(fn)   # fn2(fn)  ——》fn
x()  # 我是fn

4.函数可以作为容器的元素

def fn():
    print('我是fn')
li1 = [1,2,3,fn]
f = li1[3]
f()  # fn()

4.2 匿名函数 lambda

语法:
lambda 参数列表:运算表达式
def fn(x):
    return x*x


# print(fn(5))  # 25
f = lambda x:x*x
print(f(5))  # 25
总结注意事项:
1.lambda并不会带来程序运行效率的提高,只会使代码更简洁
2.如果使用lambda,lambda内不要有循环,因为可读性不好,有的话请使用标准函数完成,目的是为了代码有可重用性和可读性
3.lambda只是为了减少单行函数的定义而存在,如果一个函数,只有一个返回值,只有一句代码,就可以使用lambda

4.3 高阶函数

4.3.1 高阶内置函数简介
所谓的高阶函数就是把函数作为参数传入,就是把一个函数作为另一个函数的参数传入
abs() ——》求绝对值
print(abs(-1))  # 1
sum() ——》求和
print(sum([1, 1, 2, 3, 4])) # 11
round() ——》求四舍五入
print(round(4.3)) # 4
任意两个数字,对2个数字求绝对值后进行求和
def ab_sum(a,b,f):
    return f(a)+f(b)
res = ab_sum(-1,4,abs)
print(res)

求相反数的和
def xfs(x):
    return -x
def ab_sum(a,b,f):
    return f(a)+f(b)
res = ab_sum(1,-4,xfs)
print(res)
4.3.2 map()
map(func,seq)第一个参数是给一个函数,第二个参数是给一个序列类型(要改变的序列)
map的作用就是改变序列中所有的元素,改变规则由我们传入的函数决定
li1 = [-1,2,-3,4,-5]
print(list(map(abs,li1))) # [1, 2, 3, 4, 5]
将列表中序列的各个元素加一
li1 = [1,2,3,4,5]
# 普通做法
li2 = []
for i in li1:
    li2.append(i+1)
print(li2) # [2, 3, 4, 5, 6]
# map()做法
def add1(x): # x就是列表中的每个元素
    return x+1
print(list(map(add1,li1)))
# lambda做法
print(list(map(lambda x:x+1,li1)))
4.3.3 filter()
filter(func,seq)第一个参数是给一个函数,第二个参数是给一个序列类型(要改变的序列)
filter用于过滤序列,过滤掉不符合条件的元素
需求:保留一个序列中所有的偶数
li1 = [1,2,3,4,5,6,7,8,9,10]
# 普通做法
li1 = [1,2,3,4,5,6,7,8,9,10]
for i in li1:
    if i %2 !=0: # i是奇数
        li1.remove(i)
print(li1) # 所有的偶数
# filter用法
li1 = [1,2,3,4,5,6,7,8,9,10]
def os1(x):
    return x%2==0
print(list(filter(os1,li1)))
# lambda用法
print(list(filter(lambda x:x%2==0,li1)))
4.3.4 sorted()
语法:sorted(seq,key=函数) # 第一个是给一个序列类型,第二个是参数key=函数  函数是自己所定义的规则排序
返回一个排序后的序列
li1 = [2,1,4,3,5,6,9,7]
print(sorted(li1))  # 升序
print(sorted(li1,reverse=True)) # 降序
需求:
li1 = ["小零:69","小违:79","小力:89","小荣:100","小川:59"]
def f(x):
    arr = x.split(":")
    return int(arr[1])
print(sorted(li1,key=f)) # ['小川:59', '小零:69', '小违:79', '小力:89', '小荣:100']

# x——》x是列表中每一个元素,每一个字符串"小零:69"
# x.split(":") #["小零","69"],["小违","79"]
# arr[1] 根据下标获取第二个值也就是每个元素的分数 69,79,89,但是他们都还是字符串类型
# int(arr[1])将字符串类型转成int才可以进行排序计算

max(seq,key=函数):根据函数可以获取序列类型的最大值
min(seq,key=函数):根据函数可以获取序列类型的最小值
def f(x):
    return int(x.split(":")[1])
print(max(li1,key=f)) # 小荣:100
print(min(li1,key=f)) # 小川:59

4.4 递归函数

如果一个函数的内部调用了自己,那么这个函数就叫做递归函数
1.如果定义递归函数,不想让它报错的话,必须要有出口
2.设计一个出口,不断的向出口接近
# 打印1-500
def func(x):
    if x == 501:
        return 
    print(x)
    return func(x+1)
func(1)

标签:一篇,python,作用域,参数,fn,print,def,函数
From: https://blog.csdn.net/Al_lover/article/details/139562093

相关文章

  • 《Python程序设计(第二版)》第五章冷门点
    python小白考前复习集合关系运算去掉列表中重复元素,按原列表顺序输出无重复元素的列表集合的存储原理元素必须可哈希查找速度特别快字典函数存储原理字典可以作为if多路分支的替代写法计数作用多项式相加嵌套结构集合一般什么时候用集合呢?就是想要维护一大堆不重......
  • 一个python 程序执行顺序
    1.Python程序执行顺序在Python中,程序的执行顺序通常遵循几个基本原则:(1)从上到下:Python代码通常从上到下顺序执行。(2)代码块:由缩进(如空格或制表符)定义的代码块(如函数定义、类定义、循环体、条件语句体等)内的代码会按照特定的逻辑顺序执行。(3)控制流语句:如if、for、while等控制......
  • sqli-labs 靶场闯关基础准备、学习步骤、SQL注入类型,常用基本函数、获取数据库元数据
    Sqli-labs的主要作用是帮助用户学习如何识别和利用不同类型的SQL注入漏洞,并了解如何修复和防范这些漏洞。它提供了多个不同的漏洞场景,每个场景都代表了一个特定类型的SQL注入漏洞。用户可以通过攻击这些场景来学习和实践漏洞利用技术,以及相应的修复和防御措施。Sqli-labs......
  • python-数据分析-Numpy-3、数组的运算
    数组的运算使用NumPy最为方便的是当需要对数组元素进行运算时,不用编写循环代码遍历每个元素,所有的运算都会自动的矢量化。简单的说就是,NumPy中的数学运算和数学函数会自动作用于数组中的每个成员。#-*-coding:utf-8-*-#数组的运算#使用NumPy最为方便的是当需要对数组......
  • python后端结合uniapp与uview组件tabs,实现自定义导航按钮与小标签颜色控制
    实现效果(红框内):后端api如下:@task_api.route('/user/task/states_list',methods=['POST','GET'])@visitor_token_requireddeftask_states(user):name_list=['待接单','设计中','交付中','已完成','......
  • Python: 2d arry
     score=[[58,80,74,90,45,82],[71,70,64,85,50,86],[87,63,65,84,62,83],[91,66,67,92,65,90],[83,74,81,82,57,82]]k=0whilek<5:subavg=0a=0whilea<6:subavg......
  • 《手把手教你》系列练习篇之15-python+ selenium自动化测试 -番外篇 - 最后一波啊!!!(详细
    1.简介 本来上一篇就是练习篇的最后一篇文章了,但是有的小伙伴私下反映说是做了那么多练习,没有一个比较综合的demo练练手。因此宏哥在这里又补存了一些常见的知识点进行练习,在文章最后也通过实例给小伙伴们或者童鞋们进行了一个登录模块的自动化测试的实例,其他的你可以照......
  • 《手把手教你》系列练习篇之14-python+ selenium自动化测试 -压台篇(详细教程)
    1.简介 本文是练习篇的最后一篇文章,虽然练习篇的文章到此就要和大家说拜拜了,但是我们的学习之路才刚刚开始。不要停下你的脚步,大步朝前走吧!比你优秀的人还在走着,我们有什么理由停下自己的脚步了,生命不止,学习亦是如此。好了,宏哥的毒鸡汤好喝吧,喝够了就开始学习吧。......
  • 一起学习javascript-进阶版函数(1)
    <script>  //举个例子 functionsum(x){    returnx+1;  }    functionadd(a,b,f){    varc=f(a)+f(b)    console.log("c的值为:"+c);  }  //给add函数传参  add(3,6,sum);// 这里的f相当于为//......
  • 一起学习javascript-函数(2)
    <script>  //变量作用域与解构赋值  functionf1(y){  varx=1;  x=x+2;  console.log(x+y);  console.log(x);  //因为变量x在函数f1中申明,在这里属于局部变量,所以x只能在f1中访问,f1执行完,x就销毁了}f1(2);//为了更直观一点,调用......