首页 > 编程语言 > 详细

python函数

时间:2020-01-09 22:34:18      阅读:82      评论:0      收藏:0      [点我收藏+]

函数的优势:
1,减少代码的重复性。

2,使代码可读性更好。
自定义函数:
def 关键字 空格 函数名:英文冒号
函数体
执行函数 函数名+()
函数是以功能为导向的。
函数的返回值:
return 作用:1)函数中遇到return 结束函数,下面代码不执行,相当于while循环中的break。
         2)将函数里面的值返回给函数的执行者(调用者)。

1)举例
def login():
  print(111)
  print(222)
  return 
  print(333)
login() #函数执行者
2)举例:
函数的初识:
def login():
  print(111)
  print(222)
  return 666    
print(login())# 666

return使用方法总结:

第一种情况:只有return 什么都没写 ,或者函数中没有return,函数执行者返回 None
      什么是None:python为了节省内存,对于[],{},(),‘‘,set()只要是空的 都保存在None中,是个独立的数据类型。
第二种情况:return None(将None写出来)
第三种情况:return 单个值(这个值是什么类型,返回的值给执行者就是什么类型)

def login():
  a = 2
  b = 3
  return a
print(login()) # 2

第四种情况:return 多个值(以元组的形式返回给函数的调用者)

函数的使用:

常用方法计算元素长度:
l1 = [1,2,3,4,1,6,9,10]
print(len(l1))
自定义函数计算方法:
def my_len():
  l1 = [1,2,3,4,1,6,9,10]
  count = 0
  for i in l1:
    count +=1
  return count
print(my_len())
*************************************************
函数的参数:
举例说明:
def my_len(a): #形式参数 形参
  l1 = [1,2,3,4,1,6,9,10]
  count = 0
  for i in l1:
    count +=1
  return count
l1 = [1,2,3,4,1,6,9,10]
my_len(l1) #实际参数 实参

实参角度:三种
位置参数 :实参和形参数一一对应
举例说明:
def tes(a,b,c):
  print(111)
  print(a,b,c)
tes(22,‘alex‘,[11,22,33])
关键字参数 :也得一一对应 实参和形参数量相等,实参的顺序可以变(可以理解为分别赋值)
举例说明:
def func(x,y):
  print(x,y)
func(y=333,x=444 ) #也可以不用写x= y= 直接写值也行
混合参数(位置参数,关键字参数):整体数量要一一对应,位置参数必须在前面 多个关键字参数位置可以互换,不用一一对应
举例说明:
def func(x,y,z):
  print(x,y,z)

func(111,222,z=555)

形参角度:三种
位置参数:相对于实参位置而言 也得一一对应

默认参数: 默认参数必须放在 形参的位置参数后面,不传值就是默认值, 传值则覆盖默认值。
举例说明:
def func2(x,y,z=100):#默认参数
  print(x,y,z)
func2(1,2)

def func2(x,y,z=100):
  print(x,y,z)
func2(1,2,3000) #为z赋值

动态参数:用户传入到函数中的实参数量不定时,或为以后拓展,此时要用到动态参数。
此时要用到动态参数*args,**kwargs(这个英文可以改,他们只是个变量,也叫万能参数)
*args接受的是所有的位置参数。形成元组
**kwargs接受的是所有的关键字参数。形成字典
举例说明:
def func1(*args,**kwargs):
  print(args)
  print(kwargs)
func1(1,2,3,4)
func1(x=4,y=5,z=6)
func1(1,2,3,x=4,y=5,z=6)
动态参数的位置:
*args:
  位置参数 *args 默认参数
**kwargs:
  放在最后面:位置参数 *args 默认参数,**kwargs.
举例说明:

def func1(a,b,*args,sex=,**kwargs):
  print(a)
  print(b)
  print(args)
  print(sex)
  print(kwargs)
func1(1,2, 5,6,7,8,9,sex=,x=6,y=5,name=alex)

补充:
#如果函数的默认参数是可变的数据类型,无论使用多少次默认参数,都是一个,并且如果默认参数是{} [] ()等 实参位置不用加索引
def extendlist(val,list=[]):
  list.append(val)
  return list
list1=extendlist(10)
list2=extendlist(123,[])
list3=extendlist(‘a‘)
list=[10,‘a‘] #默认列表
list=[123,] #新列表
list=[10,‘a‘] #一变都变,默认列表

print(‘list1=&s‘ %list1)

*的魔性用法:将可迭代对象 直接将每个元素加入到args中

在函数的定义的时候,*代表聚合和聚合
举例说明:

def func3(*args,**kwargs):#函数的定义,*用意是聚合
  print(args)
l1=[1,2,3]
l2=[11,21,32]
func3(*l1,*l2)# *的用意是打散

def func3(*args,**kwargs):
  print(args)
  print(kwargs)
dic1 = {name:alex}
dic2 = {age:1000}
func3(**dic1,**dic2) # 是两个*

补充:

def func(*args,**kwargs):在这是聚合
  print(args) # (1,2,3)
  print(*args) # 1 2 3 在这又打散
func1(*[1,2,3],**{‘name‘:‘alex‘}) 在这* 是打散

def func(*args,**kwargs):
  print(*kwargs) # (1,2,3)#print函数无法接受**kwargs关键字参数->print(‘name‘=‘alex‘)
  print(kwargs) #但是你加* 会输出字典的键。
func(*[1,2,3],**{‘name‘:‘alex‘,‘ags‘:18})

*处理剩下的元素
  *除了在函数中可以这样打散,聚合外,函数外还可以灵活的运用:

# 之前讲过的分别赋值
a,b = (1,2)
print(a, b) # 1 2
# 其实还可以这么用:
a,*b = (1, 2, 3, 4,)
print(a, b) # 1 [2, 3, 4]

名称空间,加载顺序等

当程序运行时,代码从上至下以此读取,遇到变量与值,它会在内存中开辟一个空间,存放变量与值得内存地址的对应关系。
这样存储变量与值得对应关系的空间叫做名称空间(命名空间)又称全局名称空间

当解释器遇到函数时,它会将函数名存储在内存中,但是对于函数体漠不关心。
当函数执行时,它会通过函数名找到函数体,然后将函数体里面的变量等对应关系存放在一个临时开辟的空间中,随着函数的结束,临时的空间关闭,这样的空间叫做临时名称空间。
另一点:函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空

内置名称空间:代码需要解释器来读取,运行需要添加到内存
如len() print() input()

名称空间:
内置名称空间
全局名称空间
局部名称空间

加载顺序:
内置名称空间 --> 全局名称空间(程序运行时)--> 临时(局部)名称空间(函数调用时执)

作用域:
全局作用域:内置名称空间,全局名称空间
局部作用域:局部名称空间

取值顺序(只能单项):临时(局部)名称空间 --> 全局名称空间 --> 内置名称空间
l    local
E  eclose
G  global
B   built-in
举例说明:

sum = 666 #global
def func1():
    sum = 555 #eclose
    print(sum)
    def inner():
        sum = 111 #local
      print(sum)
    inner()
func1()

检测那些变量是全局的那些事局部的,globals() locals()
#locals():函数会以字典的类型返回当前位置的全部局部变量 (可以检查局部,也可以检查全局)。
#globals():函数以字典的类型返回全部全局变量。

def extendList(val,list=[]):
    list.append(val)
    print(locals())
    return list         #这个list是局部的
ret = extendList(1)   #但是list返回的值是全局的

print(globals())

函数的嵌套:主要是要明白数据的执行顺序。

举例说明:
def func1():
    a =666
    print(666)

def func2():
    name = adf
    print(name)
    func1()
print(333)
func2()
print(555)

**********************global nonlocal 关键字*******************

在全局名称空间里得到局部名称空间的变量用:
1, return
举例说明:

def func1():
    name=alex
    print(name)
    return name
ret = func1()
print(ret)

2,global :1)在局部作用域中声明一个全局变量。

def func1():
    global name
    name=alex
func1()
print(name)

     2)在局部作用域中更改一个全局变量(在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字))

name = 小旋风
def func1():
    global name
    name=男神
func1()
print(name)

补充:局部作用域对全局作用域的变量(此变量只能是不可变的数据类型)只能进行引用,而不能进行改变,只要改变就会报错,对于可变的数据类型,函数中如果对其进行操作,改变全局变量不用引入global

l1 =[1,2,3]
def func1():
    l1.append(666)
func1()
print(l1)

**nonlocal如果上一层没有变量 就会报错(在局部作用域如果想对父级作用域的变量进行改变时,需要用到nonlocal)

1,不能改变一个全局变量,但是可以改变局部变量
在局部作用域汇中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改
并且引用的哪层,从那层及以下此变量全部发生改变。
举例说明:

def func1():
    name = 男神
    print(name)
    def inner():
        nonlocal name
        name = 小旋风
        print(name)
    inner()
    print(name)
func1()

def add_b():
    b =42
    def do_global():
        b =10
        print(b) #10
        def dd_nonlocal():
            #nonlocal b #10
            b = b + 20 #30
            print(b) # 30
        dd_nonlocal()
        print(b) # 30
    do_global()
    print(b)# 42
add_b()

补充:

count = 1
def func4():
    count = count + 1 #这样会报错
    print(count)
func4()
#局部只能引用全局的变量,不能修改,如果想修改,加global。
count = 1
def func4():
    global count
    count = count + 1 #这样就不会报错
    print(count)    
func4()
#子函数只能引用父函数的变量,不能修改,如果想修改,加nonlocal。
def func4():
    count = 3
    def inner():
        nonlocal count #加个nonlocal之后就不会再报错,否则会报错。
        count = count + 1
        print(count)
    inner()    
func4()

*************************函数名的应用***********************

什么是函数名:
1,他是一个变量 直接打印函数名得到的是函数的内存地址,加个()就执行
2,函数名能进行赋值运算。

def func1():
    print(666)
f1 =func1
f1()

3,函数名可以作为函数的参数

def func1():
    print(666)

def func2(x):
    x()
    print(555)
func2(func1)

4,函数名可以作为容器数据类型的元素。

def func1():
    print(666)

def func2():
    print(222)

def func3():
    print(111)

def func4():
    print(777)

l1 = [func1,func2,func3,func4]
for i in l1:
    i() # 一一全部执行

5,函数名可以作为函数的返回值

def func1():
    print(666)

def func2(x):
    print(222)
    return x
ret = func2(func1)

*****************************闭包*************************

内层函数对外层函数非全局变量的引用就叫闭包
判断是不是闭包,是函数名.__closure__返回的是None则不是闭包,返回cell则是。

def func1():
      name = 小旋风
      def inner():
          print(name)
      inner()
      print(inner.__closure__)判断是否是闭包,如果返回cell 是 None否  
func1()
另一例子:比较又迷惑性,这个也是闭包  相当于 在函数中name重新赋值 
def func1(x):
      def inner():
          print(x)
      inner()
      print(inner.__closure__)
name = 小旋风      
func1(name)

闭包有什么用?

当执行一个函数时,如果解释器判断此函数闭包存在,这样函数就有一个机制,闭包的所在的临时名称空间不会随着函数的执行完毕而消失。

比较有意思的一道题:

def func():
    
    def func1():
        name = 小旋风
    def func2():
        nonlocal name 
        name = 男神
    def func3():
        global name
        name = 女神
    name = 小屁孩
    
    func1() 
    print(name) 
    func2()
    print(name) 
    func3()
    print(name) 
func()
print(name) 

******************************装饰器********************************

import time
可以使用 time.time()计算时间 time.sleep()控制时间及停留多少时间后再执行。
简单装饰器

import time
def login():
    time.sleep(1)
    print(同一个世界....)
def timmer(f):
    def inner():
        start_time  = time.time()
        f()
        end_time = time.time()
        print(此函数的执行时间%s % (end_time-start_time))
    return inner
login = timmer(login)
login()

import time
def timmer(f): #装饰器
    def inner():
        start_time  = time.time()
        f()
        end_time = time.time()
        print(此函数的执行时间%s % (end_time-start_time))
    return inner
@timmer  #login = timmer(login) 加一个‘@’键
def login():
    time.sleep(1)
    print(同一个世界....)

login()

函数带返回值的装饰器(万能装饰器)

import time

def timmer(f):  f = login  #具有通用性
    def inner(*args,**kwargs): #函数‘*’聚合 #args(2,3)
        start_time  = time.time()
        ret=f(*args,**kwargs) #实参   执行 ‘*’打散 login() *(2,3) 2,3 
        end_time = time.time()
        print(此函数的执行时间%s % (end_time-start_time))
        return ret
    return inner
@timmer   #login=timmer(login)  inner 此login是新变量
def login(a,b):
    time.sleep(1)
    print(同一个世界....)
    return 666
login(2,3)  #inner(2,3)

万能装饰器雏形:

def wrapper(f):
    def inner(*args,**kwargs):
         ‘‘执行被装饰函数之前的操作‘‘‘‘
        ret = f(*args,**kwargs)
         ‘‘执行被装饰函数之前的操作‘‘‘‘
        return ret
    return inner

@wrapper
f()

*******************函数的有用信息**************************

from functools import wraps #引入模块

def wrapper(f):
    @wraps(f) #在这边加入
    def inner(*args,**kwargs):
        ‘‘‘执行前‘‘‘
        ret = f(*args,**kwargs)
        ‘‘‘执行后‘‘‘
        return ret
    return inner

@wrapper  
def login(username,password):
    ‘‘‘ 
    此函数需要用户名,密码两个参数,完成的是登录的功能
    ‘‘‘
    print(登录成功...)
    return True
    
login(1,2)
print(login.__name__) #打印函数名
print(login.__doc__) #打印函数内容

********************带参数的装饰器****************************

import time

def time_out(flag1):#带参数的装饰器 #flag1= flag
    def timer(f)
        def inner(*args,**kwargs):
            if flag:
                star_time = time.time()
                time.sleep(2)
                ret = f(*args,**kwargs)
                end_time = time.time()
                print(执行时间%d %(end_time-star_time))
                return ret
            else:
                ret = f(*args,**kwargs)
                return ret
        return inner
    return timer
flag =True
@time_out(flag) #1,先执行 time_out(flag)函数 =timer 2,@与timer结合,形成熟悉的装饰器@timer
def func1():
    print(111)

@time_out(flag)
def func2():
    print(222)
@time_out(flag)
def func3():
    print(333)

func1()
func2()
func3()

***********************多个装饰器装饰多个函数******************

def wrapper1(func): #func = f函数名
    def inner1():
        print(wrapper1,before func)#2
        func()
        print(wrapper1,after func)#4
    return inner1
    
def wrapper2(func): #func=inner1
    def inner2():
        print(wrapper2,before func) #1
        func() #执行inner1()
        print(wrapper2,after func)#5
    return inner2
    
@wrapper2  #f = wrapper2(f) 里面的f新变量=inner1 外面的函数是最新变量=inner2
@wrapper1  #f=wrapper1(f) 里面的f函数名,外面的f新变量=inner    (两个装饰器,先执行距离最近的装饰器  在执行其他的 也就是由进到远)
def f():
    print(in f)#3
    
f() #inner2()

补充知识点:

装饰器的本质是闭包
开放封闭原则(写代码最好不要写死):允许代码扩展,添加新功能,如果函数交给其他人使用,所以进行封闭

#局部作用域可以对全局作用域的变量进行引用:举例说明
count = 1
def func1():
    print(count)
func1()
#函数内部如果有变量名与全局变量名相同,且对此变量进行改变,python就会将你引用的变量视为局部定义的变量,但是局部没有定义,那么他会报错。
count = 1
def func1():
    count = count + 1 #会报错
    print(count)
func1()
#这种情况也会报错,要理解,都是一个道理
def func1():
    count = 3
    def inner():
        count=count+1
    inner()
    print(count)
func1()
在函数中使用global 要放在函数体的第一个位置
flag = True
def func1(): #会报错
    if flag:
        print(333)
    global flag
    flag=False
func1()

flag = True
def func1(): #这样就不会报错
    global flag
    if flag:
        print(333)
    flag False
func1()#for if while 没有开辟临时空间,只有函数时才开启临时空间,只能对外面的数据进行引用,不能更改。
flag = True
while flag:
    print(333)
    flag = False
    print(222)
函数中如果使用global加一个变量,必须是第一次使用这个变量,也就是在前面。

***************************迭代器**************************
可迭代对象定义:内部含有__iter__
可迭代对象转为迭代器:可迭代对象.__iter__()
迭代器定义:内部含有__iter__() 和__next__()
判断是不是迭代器:__iter__在不在dir(对象中)
         isinstance方法检测。
迭代器优点:节省内存
      惰性机制
      单项不可逆

 

可迭代对象:内部含有__iter__方法的就是可迭代对象,遵循可迭代协议。
  用dir函数可以检测:
    print(dir(‘123‘))#返回的是列表
    print(‘__iter__‘ in dir([1,2,3])) 用这个方法判断列表中是否存在__iter__

迭代器:可迭代对象通过.__iter__()可以转化成迭代器,遵循可迭代协议,其实它也是数据类型。

内存占用非常小;节省内存;满足惰性机制,在循环到第四次时,再次循环它会从第5次继续执行;迭代器是未来做数据类型;取值过程单项不可逆的首选方式
l = [1,2,3]
l_obj = l.__iter__() #生成迭代器
print(l_obj)
print(l_obj.__next__())

迭代器取值方法:

1).__next__()
2) for循环:for循环其实就是将可迭代对象,转化成迭代器,通过.__next__()来实现元素读取。
需要注意一点:

l = [1,2,3]
l_obj = l.__iter__()
print(l_obj.__next__())#在这里执行.__next__()后再 执行for循环 执行的是剩余的内容,符合迭代器的惰性机制。
print()
for i in l_obj:
  print(i) #只能打印出2 3

怎样判断是否是迭代器:
1)内部还有.__iter__()和.__next__()方法的就是迭代器。
2)  from collections import iterable
  from collections import iterator
  print(isinstance(‘123‘,iterable))#判断是否是可迭代对象 isinstance可以判断所有属性,可以判断任意数据类型。
  print(isinstance(‘123‘,iterator))#判断是否是迭代器

实际上可迭代对象是不可以一个一个的一次取值的,因为他没有__next__方法,但是
for循环提供一个机制:
1)将可迭代对象转化成迭代器
2)利用__next__进行取值。
3)用try异常处理方法防治报错。
如下例子:模拟for循环机制

l = [1,2,3,4,5]
l_obj =l.__iter__()
while True:
    try:
        print(l_obj.__next__())
    except StopIteration:
        break

*************************生成器******************************

生成器的本质也是迭代器,生成器是自己用python写的迭代器。
1,通过生成器函数构建。
2,通过生成器推导式构建。

1)函数构建生成器
def func1(): #函数体就是生成器函数
print(666)
yield 222
yiels 777
g_obj = func1() #生成器对象 在下面通过func1().__next__()执行这个函数
print(g_obj.__next__()) #生成器也是.__next__()取值 一个yield对应一个.__next__()
print(g_obj.__next__())
生成器作用的说明举例:
def cloth2():
for i in range(1,10001):
yield ‘衣服%s‘ %i

g = cloth2()
for i in range(1,51):
print(g.__next__())

for i in range(1,151):
print(g.__next__())

#send的用法
def func1():
count = yield 222
print(count)
yield 777
yield 888
g_obj = func1()
print(g_obj.__next__())
print(g_obj.send(2))
1)send 具有next功能,一次只能执行一个yield
2)send 可以给上一个yield传值 传什么值都行
3)第一个取值不能使用send
4)最后一个yield不会得到send的值

2)推导器构建

python函数

原文:https://www.cnblogs.com/xiao-xuan-feng/p/12173041.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!