首页 > 编程语言 > 详细

python学习之函数

时间:2019-03-22 01:15:21      阅读:190      评论:0      收藏:0      [点我收藏+]

(课前三剑客)

什么是函数:
  1. 函数是具备某一功能的工具
为什么用函数:
  1. 程序组织结构不清晰,可读性差
  2. 代码冗余
  3. 可扩展性差
如何使用函数
  函数的使用必须遵循的原则:先定义,后调用

1、语法

       def 函数名(参数1, 参数2,......)
               """文档注释"""
                code.......
               return 返回值
        
       def:定义函数的关键字
       函数名:指向函数的内存的地址,加上()就可以执行函数内的代码
  参数:函数的调用者为函数体传值的媒介,在python内参数无需声明类型,如果无参,就不用传输参数
       代码块:函数体功能的具体实现
       返回值:代码块执行的结果
  
  定义阶段:只检测语法,不执行代码
  调用阶段:运行函数体代码
 
技术分享图片
#定义函数的三种形式
#1.1 无参函数
# def foo():
#     print(from foo)
# foo()

#1.2 有参函数
# def bar(x,y):
#     print(x,y)
# bar(1,2)

#1.3 空函数
# def func():
#     pass
定义函数三种方式:有参,无参,空函数
技术分享图片
# 调用函数的三种形式
#2.1 #语句形式
# def foo():
#     print(‘from foo‘)
# foo()

#2.2 表达式形式
# def foo(x,y):
#     res = x + y
#     return res
#
# res=foo(1,2) #表达式形式
# res1=foo(1,2)*100
# print(res1)

#2.3 可以当作参数传给另外一个函数
# def max2(x,y):
#     if x > y:
#         return x
#     else:
#         return y

# 1 2 3
# res=max2(max2(1,2),3)
# print(res)
调用函数的三种方式

  return作用:

    1. 返回值,没有类型和个数限制,返回多个值时,调用得到一个元组,不写返回None

    2. 结束函数执行

 2、函数参数

  分类:

    1. 形参:在定义函数阶段,括号内指定的变量名称

    2. 实参:再调用函数阶段,括号内传入的值,即实参本质就是‘值’

    关系:在调用时,会将实参值赋给形参,调用结束后就失效了

   形参与实参的具体分类:
    1. 位置参数
      形参:在定义函数阶段,按照从左到右的顺序依次定义的形参。
      实参:调用函数从左到右的顺序依次传入的参数。
      强调:位置形参必须被传值,不能多不能少,且在调用时位置实参与位置形参一一对应
技术分享图片
# def foo(x,y):
#     print(x,y)
# foo(1,2)
# foo(1,2,3)  # 报错
# foo(1)    # 报错
View Code

    2. 关键字参数

      关键字实参:在调用函数阶段,按照key=value的形式指名道姓为形参传值。
        注:可以完全打乱顺序,但必须指定形参传值
          可以混合使用,但位置实参必须放在关键字实参前面,且不能对同一形参重复赋值
技术分享图片
# def foo(x,y):
#     print(x,y)
# foo(1,2)
# foo(x=1,y=2)
# foo(1,y=2)
 
# foo(12,x=1) #报错,不能对同一参数多次赋值,
# foo(y=2,1)  #报错,位置参数必须放在关键字参数之前,
# foo(y=2, x=1)
View Code

    3. 默认参数:

      默认形参:定义函数阶段,就已经为某个形参赋值

        注:在定义阶段已经赋值,意味着调用阶段可以不用为其赋值

          位置形参不许放在默认形参之前;

          默认参数,通常都是不可变类型

技术分享图片
# def foo(x,y=2):
#     print(x,y)

# foo(1)
# foo(1,3)
# foo(y=3,x=1)

# def foo(y=2,x): # 报错,默认参数必须放在位置参数后面
#     print(x,y)

# def register(name,hobby,l=[]):
#     l.append(hobby)
#     print(‘%s 的爱好为 %s‘ %(name,l))
#
# register(‘aaa‘,‘study‘)
# register(‘bbb‘,‘play‘)
# register(‘ccc‘,‘sing‘)

#结果:
# aaa 的爱好为 [‘study‘]
# bbb 的爱好为 [‘study‘, ‘play‘]
# ccc 的爱好为 [‘study‘, ‘play‘, ‘sing‘]
View Code

    4. 可变长度的参数:

      实参:调用函数时,传入的实参值个数不固定

      方法:使用 * 和 ** 

        *:形参中带*,会在调用函数时,溢出位置实参保存成元组的形式,赋值给*后面的变量名

         **:形参中带**,会将调用函数时,溢出关键字实参保存成字典的形式,赋值给**后面的变量名

 

        *:实参中带*,在传值前都会将其打散成位置参数,进行赋值

         **:实参中带**,在传值前,都会将其打散成关键字参数,进行赋值(打散的主要是字典) 

技术分享图片
在形参中的*和**# def foo(x,y,*z): 
#     print(x,y,z)
#
# foo(1,2,3,4,5,6) 
#
# 输出结果:
# 1,2,(3,4,5,6)

# def foo(x,y,**z): 
#     print(x,y,z)
#
# foo(1,y=2,a=1,b=2,c=3)
#
# 输出结果:
# 1,2,{‘z‘:3,‘a‘:1,‘b‘:2}

在实参中的*和**# def foo(x,y,*z): #z=(3,4,5,6)
#     print(x,y,z)
# foo(1,*[2,3,4,5,6]) # foo(1,2,3,4,5,6)
#
# 输出结果:
# 1,2,(3,4,5,6)

# def foo(x,y,z):
#     print(x,y,z)
#
# foo(**{‘y‘:111,‘x‘:222,‘z‘:333}) #foo(z=333,x=222,y=111)

# 规范:在形参中带*与**的,*后的变量名应该为args,**后跟的变量名应该时kwargs
# def foo(*args,**kwargs): #args=(1,2,3,4,5) kwargs={‘a‘:1,‘b‘:2,‘c‘:3}
#     print(args)
#     print(kwargs)
# foo(1,2,3,4,5,a=1,b=2,c=3)
View Code

     5. 当想要将传给一个函数的参数格式原封不动转嫁给其内部的一个函数,应该使用以下格式:

技术分享图片
# def bar(x,y,z):
#     print(x,y,z)
#
# def foo(*args,**kwargs): #args=(1,2) kwargs={‘z‘:3}
#     bar(*args,**kwargs)  #bar(*(1,2),**{‘z‘:3})  #bar(1,2,z=3)
# foo(1,2,z=3)
View Code

    6. 命名关键字参数,放到*与**之间的参数。命名关键字参数必须按照key=value的形式传值

技术分享图片
# def foo(*,x=1,y):
#     print(x)
#     print(y)

# foo(y=2222,x=1111)
# foo(y=2222)
View Code
技术分享图片
def foo(x, y=1, *arg, m, n, **kwargs): 
    pass

# 对应的参数类型:
#    x: 位置参数,
#    y: 默认参数,
#     m和n: 是命名关键子参数,
#    *与**: 可变长度参数
完整的函数参数形式

3、 函数对象

  函数是第一类对象:指的是函数名指向的值(函数)可以被当作数据去使用

  使用方法:

    1. 可以被引用

    2. 可以被当作参数传给另一个参数

    3. 可以当作一个函数的返回值

    4. 可以当作容器的元素

技术分享图片
def func(): # func=函数的内地址
    print(from func)

# 1. 可以被引用
# x=age
# print(x,age)

# f=func
# print(f)
# f()

# 2. 可以当作参数传给另外一个函数
# def bar(x):
#     print(x)

# bar(age)
# bar(func)

# 3. 可以当作一个函数的返回值
# def bar(x):
    # return x

# res=bar(age)
# print(res)

# res=bar(func)
# print(res)

# 4. 可以当作容器类型的元素
# l=[age,func,func()]
# print(l)
示例

  函数嵌套分为两大类:

    1. 函数的嵌套调用:在调用函数过程中,又调用其它的函数

    2. 函数的嵌套定义:一个函数内部又定义了另一个函数

技术分享图片
# def bar():
#     print(‘from bar‘)
#
# def foo():
#     print(‘from foo‘)
#     bar()
#
# foo()


# def f1():
#     print(‘from f1‘)
#     def f2():
#         print(‘from f2‘)
#         def f3():
#             print(‘from f3‘)
#         f3()
#     f2()
#
# f1()
View Code

4、名称空间与作用域

  名称空间:用来存放名字与值内存地址绑定关系的地方(内存空间),

         但凡查找值一定通过名字,访问名字必须去查找名称空间

    分类:

      1. 内置名称空间:存放python解释器自带的名字。

      2. 全局名称空间:存放文件级的名字。

      3. 局部名称空间:存放函数内的名字

    生命周期:

      1. 内置名称空间:解释器启动就生效,关闭就失效了

      2. 全局名称空间:解释器执行python文件时生效,执行完后则失效

      3. 局部名称空间:只有在调用函数时临时产生该函数的局部名称空间,调用结束后则失效

    加载顺序:内置 -> 全局 -> 局部

    查找名字的顺序:

      基于当前所在位置往上查找:

        如果在局部:查找顺序:局部 -> 全局 -> 内置

        如果在全局:查找顺序:全局 -> 内置

技术分享图片
# x=111
#
# def f1():
#     x=222
#     def f2():
#         def f3():
#             # x=444
#             print(x)
#         x=333
#         f3()
#     f2()
# f1()

# 结果:333
View Code

    强调:名字的查找顺序,在函数定义阶段就已经固定死了,与函数的调用位置无关。

       也就是说无论在任何地方调用函数,都必须回到当初定义函数的位置去确定名字的查找顺序

技术分享图片
#示例一:
# x=111
# def outer():
#     def inner():
#         print(‘from inner‘,x) # x访问的时全局名称空间中x
#     return inner
#
# f=outer()
# # print(f)
#
# x=222
# f()    #结果:from inner 222

# 示例二:
# x=111
# def outer():
#     def inner():
#         print(‘from inner‘,x) # x访问的时全局名称空间中x
#     return inner
#
# f=outer()
#
# # x=222
# def func():
#     x=333
#     f()
#
# x=444
# func()    #结果:from inner 444

#示例三:
# x=111
# def outer():
#     def inner():
#         print(‘from inner‘,x) # x是来自于当前层的名字
#         x=222
#     return inner
#
# f=outer()
#
# f()   #结果:报错,变量必须是先声明,后调用
示例

  作用域:指的是作用的范围。

    全局作用域:包含内置名称空间,全局名称空间,特点是全局有效

    局部作用域:包含局部名称空间,特点是局部有效,临时存储,函数调用结束后就失效了

    使用方式:

      global:在局部声明一个名字来自与全局作用域,可以用来在局部修改全局不可变类型。

      nonlocal:声明一个名字来自当前层外一层作用域,不能修改全局变量,可以在局部修改

           外层函数不可变类型,如果没找到,会一直找到最外层,还是没有,就报错。

技术分享图片
# x=1
# def foo():
#     global x
#     x=2
#
# foo()
# print(x)    #结果:2

x=0
def f1():
    x=111
    def f2():
        nonlocal x
        x=222
    f2()
    print(x)

f1()    #结果 222
# 如果x=111注释掉,则会报错
View Code

5、闭包

  什么是闭包?

    闭:闭包函数指是定义在一个函数内部的函数 。

    包:该内部函数包含对外层函数作用域名字的引用

    需要结合函数对象的概念将闭包函数返回到全局作用域去使用,从而打破函数的层级限制

  为什么要用闭包?

    提供一种为函数体传值的解决方案

6、装饰器

   什么是装饰器?

    用来为被装饰对象添加新功能的工具 

    装饰器本身可以是任何可调用对象,被装饰的对象也是任意可调用对象 

  为什么要装饰器?

    开放封闭原则:封闭指的是对修改封闭,对扩张开放

    装饰器的实现必须遵循两大原则:

      不修改被装饰对象的源代码

      不修改被装饰对象的diao‘yong‘fang‘sh    

  怎么用装饰器? 

    调用函数时,实际上执行的是把被装饰函数当作参数传入的装饰器函数,  

技术分享图片
def outter(func):
    def wrapper(*args,**kwargs):
        #在调用函数前加功能
        res=func(*args,**kwargs) #调用被装饰的\也就是最原始的那个函数
        #在调用函数后加功能
        return res
    return wrapper

@outter #解释语法时,执行index=outter(index),index=wrapper,执行时,wrapper()
def index():
    print(welcome to index page)
    time.sleep(3)

index()
示例

  多个解释器叠加:解释语法时,自下而上运行;执行装饰器的函数时候时自上而下

技术分享图片
import time
def outter1(func1): #func1=wrapper2
    print(outter1)
    def wrapper1(*args,**kwargs):
        print(wrapper1)
        res1=func1(*args,**kwargs) #res1=wrapper2(*args,**kwargs)
        return res1
    return wrapper1

def outter2(func2): #func2=最原始的那个index的内存地址
    print(outter2)
    def wrapper2(*args,**kwargs):
        print(wrapper2)
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

@outter1 # index=outter1(wrapper2) #index=wrapper1
@outter2 #outter2(最原始的那个index的内存地址) ===> wrapper2
def index():
    print(welcome to index page)
    time.sleep(3)

index()  #wrapper1()
# 结果:
# outter2
# outter1
# wrapper1
# wrapper2
# welcome to index page
View Code

  有参装饰器

技术分享图片
# 有参装饰器的模板
def outter1(x,y,z):
    def outter2(func):
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            return res
        return wrapper
    return outter2


# 无参装饰器的模板
def outter(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper
View Code

  完美的伪装

技术分享图片
# 当用户查看函数信息时
def index():
    """
    index 功能
    """
    print(welcome to index page)
    time.sleep(3)
# print(index.__name__)
# print(help(index)) #index.__doc__
# 结果:
# index
#     index 功能

#使用装饰器后,用户查看函数信息,
def deco(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return wrapper
@deco #index=deco(index) #index=wrapper函数的内存地址
def index():
    """
    index 功能
    """
    print(welcome to index page)
    time.sleep(3)
# print(index.__name__)
# print(help(index)) #index.__doc__
# 结果:
# wrapper
#     None

# 修改方法有两种,
# 第一种自己添加,
def deco(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    wrapper.__name__=func.__name__
    wrapper.__doc__=func.__doc__
    return wrapper
@deco #index=deco(index) #index=wrapper函数的内存地址
def index():
    """
    index 功能
    """
    print(welcome to index page)
    time.sleep(3)

#第二种导入模块,添加装饰器
from functools import wraps
def deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return wrapper
View Code

7、函数的递归

  在调用一个函数中又直接或间接地调用该函数本身 。

  递归两个阶段:

    回溯:一个重复的过程,但是每一次重复问题的规模都应该减少。

       并且应该在慢组某种条件的情况下结束重复,开始进入递推阶段

    递归:往回一层一层推算结果

技术分享图片
# 计算Fibonacci数
# def Fibonacci(n):
#     """打印斐波那契前n个数字"""
#     if n == 0 or n == 1:
#         return n
#     else:
#         res = Fibonacci(n-1)+Fibonacci(n-2)
#         return res
#
# for i in range(20):
#     print(Fibonacci(i))

# Hanoi塔
def mov(x, y, z):
    """把x塔的圆盘移到z塔"""
    z.append(x.pop())
    return x,y,z

def Hanoi(n, x, y, z):
    if n == 1:
        mov(x, y, z)
        return
    else:
        Hanoi(n-1, x, z, y)
        mov(x, y, z)
        Hanoi(n-1, y, x, z)

x = [3,2,1]
y = []
z = []
Hanoi(len(x),x,y,z)

# 二分法查找从小到大的列表中的数
def search(n,l):
    print(l)
    if len(l) == 0:
        print(not exists)
        return
    mid_index=len(l) // 2
    if n > l[mid_index]:
        #in the right
        l=l[mid_index+1:]
        search(n,l)
    elif n < l[mid_index]:
        #in the left
        l=l[:mid_index]
        search(n,l)
    else:
        print(find it)

l=[1,2,10,30,33,99,101,200,301,311,402,403,500,900,1000] #从小到大排列的数字列表
search(3,l)
应用

 8、生成式

  1. 三元表达式

    a = 1 if 1>2 else 2 ,返回最大值

  2. 列表生成式

    l = [i for i in  range(10)], 结果[0,1,2,3,4,5,6,7,8,9]

    三元和列表混合使用

    res = [i for i in range(10) if i== 2],结果是:[2] 

    res = ["abc" if i==2 else i for i in range(10)],结果是res = [0, 1, ‘abc‘, 3, 4, 5, 6, 7, 8, 9]

  3. 字典生成式

    lis1 = [‘a‘,‘b‘,‘c‘,‘d‘],lis2 = [1,2,3,4]

    {lis1[i]:lis2[i] for i in range(len(lis1))}  或者 {k: lis2[i] for i,k in enumerate(lis1)}

    结果:{‘a‘: 1, ‘b‘: 2, ‘c‘: 3, ‘d‘: 4}

技术分享图片
#可以和三元表达式混合使用
{k: lis2[i] for i,k in enumerate(lis1) if i == b}
{b: 2}
# 其它生成字典的方法:
# 第一种:
# items = [(‘aaa‘,111),(‘bbb‘,222),(‘ccc‘,333)]
# dic = dict(items)
# {‘aaa‘: 111, ‘bbb‘: 222, ‘ccc‘: 333}

# 第二种, 字典内置函数
# {}.fromkeys([1,2,3], ‘aaa‘)
# {1: ‘aaa‘, 2: ‘aaa‘, 3: ‘aaa‘}

# 还可以生成集合
{i for i in [1,2,3,4,5,6,5,6]}
{1,2,3,4,5,6}
{i for i in hello}
{h, e, l, o}
View Code

  4. 匿名函数

    用在使用一次的场景,没有重复使用的需求

    使用方法:

      (lambda x, y: x+y)(1, 2)  结果:3 

技术分享图片
# 匿名函数与内置函数结合使用
# max, min, sorted, map, filter, reduce

salaries={
    aaa:3000,
    bbb:100000,
    ccc:10000,
    ddd:2000
}

# max和min
# 可以通过max函数的key参数来改变max的比较依据,
# 原理:max函数会循环出一个值,然后将该值传给key指定的函数
# 调用key指定的函数,将拿到的返回值当作比较依据

# 如果不设置key,
# max(salaries)
# 得到的结果:"ddd",原因:根据ASCII来判断,“d”对应的值最大。

# 传入key
# res=max(salaries,key=lambda name:salaries[name])  
# 结果:‘bbb‘
# 最小值
# res=min(salaries,key=lambda name:salaries[name])  
# 结果:‘ddd‘

# sorted排序(元素类型必须一样,要么都是数字,要么都是字符串)
# nums=[11,33,22,9,31]
# res=sorted(nums)
# 结果:[9,11,22,31,33]
# res=sorted(nums,reverse=True) # 反序
# 结果:[33,31,22,11,9]
# res=sorted(salaries,key=lambda name:salaries[name])
# 结果:[‘ddd‘, ‘aaa‘, ‘ccc‘, ‘bbb‘]

# map 映射,把一个列表按照自定义的规则映射成另一个新的列表
# names = [‘aaa‘, ‘bbb‘, ‘ccc‘, ‘ddd‘]
# res = map(lambda name: name + "ABC", names)
# (python3)结果返回的是一个迭代器对象,list(res) = [‘aaaABC‘, ‘bbbABC‘, ‘cccABC‘, ‘dddABC‘]
# 在python2中,返回的直接是一个列表


# filter, 过滤,从一个列表中过滤出符合我们规则的值
# 原理:循环出每个人名,传给lambda,将返回值为True的人名留下来。
# names = [‘aaaABC‘, ‘bbbABC‘, ‘ccc‘, ‘dddABC‘]
# res = filter(lambda name: name.endswith("ABC"), names)
# (python3)结果返回的是一个迭代器对象,list(res) = [‘aaaABC‘, ‘bbbABC‘, ‘dddABC‘]
# 在python2中,返回的直接是一个列表

#其它方法实现相同效果:
# [name for name in names if name.endswith("ABC")]

# reduce, 合并,把多个值合并成一个结果
from functools import reduce
l = [a, b, c, d]
res = rduce(lambda x, y: x+y, l, "A")#"A"是初始值,不设就为空
#‘A‘,‘a‘ => ‘Aa‘
#‘Aa‘,‘b‘=>‘Aab‘
#‘Aab‘,‘c‘=>‘Aabc‘
#‘Aabc‘,‘d‘=>‘Aabcd‘

# 求1~100总和
# res=reduce(lambda x,y:x+y,range(1,101))
#1,2=>3
#3,3=>6
# print(res)
lambda在max,min,sorted,filter,reduce中的使用

8、迭代器

  什么是迭代器?

    迭代器指的是迭代取值的工具。

    迭代是一个重复的过程,每一次重复都是基于上次的结果而进行

技术分享图片
    #单纯的重复不是迭代
    # i=0
    # while True:
    #     print(i)


    # 迭代:重复+每次重复都是基于上一次的结果而进行
    l=[a,b,c]
    i=0
    while i < len(l):
        print(l[i])
        i+=1
View Code

  为何使用迭代器?

    迭代器提供了一种通用的且不依赖索引的迭代取值方式

  1. 可迭代对象

    但凡内置了__iter__方法的对象都称为可迭代对象

    可迭代对象有:str, list, tuple, dict, set, 文件对象

技术分享图片
# 执行可迭代对象下的__iter__方法,返回的值就是一个迭代器对象iterator
# dic={‘x‘:1,‘y‘:2,‘z‘:3}
# iter_dic=dic.__iter__()
#
# # print(iter_dic)
# print(iter_dic.__next__())
# print(iter_dic.__next__())
# print(iter_dic.__next__())
# print(iter_dic.__next__()) #抛出异常StopIteration应该被当成一种结束信号

# f=open(‘a.txt‘,‘rt‘,encoding=‘utf-8‘)
# iter_f=f.__iter__()
# print(iter_f.__next__())
# print(iter_f.__next__())
# print(iter_f.__next__())
# print(iter_f.__next__())
View Code

  2. 迭代器对象

    即内置有__next__方法的对象,执行迭代器__next__方法可以不依赖缩影取值

    又内置__iter__方法的对象,执行迭代器__iter__方法得到的认是迭代器本身

    补充:

      1. 迭代器对象一定是可迭代对象,而可迭代对象去不一定是迭代器对象

      2. 文件对象本身就是一个迭代器对象

      3. 同一个迭代器只有一次循环取值,取完后再取就抛出异常

技术分享图片
# l=[‘a‘,‘b‘,‘c‘]
# iter_l=l.__iter__() # 调用可迭代的对象__iter__得到的是迭代对象,
# print(iter_l is iter_l.__iter__()) # 结果是True


# dic={1,2,3,4}
# dic={‘x‘:1,‘y‘:2,‘z‘:3}
# # print(len(dic)) #dic.__len__()
# iter_dic=iter(dic) # dic.__iter__()
#
# while True:
#     try:
#         print(next(iter_dic)) #iter_dic.__next__()
#     except StopIteration:
#         break
View Code

  3. for循环本质就是迭代器循环

    工作原理:

      1. 先调用in后面那个对象的__iter__方法,将其变成一个迭代器对象

      2. 调用next(迭代器),将得到的返回值赋值给变量名k

      3. 循环往复直到next(迭代器)抛出异常,for自动捕捉异常然后结束循环

      for k in range(10):  print(k)  

  4. 迭代器总结

    优点:提供一种通用的且不依赖于索引的迭代取值方式;同一时刻在内存中只存在一个值,更节省内存

    缺点:取值不如按照索引的方式灵活,无法预测迭代器所包含值的长度       

    在python2中一些内置函数如map,filter,range,生成的是列表,

    到了python3中做了优化,都变成了迭代器对象

   9、生成器

  生成器就是一种自定义的迭代器,本质是迭代器            

   但凡函数内包含yield 关键字,调用函数不会立即执行函数代码,会得到一个返回值,该返回值就是生成器对象 

技术分享图片
# def func():
#     print(‘first‘)
#     yield 1
#     print(‘second‘)
#     yield 2
#     print(‘third‘)
#     yield 3
#     print(‘fourth‘)
#
# g=func()
# print(g)
# print(g.__iter__().__iter__() is g) # 结果是True

# res1=next(g) #会触发函数的执行,直到碰到一个yield停下来,并且将yield后的值当作本次next的结果返回
# print(res1)
#
# res2=next(g)
# print(res2)
#
# res3=next(g)
# print(res3)
#
# res4=next(g)

# 结果是:
# first
# 1
# second
# 2
# third
# 3
# fourth
# 抛出异常,StopIteration
基本使用
技术分享图片
# 可以实现对函数内传值
def foo():
    print("start.....")
    num_list = []
    while True:
        num = yield num_list
        print("send:%s"%num)
        num_list.append(num)


g = foo()
next(g)    #先让生成器暂停到yield的位置,准备接受外部传进来的值

# send执行步骤:先为暂停位置的yield赋值,
# 然后next(生成器)直到再次碰到一个yield停下来,然后把这次位置的值当作本次next结果,赋给res
res = g.send(aaa) 
print(res)
res = g.send(123456)
print(res)
res = g.send(你好呀)
print(res)

# 结果:
# start.....
# send:aaa
# [‘aaa‘]
# send:123456
# [‘aaa‘, ‘123456‘]
# send:你好呀
# [‘aaa‘, ‘123456‘, ‘你好呀‘]
对函数内传值

  yield总结:

    1. yield提供了一种自定义迭代器的解决方案

    2.  yield可以保存函数的暂停的状态

    3. yield 对比return

      相同点:都可以 返回值,值的类型与个数没有限制

      不同点:yield可以返回多次,而return只能返回一次函数就结束了

10、生成器表达式 

  g = (i**2 for i in range(1,6) if i > 3)
    注:只要不next,一行代码不会执行,一旦next,直到产出值后才暂停
技术分享图片
# 生成器表达式
# g=(i**2 for i in range(1,6) if i > 3)
# # print(g)
# print(next(g))
# print(next(g))
# print(next(g))

#结果:
# <generator object <genexpr> at 0x00000291B5E2EEB8>
# 16
# 25
# StopIteration

# 求文件的长度
# 第一种
# with open(r‘aaa‘,‘rt‘,encoding=‘utf-8‘) as f:
#     data=f.read()
#     print(len(data))

with open(raaa,rt,encoding=utf-8) as f:
    #第二种
    # res=0
    # for line in f:
    #     res+=len(line)
    # print(res)

    # 第三种,使用生成器表达式
    # g=[len(line) for line in f]
    # print(sum(g))

    # 第四种,使用生成器表达式
    # g=(len(line) for line in f)
    # print(sum(g))

    res1=sum(len(line) for line in f)
    print(res1)

# sum函数的原理:
#     传入可迭代对象,
#     先调用可迭代对象的__iter__(),变成迭代器对象,
#     然后next取值再相加
生成器的使用
技术分享图片
笔试题目: 
def add(n, i):
    return n+i

def test():
    for i in range(4):
        yield i

g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)

res = list(g)
print(res)

# 注意:生成器表达式再没有next时是不执行的
# 由于g没有执行,所以n没有参与计算,直到n被赋值10
# list函数就是一直调用next取生成器的值

# 结果:[20, 21, 22, 23]
笔试题目

11、内置函数

技术分享图片
abs(),绝对值
        all(), 传入可迭代对象,所有为真,返回结果为True,若传入为空,则返回True
        any(), 传入可迭代对象,一个为真,返回结果为True,若传入为空,则返回False
        bin(),oct(),hex(),
        bool(),只有0,‘‘,[],{},(),None时,为False,其它都为True
        bytes(),编码,bytes("你好", encoding=utf-8)等同于"你好".encode("utf-8")
                        如果编码的是字母,bytes("abcd", encoding=utf-8) 等同于b"abcd"
        callable(),可调用的,只有函数可调用
        chr(),数字变ASCII字符,ord(),ASCII字符变数字
        
        classmethod,staticmethod,property,在面向对象中被当作装饰器使用
        delatter, hasattr,getattr,setattr,面向对象的反射
        isinstance(), issubclass(),面向对象的判断
        super(),

        dir(),查看一个对象下可以调用的方法
        divmod(),divmod(10, 3)得到(3, 1)
        enumarate(),枚举
        eval(), 把字符串的内容取出来,eval([1,2,3])得到[1,2,3]
        exec(),同上,可以执行多行,不拿返回值
        frozenset(), 不可变集合
        globals(),得到全局变量
        locals(),局部变量
        pow(),pow(2, 3,3)等同于(2**3)%3
        reversed(), 列表反转成一个迭代器
        round(),四舍五入,遇到.5取偶数边
        slice(),切片, 创造一个切片规则对象, obj = slice(1,5,2), ‘‘helloworld[obj] = el        zip(), a=[1,2,3,4], b= "abc" list(zip(a,b))得到[(1, a), (2, b), (3, c)]
        __import__(),以字符串导入模块,__import__(time)
View Code

 

python学习之函数

原文:https://www.cnblogs.com/ywsun/p/10573884.html

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