Python函数基础知识

目录

函数的基础

形参:

实参:

动态传参:

不容易理解的地方:

return   返回值

命名空间

函数名:

闭包

如何分辨闭包:

闭包的作用:

迭代器:

递归:

装饰器:

作用:

使用情景:

扩展(带参装饰器)

生成器的三种创建办法:

定义:

优点:

使用方式:

推导式

列表推导式 [结果 for 变量 in 可迭代对象 if 筛选]

字典推导式 {键 : 值 for 变量 in 可迭代对象 if 筛选}   结果是 

集合推导式 {结果 for 变量 in 可迭代对象 if 筛选}



 


 

函数的基础

  1. # 申明方法

             def 方法名(形参):

                    代码块

  1. # 调用方法

              方法名(实参)

def demo(name,age):
    print(f'(我是{name},我今年{age}岁))

#调用方法
demo('admin',12)

形参:

位置形参:def demo(name,age)

默认值形参:def demo(name,age=12)

二者可以混合使用,但是 位置形参 必须在默认值形参之前

实参:

位置实参:demo('admin',12)

关键字实参: demo('admin',age=12)

二者可以混合使用,但是 位置实参 必须在关键字实参之前

动态传参:

*参数   是位置参数

**参数  是关键字参数 方法接受到的是字典 

位置参数>动态位置参数>关键字参数>动态关键字参数

 

在形参上:*聚合   **聚合

在实参上:*打散   **打散

格式:

*args  接受所有位置参数

lis = [1,2,3,4]
def function(*args): # 聚合 将打散的 内容 再次组成元组形式 (1,2,3,4)
    print(args)
    print(*args)

function(lis)   #
function(*lis)    #打散   *lis实际上就是 1,2,3,4

#结果:
([1, 2, 3, 4],)
[1, 2, 3, 4]

(1, 2, 3, 4)
1 2 3 4
 

**wargs 接受所有关键字参数*******************************************

dir = {'a':1,'b':2,"c":3,"d":4}
def function(**kargs): #这里将其聚合成 {'a':1,'b':2,"c":3,"d":4}
    # print(**kargs)  #报错 TypeError: 'a' is an invalid keyword argument for this function
    # print(*kargs)  # a b c d
    print(kargs)     #{'a': 1, 'b': 2, 'c': 3, 'd': 4}

function(**dir)  # 其实这里的是  a=1  b=2   c=3   d=4
# function(*dir) #报错 TypeError: function() takes 0 positional arguments but 4 were given
# function(dir) #报错 TypeError: function() takes 0 positional arguments but 1 was given


#注意 :
dir = {'a':1,'b':2,"c":3,"d":4}
def function(**kwargs):
    print(**kwargs)   #报错 TypeError: 'a' is an invalid keyword argument for this function
function(**dir)

为什么打印 **kwargs 会报错的原因是:
字典前加 ** 会将字典打散为 a=1,b=2,c=3,d=4。 
传入 function(**kwargs)方法后会被 **kwargs 全部接受 聚合成 {'a': 1, 'b': 2, 'c': 3, 'd': 4}
而 print(**字典)   则会将 字典再次打散为关键字参数, 
但是print 的方法的参数中是没有 **kwargs(接受所有的关键字参数的) , 因此会报错
但是 print()方法中是有 *args 参数的,也就是为什么print(*args) 并不会报错

不容易理解的地方:

def func(**kwargs):         
   print(kwargs)

dic = {"1":1}
func(**dic)

#结果:  {'1': 1}

#减少写参数量
# dic = {"1":1}
# func(**dic)  等同于 func("1"=1) 虽然后者报错,但是在实际空间中是以这种方式存储

 

 

 

 

return   返回值

def demo(name,age):
    print(f'(我是{name},我今年{age}岁))
    return
    print("这句话不会执行")

#调用方法
demo('admin',12)

注意:在一个方法体内,return之后的代码都不会执行到

 

命名空间

内置命名空间(优先级最高)

存放Python解释器为我们提供的名字,其中就包括内置函数,list,dict,tuple,set,str,int等都属于内置空间的。  

全局命名空间

局部命名空间:函数内部

 

取值顺序:就进原则

globals()函数来查看全局作用域中的内容

locals()来查看当前作用域的内容

 

global 变量名  : 表示使用全局变量

 在局部变量中使用,当全局变量中没有该参数时,则会将局部变量升级为 全局变量   (不推荐)

nonlocal  变量名 : 找局部作用域中,离他最近的那层的变量给引用过来,。如果除全局外的局部都不存在改变量则会报错(No find)
 

函数名:

def func():
    pass

函数名可以当作值去赋值给变量

a = func
a()      #调用的是func()

函数名可以当作参数传递给函数

def func2(msg):
    print(msg)
func2(func)        #执行后的结果 打印的是 func方法的内存地址

函数名可以当作函数返回值,注意:返回值不能加括号

def func():
    def func_copy():
        pass
    return func_copy
print(func())        #打印的是 func_copy的内存地址
print(func()())         #打印的是 func_copy的方法内容

函数名可以当作元素存放一个容器里

def func():pass
def func2():pass
def func3():pass
li = [func,func2,func3]    #列表中存的其实是 每个方法的内存地址
for i in li:
    i()            #打印每一个方法

查看函数的内存地址 print(函数名)

print(func)

 

闭包

如何分辨闭包:

闭包必须是嵌套函数,内部函数在使用外部变量(非全局变量)就是闭包。

可以使用方法名.__closure__   查看该函数是否为闭包   只要返回值不是None,他就是闭包

def func():
    n = 1
    def func2():
        print(n)
    return func2     #注意这里的返回值 只是func2的方法名,也就是将其的地址返回。
func()()

闭包的作用:

1.可以读取到其他函数内部的变量

2.可以将变量保存在内存中,使其生命周期增强

3.可以保护其内部变量不受外界影响,不被修改,做到私有化

 

迭代器:

lst = [1,2,3,4,5]
l = lst.__iter__()   # 从一个可迭代对象转换成迭代器
print(l.__next__())    #从迭代器中读取第一个

可迭代对象:具有 __iter__()方法   

print(isinstance('列表等',Iterable))        判断是否为可迭代对象

迭代器:拥有 __iter__()方法和__next__() 方法

print(isinstance('列表等',Iterator))        判断是否为迭代器

# for循环机制
li = [1,2,3,4,5,6]
for i in li:
    print(i)

#  等价于
li2 = li.__iter__()
while True:        # 循环:
    try:        
        print(li2.__next__())    # 获得下一个值:
    except StopIteration:
        break             # 遇到StopIteration就退出循环

 

递归:

其实就是方法自己本身再调用自己

# 一个简单的递归
def fun(n):
    print(n)
    n += 1
    fun(n)

fun(1)

#结果会报 
#  RecursionError: maximum recursion depth exceeded while calling a Python object

递归注意事项:有进也有出

递归的最大深度:官方定义是 1000,而实际上测试 只是 998

# 递归求阶乘
def factorial(n):
    if n == 1 :
        return 1
    else:
        return n*factorial(n-1)

递归的深度可以修改:

import sys
sys.setrecursionlimit(int num)   #调用sys系统模块

 

 

装饰器:

装饰器的本质其实就是 闭包

举一个简单的装饰器

import time

def fun(a, b):
    print('我是fun',a,b)

def test(fun):
    def time_fun(*args,**kwargs):
        star = time.time()  #时间戳
        time.sleep(2)   #睡眠两秒钟
        fun(*args,**kwargs)
        end = time.time()   #时间戳
        print(end-star)
    return time_fun   #闭包功能

fun = test(fun) #将 time_fun函数的内存地址赋值给fun
fun(1,2)    #虽然看见的是fun函数,但是实际走的却是time_fun函数

# 结果:
# 我是fun 1 2
# 2.000408411026001

可以使用@符 升级为:

@ 后跟 装饰器的名称          整体等同于   被装饰函数名称 = 装饰器名称(被装饰函数名称)

import time

def test(fun):
    def time_fun(*args,**kwargs):
        star = time.time()  #时间戳
        time.sleep(2)   #睡眠两秒钟
        fun(*args,**kwargs)
        end = time.time()   #时间戳
        print(end-star)
    return time_fun   #闭包功能

@test    #fun = test(fun)
def fun(a, b):
    print('我是fun',a,b)


fun(1,2)    #虽然看见的是fun函数,但是实际走的却是time_fun函数


#结果相同

作用:

在开发阶段要满足 开放封闭 原则   (开放是指:扩展功能开放。  封闭是指:源码封闭,不允许其他人修改)

装饰器可以实现不改变调用函数名的情况下,实现对本来函数的功能实现扩展

使用情景:

测试函数的运行时间

登陆校验

扩展(带参装饰器)

import time

def all(name):
    def test(fun):
        def time_fun(*args, **kwargs):
            star = time.time()  #时间戳
            time.sleep(2)   #睡眠两秒钟
            print(name)
            fun(*args, **kwargs)
            end = time.time()   #时间戳
            print(end-star)
        return time_fun   #闭包功能
    return test

@all('a')     #fun = all('a')(fun)      fun(1,2)
def fun(a, b):
    print('我是fun', a, b)

fun(1,2)    #虽然看见的是fun函数,但是实际走的却是time_fun函数

 

1.生成器的三种创建办法:

    1.通过生成器函数  关键字 yield

def func():
    print(1)
    yield 1
    print(2)
    yield 2

l = func()
print(l.__next__())
print(l.__next__())
# print(l.__next__())   #报错,StopIteration

    2.通过生成器表达式创建生成器

生成器表达式:

结果 for  变量 in 可迭代对象 if 筛选)  #重点是小括号

get1 = ( i for i in range(10) if i%2 == 0)
print(get1)

#结果:<generator object <genexpr> at 0x0000017DB9320938>

    3.通过数据转换

 

2.生成器函数定义:

函数中包含了yield的就是生成器函数

注意:生成器函数被执行,获取到的是生成器,而不是函数的执行

yield from

def func():
    li = [1,2,3,4]
    yield from li

f = func()
for i in f:
    print(i, end=",")

#结果:1,2,3,4

 

 

3.生成器的优点:

li = []
def func():
    for i in range(1000):
        li.append(i)

print(li)

#比较浪费空间,一次性取完

def func():
    for i in range(1000):
        yield i

f = func()
for i in range(10):
    print(f.__next__())

#需要多少取多少

 

4.使用方式:

1. __next__()

get1 = ( i for i in range(10) if i%2 == 0)  #生成器就是一个自己写的迭代器
#方式一:
for i in get1:
    print(i,end=" ")
#方式二:
for i in range(5):
    print(get1.__next__(),end=" ")


#结果:0 2 4 6 8 

2.send(值)   给上一个yield位置传一个值  #send其实有next方法和传值方法

def func():
    for i in range(10):
        print(i)
        l = yield "你好"
        print(l)

f = func()
print(f.__next__())    #第一次执行,会执行完yield,暂留在那里
print(f.send("我不好"))    #使用send会将参数赋值给上一次暂留位置,也就是程序中的l ,然后继续执行,知道下一个yield暂停

#结果:
# 0
# 你好
# 我不好
# 1
# 你好

注意点:send在使用时,如果没有先使用 __next__方法,则send()方法中的参数必为None 

yield和return的区别:

yield和return的效果是一样的,但是还是有点区别

  yield是分段来执行一个函数    yield 后面跟的相当于一个输出语句

  return是直接停止这个函数

send和__next__()一样都可以让生成器执行到下一个yield

send和__next__()区别:

send 和 next()都是让生成器向下走一次

send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器的时候不能使用send()

第一次调用的时候使用send()也可以但是send的参数必须是None
 

 

 

5.推导式

1.列表推导式 [结果 for 变量 in 可迭代对象 if 筛选]

li = [i for i in range(10) if i%2 == 0]
print(li)

#结果:[0, 2, 4, 6, 8]

2.字典推导式 {键 : 值 for 变量 in 可迭代对象 if 筛选}   结果是 

li_1 = [1,2,3,4]
li_2 = [1,2,3,4]
dic = {li_1[i]:li_2[i]for i in range(len(li_1))}
print(dic)

#结果:{1: 1, 2: 2, 3: 3, 4: 4}

3.集合推导式 {结果 for 变量 in 可迭代对象 if 筛选}

set1 = { i for i in range(10) if i%2 == 0}
print(set1)

#结果:{0, 2, 4, 6, 8}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值