Python3之函数

函数目录:


一、初识函数
1.内置函数
len()
s = 'felix'
len(s)
2.自定义函数
def my_len(): #自定义函数 声明函数 函数名定义方法跟变量规则相同
i = 0
for k in s:
i += 1
print(i)
length = my_len()
print(length)
函数
定义了之后,可以在任何需要它的地方调用
没有返回长度,只是单纯的打印
返回的重要性
a,b
len(a) #内置函数
len(b)
def my_len(): #自定义函数
i = 0
for k in s:
i += 1
return i #返回值
length = my_len() #自定义的函数进行调研
print(length)
len()
1.不能变,只能计算s字符串的长度
2.只是输出了结果
二、返回值
返回值的3种情况
(1)没有返回值 —— 默认返回None
1.不写return
2.只写return:结束一个函数的继续,代码块遇到return就结束后面的代码
3.return None —— 不常用
(2)返回1个值
1.可以返回任何数据类型
2.只要返回就可以接收到
3.如果在一个程序中有多个return,那么只执行第一个
(3)返回多个值
用多个变量接收:有多少返回值就用多少变量接收
用一个变量接收: 得到的是一个元组
 实例:
def func():
    l = ['张老板','小黑']
    for i in l:
        print(i)
        if i=='小黑':
            return None
    print('='*10)
ret = func()
print(ret)

def func():
    return [1,2,3]
print(func())

def func():
    return {'k':'v'}
print(func())

def func2():
    return 1,2,3  #return 1,2,3

r= func2()
print(r)

a,b,c = 1,2,3
a = 1
b = 2
c = 3  python自动进行解构
a,b = [1,2]
a = 1
b = 2

三、参数
1.什么叫参数?
参数的语法
形参和实参的概念
函数与函数的代码不会相互影响
def my_len(s):  # 自定义函数只需要0个参数,接收参数,形式参数,形参
    i = 0
    for k in s:
        i += 1
    return i  # 返回值


ret = my_len('A')  # 传递参数:传参,实际参数,实参
ret = my_len([1, 2, 3, 4, 5])  # 传递参数:传参
ret = my_len({'k1': 'v1', 'k2': 'v2'})
print(ret)


def f2(l1):
    f1(l1)
    for i in l1:
        print(i)


def f1(l1):
    for i in l1:
        print(i)


f2([1, 2, 3, 4])

2.参数
(1)没有参数
定义函数和调用函数时括号里都不写内容
(2)有一个参数
传什么就是什么
(3)有多个参数
位置参数
exp: 传递2个参数


def my_sum(a, b):
    print(a, b)
    res = a + b  # result
    return res


ret = my_sum(1, 2)
print(ret)

  

    3.站在实参的角度上:
按照位置传参:位置参数
按照关键字传参:关键字参数
混着用可以:但是 必须先按照位置传参,再按照关键字传参数
不能给同一个变量传多个值
4.站在形参的角度上
位置参数:必须传,且有几个参数就传几个值
默认参数: 可以不传,如果不传就是用默认的参数,如果传了就用传的
exp:

def classmate(name, sex='男'):
    print('%s : %s' % (name, sex))

classmate('A')
classmate('B')
classmate('C')
classmate('D', '女')

  

    5.只有调用函数的时候
按照位置传 : 直接写参数的值
按照关键字: 关键字 = 值
6.定义函数的时候:
位置参数 : 直接定义参数
默认参数,关键字参数 -> 参数名 = '默认的值'
动态参数 : 可以接受任意多个参数
参数名之前加*,习惯参数名args, 元组
参数名之前加**,习惯参数名kwargs 字典
顺序:必须先定义位置参数,*args,默认参数,**kwargs
def classmate(name, sex):
    print('%s : %s' % (name, sex))


classmate('二狗哥', '男')
classmate(sex='男', name='二狗哥')


def classmate(name, sex='男'):
    print('%s : %s' % (name, sex))


classmate('二狗哥')
classmate('小花', sex='女')


def sum(*args):
    n = 0
    for i in args:
        n += i
    return n

print(sum(1, 2))
print(sum(1, 2, 3))
print(sum(1, 2, 3, 4))


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


func(a=1, b=2, c=3)
func(a=1, b=2)
func(a=1)

  

    7.动态参数有两种:可以接受任意个参数
*args : 接收的是按照位置传参的值,组织成一个元组
**kwargs: 接受的是按照关键字传参的值,组织成一个字典
args必须在kwargs之前
def func(*args, default=1, **kwargs):
    print(args, kwargs)

func(1, 2, 3, 4, 5, default=2, a='aaaa', b='bbbb', )

  

    8.动态参数的另一种传参方式
def func(*args):  # 站在形参的角度上,给变量加上*,就是组合所有传来的值。  封装
    print(args)


func(1, 2, 3, 4, 5)
l = [1, 2, 3, 4, 5]
func(*l)  # 站在实参的角度上,给一个序列加上*,就是将这个序列按照顺序打散  解构


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


func(a=1, b=2)
d = {'a': 1, 'b': 2}  # 定义一个字典d
func(**d)

  

    9.函数的注释
def func():
'''
这个函数实现了什么功能
参数1:
参数2:
:return: 是字符串或者列表的长度
'''
pass

  10.默认参数的陷阱

如果默认参数的值是一个可变的数据类型,那么每一次调用函数的时候,
如果不传值就公用这个数据类型的资源

def func( 1 = [] ):
    l.append(1)
    print(l)

func()
func()
func()
func()
func()

执行后:

[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1, 1]


def func(k,l = {}):
    #l.append(1)
    l[k] = 'v'
    print(l)

func(1)
func(2)
func(3)
func(4)
func(5)

执行结果:
{1: 'v'}
{1: 'v', 2: 'v'}
{1: 'v', 2: 'v', 3: 'v'}
{1: 'v', 2: 'v', 3: 'v', 4: 'v'}
{1: 'v', 2: 'v', 3: 'v', 4: 'v', 5: 'v'}

四、命名空间和作用域

  1.三种命名空间

  (1)内置命名空间---‘Python解释器’   可以使用全局、内置命名空间的名字
就是python解释器一启动就可以使用的名字存储在内置命名空间中
内置的名字在启动解释器的时候被加载进内存里
(2)全局命名空间---‘我们写的代码单不是函数中的代码’ 可以使用内置命名空间的名字 但是不能用局部中的名字
 是在程序从上到下被执行的过程中一次加载进内存的
 放置了我们设置的所有变量名和函数名
(3)局部命名空间---‘函数’ 不能使用局部和全局的名字
 就是函数内部定义的名字
 当调用函数的时候 才产生这个名称空间 随着函数执行的结束 这个命名空间就消失了

  三种命名空间之间的加载与取值顺序:

  加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

exp1:

def input():
    print('in input now')

def func():
    input()

func()
执行结果:
in input
now

exp2:

def input():
    print('in input now')

def func():
    input = 1
    print(input)

func()
执行结果:
1

注意:func --> 函数的内存地址
        函数名() 函数的调用
        函数的内存地址()  函数的调用
   
注意:
  • 在正常情况,直接使用内置的名字;当我们在全局定义了和内置名字空间中同名的名字是,会使用全局的名字
  • 当我自己有名字的时候,不去找我的上级要了;如果自己没有 就找上一级要,上一级没有再找上一级,如果内置的名字空间都没有 就报错
  • 多个函数应该拥有多个独立的局部名字空间,不互相共享

  2.两种作用域

1.全局作用域    作用在全局    内置和全局名字空间的名字属于全局作用域
   查看全局作用域方法:
     print(globals())

2.局部作用域    作用在局部    函数(局部名字空间的名字属于局部作用域)
   查看局部作用域方法:
   print(locals())


exp:

a = 1
def func():
    a += 1

func()
print(a)
执行结果:
1


a = 1
b = 2
def func():
    x = 'aaa'
    y = 'bbb'
    print(locals())

func()
执行结果:
{'x': 'aaa', 'y': 'bbb'}

globals()
永远打印全局的名字
locals()
输出什么根据locals所在的位置确定

对于不可变数据类型,在局部可以查看全局作用域的变量
但是不能直接修改
如果想要修改,需要在程序的一开始增加
global 声明
如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效

global关键字

a = 10
def func():
    global a
    a = 20

print(a)
func()
print(a

  

  3.函数的嵌套和作用域链

(1)函数的嵌套定义
def max(a,b):
    return a if a > b else b

def the_max(x,y,z)
    c = max(x,y)

the_max(111,222,333)

(2)内部函数可以使用外部函数的变量
exp1:

def outer():
    a = 1

    def inner():
        print(a)
        print('inner')

    inner()

outer()

exp2:

def outer():
    a = 1

    def inner():
        print(a)
        print('inner')
        
        def inner2():
            print('inner2')
            
        inner2()
        
    inner()


outer()

  

  nonlocal关键字

# 1.外部必须有这个变量
# 2.在内部函数声明nonlocal变量之前不能再出现同名变量
# 3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效
exp3:

a = 1
def outer():
    a = 2
    def inner():
        a = 3
        def inner2():
            nonlocal a #声明了一个上面第一层局部变量
            a += 1     #不可改变数据类型的修改
        inner2()
        print('###a###',a)
    inner()
    print('***a***', a)
outer()
print('全局',a)
执行结果
###a### 4
***a*** 2
全局 1

def func():
    print(123)

func() #函数名就是内存地址
func2 = func #函数名可以赋值
func2()

l = [func,func2] #函数名可以作为容器类型的元素
for i in l:
    i()

def func():
    print(123)

def test(f):
    f()
    return f         #函数名可以作为函数的返回值

a = test(func) #函数名可以作为函数的参数

  

五、闭包函数和装饰器

  1.闭包函数

内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数

#函数内部定义的函数称为内部函数

def outer():
    a = 1
    def inner():
        print(a)
    inner()
outer()

   def outer():
    a = 1
    def inner():
        print(a)
    return inner
outer()

判断闭包函数的方法__closure__

#输出的__closure__有cell元素 :是闭包函数
def func():
    name = 'felix'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f = func()
f()

#输出的__closure__为None :不是闭包函数
name = 'alina'
def func2():
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f2 = func2()
f2()

  

#闭包嵌套

def wrapper():
    money = 1000
    def func():
        name = 'felix'
        def inner():
            print(name,money)
        return inner
    return func

f = wrapper()
i = f()
i()
#应用

from urllib.request import urlopen

def index():
    url = "http://www.xiaohua100.cn/index.html"
    def get():
        return urlopen(url).read()
    return get

xiaohua = index()
content = xiaohua()
print(content)

  

  2.装饰器

  (1)装饰器的本质:就是一个闭包函数,是在不修改主体代码(函数)的情况下,需要在执行之前或者执行之后实现的功能。

    (2)形成过程

    

#装饰器——简单版1
import time

def func1():
    print('in func1')

def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

func1 = timer(func1)
func1()

#装饰器——语法糖
import time
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

@timer   #==> func1 = timer(func1)
def func1():
    print('in func1')


func1()

#装饰器——带参数的装饰器
import time
def timmer(f):
    def inner(*args,**kwargs):
        start =time.time()
        ret = f(*args,**kwargs)
        end = time.time()
        print(end -start)
        return ret
    return inner

@timmer  #语法糖 等同于 func = timmer(func)
def func(L):
    time.sleep(1)
    dic = {'num':0,'alpha':0,'space':0,'other':0}
    for i in L:
        if i.isdigit():
            dic['num'] += 1
        elif i.isalpha():
            dic['alpha'] += 1
        elif i.isspace():
            dic['space'] += 1
        else:
            dic['other'] += 1
    return dic

s = input('>>>')
print(func(s))

#装饰器——成功hold住所有函数传参
import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func1 = timer(func1)
def func1(a,b):
    print('in func1')

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))


#装饰器——带返回值的装饰器

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func2('aaaaaa')
print(func2('aaaaaa'))

#查看函数信息的一些方法

def index():
    '''这是一个主页信息'''
    print('from index')

print(index.__doc__)    #查看函数注释的方法
print(index.__name__)   #查看函数名的方法

#装饰器的固定模式

def wrapper(fn):   #装饰器函数,fn为被装饰的函数
    def inner(*args,**kwargs):
        #before  #执行前的装饰功能
        ret = fn(*args,**kwargs)  #被装饰的函数
        #after   #执行后的装饰功能
        return ret
    return inner  #返回增强版的fn (函数)
@wrapper  #语法糖  @装饰器函数名
#多个装饰器装饰一个函数
def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        ret = func()
        print('wrapper1 ,after func')
        return ret
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        ret = func()
        print('wrapper2 ,after func')
        return ret
    return inner2

def wrapper3(func):
    def inner3():
        print('wrapper3 ,before func')
        ret = func()
        print('wrapper3 ,after func')
        return ret
    return inner3

@wrapper3
@wrapper2
@wrapper1
def f():
    print('in f')
    return '哈哈哈'

print(f())
执行结果:
wrapper3 ,before func
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
wrapper3 ,after func
哈哈哈

  (3)装饰器进阶

  实例1.查看原函数的名称

def wrapper(func):  #执行顺序 1
    def inner(*args,**kdargs):  #执行顺序 4
        print('在被执行函数之前增加的功能')  #执行顺序 8
        ret = func(*args,**kdargs)     #func(*args,**kdargs)执行顺序 9   #ret执行顺序 12
        print('在被执行函数之后增加的功能')  #执行顺序 13
        return ret  #执行顺序 14
    return inner  #执行顺序 5    inner执行顺序 11

@wwapper  #执行顺序 2  #holidy = wrapper(holidy)  #wrapper(holidy)执行顺序 3    #holidy执行顺序 6
def holiday(day):
    print('全体放假%s天'%day)
    return '好开心'   #执行顺序 10

ret = holiday(3)   #holiday(3)执行顺序 7   #ret执行顺序 15
print(ret)   执行顺序 16

取函数中函数的名字-字符串格式

print(fanc.__name__) #查看字符串格式的函数名字   两个下划线 __

结合上面装饰器 打印结果为 inner  在全局作用域下已找不到func函数,已经传给inner了

print(fanc.__doc__)  #document   查看函数的注释


通过以下方式 向装饰器里的inner函数增加装饰器可得到原来holiday的字符串函数名字


from functools import wraps
def wrapper(func):
    @wraps(func)
    def inner(*args,**kdargs):
        print('在被执行函数之前增加的功能')
        ret = func(*args,**kdargs)
        print('在被执行函数之后增加的功能')
        return ret
    return inner

@wrapper   #holidy = wrapper(holidy)
def holiday(day):
    '''这是一个放假通知!'''
    print('全体放假%s天'%day)
    return '好开心'
print(holiday(3))
# ret = holiday(3)
# print(ret)

print(holiday.__name__)
print(holiday.__doc__)

执行结果:

在被执行函数之前增加的功能
全体放假3天
在被执行函数之后增加的功能
好开心
holiday
这是一个放假通知!

  实例2:给N个函数加同一个装饰器,如何实现装饰器的开和关?

#带参数的装饰器
#500个函数
import time
FLAGE = False  #通过设置标志的True 或 False 实现装饰器的开和关
def timmer_out(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end-start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer
# timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)    #test1 = timmer(test1)
def test1():
    time.sleep(0.1)
    print('test1test1test1')

@timmer_out(FLAGE)
def test2():
    time.sleep(0.1)
    print('test2test2test2')

test1()
test2()

执行结果:
test1test1test1
0.10920047760009766
test2test2test2
0.10920000076293945

  实例3:计算10万以内的所有质数个数

import time
import datetime

flag = True
# flag = False
def timmer_out(flag):
    def timmer(f):
        def inner(*args, **kwargs):
            if flag:
                # start =time.time()
                start = datetime.datetime.now()
                ret = f(*args, **kwargs)
                # end = time.time()
                end = datetime.datetime.now()
                delta = end - start
                #print( end -start )
                print(delta.total_seconds())
                return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return timmer

@timmer_out(flag)  # 语法糖 等同于 func = timmer(func)
def prime_num1(n):
    prime_number = [2]
    count = 1
    for i in range(3, n, 2):
        for j in prime_number:
            if i % j == 0:
                break
        else:
            prime_number.append(i)
            count += 1
    # print('质数数量为:',count)
    # print(prime_number)
    return count
print(prime_num1(100000))

@timmer_out(flag)
def prime_num2(n):
    count = 2
    for i in range(4, n):  # 排除偶数,偶数都是2的倍数
        if i % 6 != 1 and i % 6 != 5:
            continue
        else:
            for j in range(5, int(i ** 0.5) + 1, 2):  # 奇数除以奇数可以除尽,但奇数除以偶数不能除尽,又一次排除一部分偶数,加快程序速度
                if not i % j:
                    break
            else:
                count += 1
            # print(count,i,end='\n')
    return count
print(prime_num2(100000))

@timmer_out(flag)
def prime_num3(n):
    count = 1
    # print(1,2)  2也是质数
    for i in range(3, n + 1, 2):  # 排除偶数,偶数都是2的倍数
        if i > 10 and i & 10 == 5:
            continue
        for j in range(3, int(i ** 0.5) + 1, 2):  # 奇数除以奇数可以除尽,但奇数除以偶数不能除尽,又一次排除一部分偶数,加快程序速度
            if i % j == 0:
                break
        else:
            count += 1
            # print(count,i,end='\n')
    return count
print(prime_num3(100000))

执行结果:
4.447008
9592
0.1248
9592
0.171601
9592

  

    2.原则

  

  (1)对扩展是开放的

    为什么要对扩展开放呢?

    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

  (2)对修改是封闭的

    为什么要对修改封闭呢?

    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

装饰器完美的遵循了这个开放封闭原则。

六、生成器和迭代器

  1.可迭代协议和迭代器协议:

   可迭代协议:可迭代协议的定义非常简单,就是内部实现了__iter__方法。

print(dir([1,2]))
print(dir((2,3)))
print(dir({1:2}))
print(dir({1,2}))

执行结果:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

  可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法。

   迭代器协议:迭代器协议 —— 内部含有__next__和__iter__方法的就是迭代器

'''
dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,
然后取差集。
'''
#print(dir([1,2].__iter__()))
#print(dir([1,2]))
print(set(dir([1,2].__iter__()))-set(dir([1,2])))

结果:
{'__length_hint__', '__next__', '__setstate__'}

  

iter_l = [1,2,3,4,5,6].__iter__()
#获取迭代器中元素的长度
print(iter_l.__length_hint__())
#根据索引值指定从哪里开始迭代
print('*',iter_l.__setstate__(4))
#一个一个的取值
print('**',iter_l.__next__())
print('***',iter_l.__next__())
执行结果:
6
* None
** 5
*** 6

  

在for循环中,就是在内部调用了__next__方法才能取到一个一个的值。

l = [1,2,3,4]
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)

执行结果:
1
2
3
4
StopIteration

  最后一个代码会报错,如果我们一直取next取到迭代器里已经没有元素了,就会抛出一个异常StopIteration,告诉我们,列表中已经没有有效的元素了。

  这个时候,我们就要使用异常处理机制来把这个异常处理掉。

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

  

  2.生成器:本质是迭代器

生成器
生成器的表现形式:
生成器函数
生成器表达式
生成器函数:
还有yield关键字的函数就是生成器函数
特点:
调用函数之后函数不执行,返回一个生成器
每次调用__next__方法的时候会取到一个值
直到取万最后一个,在执行__next__会报错
迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
# 生产200万个娃哈哈
# def generator():
#     for i in range(2000001):
#         yield  '娃哈哈%s' %i  #生成器函数 关键字 yield
# g = generator()
#
# for i in g:
#     print(i)

#只取50个
def generator():
    for i in range(2000001):
        yield  '娃哈哈%s' %i  #生成器函数 关键字 yield
g = generator()

count = 0
for i in g:
    count += 1
    print(i)
    if count > 50:
        break

#继续取50个
for i in g:
    count += 1
    print(i)
    if count > 100:
        break

  

  3.生成器进阶

def genrator():
    print(123)
    yield 1
    print(456)
    yield 2
    print(789)

g = genrator()
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)

执行结果:
123
1
456
2
789
Traceback (most recent call last):
  File "D:/Python_learn/Study/9.26/生成器进阶.py", line 14, in <module>
    ret = g.__next__()
StopIteration


exp2:

def genrator():
    print(123)
    yield 1
    print(456)
    yield 2


g = genrator()
ret = g.__next__()
print(ret)
ret = g.send(None)  #send效果和 next一样
print(ret)

执行结果:
123
1
456
2

exp3:

def genrator():
    print(123)
    content = yield 1
    print('#####',content)
    print(456)
    yield 2


g = genrator()
ret = g.__next__()
print(ret)
ret = g.send('hello,python')
print(ret)

执行结果:
123
1
##### hello,python
456
2

  

send的获取下一个值的使用效果和next基本一致,只是在获取下一个值的时候,
给上一个yield的位置传递一个数据
使用send的注意事项:
1.第一次使用生成器的时候,是使用next获取下一个值
2.最后一个yield不能接受外部的值
实例:计算动态平均值
#计算动态平均数

普通写法:
def avg():
    avg = sum = count = 0
    while True:
        s = int(input('>>>'))
        count += 1
        sum += s
        avg = sum / count
        print(avg)
print(avg())


生成器写法:
def average():
    count = 0
    sum = 0
    avg = 0
    while True:
        num = yield avg
        count += 1
        sum = sum + num
        avg = sum / count

g = average()
g.__next__()
print(g.send(10))
print(g.send(20))
print(g.send(30))
print(g.send(30))

  

预激生成器的装饰器的例子
#省略执行时的第一步g.__next__()

def wrapper(f):
    def inner(*args,**kdargs):
        g = f(*args,**kdargs)
        g.__next__()
        return g
    return inner

@wrapper
def average():
    count = 0
    sum = 0
    avg = 0
    while True:
        num = yield avg
        count += 1
        sum = sum + num
        avg = sum / count

g = average()
print(g.send(10))
print(g.send(20))
print(g.send(30))
print(g.send(30))

七、递归函数

递归函数
了解什么是递归:在函数中调用自己
exp:
    def wuliao():
        print('从前有座山,山里有座庙')
        wuliao()
    wuliao()

    RecursionError: maximum recursion depth exceeded while calling a Python object
    #递归的错误,超过了递归的最大深度,最大递归深度默认是997/998 是python从内存角度做的限制

 

导入sys模块,修改递归函数限制的次数,sys.setrecursionlimit(n)
但是递归的次数还是根据电脑的配置而定 python就执行多少次。如果递归次数太多,就不太适合用
递归函数来解决问题
    exp:
    import sys
    sys.setrecursionlimit(1000000)
    n = 0
    def story():
        global n
        n += 1
        print('从前有座山,山里有座庙')
        print(n)
        story()
    story()
    执行:
    3924
    从前有座山,山里有座庙
    3925

  

递归函数的特点:
缺点:太占内存 优点:会让代码变简单
# A 多大       n = 1   age(1) = age(2)+2 = age(n+1) + 2
# A比B大两岁
# B多大?      n = 2   age(2) = age(3) + 2 = age(n+1) +2
# B比C大两岁
# C多大       n = 3   age(3) = age(4) + 2 = age(n+1) +2
# C比D大两岁
# D多大?
# D今年40了      n = 4   age(4) = 40

# n = 4 age(4) = 40
# n <4  age(n) = age(n+1) +2

def age(n):
    if n == 4:
        return 40
    elif n >0 and n < 4:
        age(n+1) + 2
#
print(age(4))

# # 教你看递归

def age(1):
    if 1 == 4:
        return 40
    elif 1 >0 and n < 4:
        age(1+1) + 2  #age(2)+2 = 46


def age(2):
    if n == 4:
        return 40
    elif 2 >0 and n < 4:
        age(2+1) + 2  #age(3)+2 = 42 + 2 = 44

def age(3):
    if n == 4:
        return 40
    elif n >0 and n < 4:
        age(3+1) + 2  #age(4)+2 = 42


 def age(4):
    if n == 4:
        return 40
    elif n >0 and n < 4:
        age(n+1) + 2

  实例:利用二分查找法(折半思想)查找某个数

L = [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88]

def find(L,target,start=0,end=None):
    end = len(L) if end is None else end
    mid_index = ((end - start) // 2 )+ start
    if start <= end:
        if L[mid_index] < target:
            return find(L,target,start=mid_index+1,end=end)
        elif L[mid_index] > target:
            return find(L,target,start=start,end=mid_index-1)
        elif L[mid_index] == target:
            return L[mid_index],L.index(target)
    else:
        return '查找的值不存在'

ret = find(L,69)  #查找69所在的索引
print(ret)
执行结果:
(69, 19)

  

八、推导式

1、生成器表达式 (i for i in range(10))
    返回一个生成器
 
    exp1:
    g = (i for i in range(10))
    print(g)
    执行结果:
    <generator object <genexpr> at 0x00000000020A4F48>
 
    for i in g:
        print(i)
 
    生成器表达式和列表推导式区别:
    1.括号不一样,生成器表达式为括号(),列表推导式为中括号[]
    2.返回的值不一样,生成器表达式返回 一个生成器 生成器节省内存 列表表达式 返回列表所有结果,
 
 
    老母鸡 = ('鸡蛋%s'%i for i in range(10) )
    print(老母鸡)
    for 鸡蛋 in 老母鸡:
        print(鸡蛋)
 
    10以内的数字的平方
    square = ( i**2 for i in range(10))
    for num in square:
        print(num)
 
 
2、列表推导式  [i for i in range(10)]
    [每一个元素或者是和元素相关的操作 for i in 可迭代数据]
 
    [ 满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] 筛选元素
 
    egg_list = []
    for i in range(10):
        egg_list.append('鸡蛋%s'%i)
    print(egg_list)
 
    执行结果:
    ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
 
    列表推导式
    egg_list = [ '鸡蛋%s'%i for i in range(10) ]
    print(egg_list)
 
    执行结果:
    ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
 
    列表推导式:[ i for i in range(10) ]
 
    exp:找到嵌套列表中名字含有两个‘e’的所有名字
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
 
    print([name for name_lst in names for name in name_lst if name.count('e') == 2])
    执行结果:
    ['Jefferson', 'Wesley', 'Steven', 'Jennifer']
 
 
 
 
    exp:
    30以内所有能被3整除的数
    [i for i in range(1,30) if i % 3 == 0]
    g = ( i for i in range(1,30) if i % 3 == 0)
    for i in g:
        print(i)
 
3、字典推导式
 
    例一:将一个字典的key和value对调
 
 
    mcase = {'a': 10, 'b': 34}
    mcase_frequency = {mcase[k]: k for k in mcase}
    print(mcase_frequency)
 
    {10: 'a', 34: 'b'}
 
    exp2:合并大小写对应的value值,将k统一成小写
    mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
    mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
    print(mcase_frequency)
    {'a': 17, 'b': 34, 'z': 3}
 
4、集合推导式
 
    squared = {x**2 for x in [1, -1, 2]}
    print(squared)
 
    {1, 4}

  

九、内置函数

内置函数
一、内置函数定义及总数
    python里的内置函数。截止到python版本3.6.2,现在python一共为我们提供了68个内置函数。
 
            Built-in Functions
    abs()       dict()  help()  min()   setattr()
    all()       dir()   hex()   next()  slice()
    any()       divmod()    id()    object()    sorted()
    ascii()     enumerate() input() oct()   staticmethod()
    bin()       eval()  int()   open()  str()
    bool()      exec()  isinstance()    ord()   sum()
    bytearray() filter()    issubclass()    pow()   super()
    bytes()     float() iter()  print() tuple()
    callable()  format()    len()   property()  type()
    chr()       frozenset() list()  range() vars()
    classmethod()   getattr()   locals()    repr()  zip()
    compile()   globals()   map()   reversed()  __import__()
    complex()   hasattr()   max()   round()
    delattr()   hash()  memoryview()    set()
 
二、分类
 
(1)作用域相关
 
    1.locals()    #返回本地作用域中的所有名字  函数会以字典类型返回当前位置的全部局部变量。
 
    2.globals()   #返回全局作用域中的所有名字  函数会以字典类型返回当前位置的全部全局变量。
 
    与local、global不同
    local 变量  #声明变量作用域
    global 变量 #声明变量作用域
 
(2)迭代器
 
    1.next(iterator[, default])  返回迭代器的下一个项目
        迭代器.__next__()  效果都一样,实际执行迭代器.__next__()
 
    2.iter(可迭代的) 函数用来生成迭代器。
        可迭代的.__iter__()
 
    3.range(start, stop[, step]) 函数可创建一个整数列表,一般用在 for 循环中。
        是一个可迭代的,不是一个迭代器
        range(10),range(1,10),range(1,10,2)
 
        print(dir(range(10)) )
        print( '__next__' in dir(range(10)) )   #False
        print( '__next__' in dir(iter(range(10))) )    #False  将可迭代的转化成迭代器
 
(3)其他:
 
    1.dir() 不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。
            如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。
        print(dir(1))
 
    2.callable()  用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回False,调用对象ojbect绝对不会成功。
                对于函数, 方法, lambda 函式, 类, 以及实现了 __call__ 方法的类实例, 它都返回 True。
        print(callable('alina')) -> False
 
        def func():pass
        print(callable(func))    ->   True
 
    3.help()  用于查看函数或模块用途的详细说明。
        help(list)
 
    4.import 模块名称    调用__import__()  函数
        __import__()  一般不用
        # import datetime
        test_time = __import__('datetime')
        print(test_time.datetime.now())
            2018-09-27 14:28:46.529354
 
    5.open() 打开文件
 
    6.id() 查看内存地址
 
    7.hash()
        print(hash(1234))
            1234
        print(hash('felix'))
            6020047598959426572
        字典的寻址方式
 
    某个方法属于某个数据类型的变量,就用 .调用
    如果某个方法不依赖于任何数据类型,就直接调用 ----内置函数 和 自定义函数
 
    8.input()  输入,字符串接受
 
    9.print()  输出
 
        end=  指定输出的结束符
            print('test',end='\t')
 
        sep=  指定输出的分隔符
           print('test',sep='|')
 
        file=  指定输出位置文件   默认输出到屏幕
            with open('file','w',encoding='utf-8') as f:
                print('测试print函数输出位置',file=f)
        flush:立即把内容输出到流文件,不作缓存
 
 
        #打印进度条
        import time
        for i in range(0,100000,2):
             time.sleep(0.1)
             char_num = i//2      #打印多少个'*'
             per_str = '\r%s%% : %s\n' % (i, '*' * char_num) if i == 100 else '\r%s%% : %s'%(i,'*'*char_num)
             print(per_str,end='', flush=True)
        #小越越  : \r 可以把光标移动到行首但不换行
        打印进度条模块  progress Bar
 
    10.exec()
    11.eval() 用来执行一个字符串表达式,并返回表达式的值。
        exec和eval都可以执行 字符串类型的代码
        eval() 有返回值 ---有结果的简单运算
        exec() 无返回值 ----简单的流程控制
        eval()只能用在你明确知道你要执行的代码是什么
 
        exec('print(123)')
        eval('print(123)')
        print(exec('print(123)'))  #没有返回值
        print(eval('print(123)'))   #有返回值
 
        code = """[(print(i*'*')) for i in range(10)]"""
        exec(code)
        123
        123
        123
        None
        123
        None
 
        *
        **
        ***
        ****
        *****
        ******
        *******
        ********
        *********
 
    12.compile(source, filename, mode[, flags[, dont_inherit]]) 将一个字符串编译为字节代码。
        code3 = """name = input('请输入你的名字:')"""
        compile3 = compile(code3,'','single')
 
        exec(compile3)
        print(name)
 
(4)数据类型相关
 
    1.complex([real[, imag]]) 用于创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。。
        复数 —— complex
        实数 : 有理数
                无理数
        虚数 :虚无缥缈的数
        5 + 12j  === 复合的数 === 复数
        6 + 15j
 
    2.float() 用于将整数和字符串转换成浮点数。
        浮点数(有限循环小数,无限循环小数)  != 小数 :有限循环小数,无限循环小数,无限不循环小数
        浮点数
            354.123 = 3.54123*10**2 = 35.4123 * 10
        f = 1.781326913750135970
        print(f)
 
    3.bin()  返回一个整数 int 或者长整数 long int 的二进制表示
    4.oct()  将一个整数转换成8进制字符串。
    5.hex()  函数用于将10进制整数转换成16进制,以字符串形式表示。
 
        print(bin(10))    0b1010
        print(oct(10))    0o12
        print(hex(10))    0xa
 
    6.abs()  求绝对值
 
    7.divmod(x,y)   把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
        Return the tuple (x//y, x%y)
        print(divmod(100,15))
            (6, 10)
        实际应为举例:100条新闻,每15条方1页,可以放多少页
 
 
    8.round()  四舍五入
 
    9.pow(x,y[,z])  方法返回 xy(x的y次方) 的值。
        当有2个参数时候,为x的y次方,等价于 x**y
            print(pow(9,2))     ->  81
        当有3个参数是,为x的y次方,再对z取余
            print(pow(9,2,4))  ->  1
 
    10.sum(iterable[, start])  求和
 
    11.max(iterable, *[, default=obj, key=func]) -> value
       max(arg1, arg2, *args, *[, key=func]) -> value
        print(max([1,22,9],[2,11,23]))
            [2, 11, 23]
        print(max(1,22,-100,key=abs))
            -100
    12.min(iterable, *[, default=obj, key=func]) -> value
       min(arg1, arg2, *args, *[, key=func]) -> value
 
 
    13.reversed()  保留原列表,反转数据,返回一个可迭代的
 
        lst = [1,5,9,2,7,3]
        lst.reverse()
        print(lst)
 
        lst1 = []
        for i in reversed(lst):
            lst1.append(i)
        print(lst1)
 
    14.slice(start, stop[, step]) 实现切片对象,主要用在切片操作函数里的参数传递。
        exp:
        lst = [1,5,9,2,7,3]
        slst = slice(0,4,2)
        print(lst[slst])
            [1, 9]
 
 
    15.format() 格式化
        #字符串可以提供的参数,指定对齐方式,<是左对齐, >是右对齐,^是居中对齐
            print(format('test', '<20'))
            print(format('test', '>20'))
            print(format('test', '^20'))
 
        #整形数值可以提供的参数有 'b' 'c' 'd' 'o' 'x' 'X' 'n' None
            >>> format(3,'b') #转换成二进制
            '11'
            >>> format(97,'c') #转换unicode成字符
            'a'
            >>> format(11,'d') #转换成10进制
            '11'
            >>> format(11,'o') #转换成8进制
            '13'
            >>> format(11,'x') #转换成16进制 小写字母表示
            'b'
            >>> format(11,'X') #转换成16进制 大写字母表示
            'B'
            >>> format(11,'n') #和d一样
            '11'
            >>> format(11) #默认和d一样
            '11'
        浮点数可以提供的参数有 'e' 'E' 'f' 'F' 'g' 'G' 'n' '%' None
            >>> format(314159267,'e') #科学计数法,默认保留6位小数
            '3.141593e+08'
            >>> format(314159267,'0.2e') #科学计数法,指定保留2位小数
            '3.14e+08'
            >>> format(314159267,'0.2E') #科学计数法,指定保留2位小数,采用大写E表示
            '3.14E+08'
            >>> format(314159267,'f') #小数点计数法,默认保留6位小数
            '314159267.000000'
            >>> format(3.14159267000,'f') #小数点计数法,默认保留6位小数
            '3.141593'
            >>> format(3.14159267000,'0.8f') #小数点计数法,指定保留8位小数
            '3.14159267'
            >>> format(3.14159267000,'0.10f') #小数点计数法,指定保留10位小数
            '3.1415926700'
            >>> format(3.14e+1000000,'F')  #小数点计数法,无穷大转换成大小字母
            'INF'
 
 
        #g的格式化比较特殊,假设p为格式中指定的保留小数位数,先尝试采用科学计数法格式化,得到幂指数exp,如果-4<=exp<p,则采用小数计数法,并保留p-1-exp位小数,否则按小数计数法计数,并按p-1保留小数位数
            >>> format(0.00003141566,'.1g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点
            '3e-05'
            >>> format(0.00003141566,'.2g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留1位小数点
            '3.1e-05'
            >>> format(0.00003141566,'.3g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留2位小数点
            '3.14e-05'
            >>> format(0.00003141566,'.3G') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点,E使用大写
            '3.14E-05'
            >>> format(3.1415926777,'.1g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留0位小数点
            '3'
            >>> format(3.1415926777,'.2g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留1位小数点
            '3.1'
            >>> format(3.1415926777,'.3g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留2位小数点
            '3.14'
            >>> format(0.00003141566,'.1n') #和g相同
            '3e-05'
            >>> format(0.00003141566,'.3n') #和g相同
            '3.14e-05'
            >>> format(0.00003141566) #和g相同
            '3.141566e-05'
 
 
    16.bytes()  转换成bytes类型(转换成二进制类型)
        s = '王秋华'
        print(bytes('王秋华',encoding='utf-8')) #unicode转换成utf-8的bytes
        print(bytes('王秋华',encoding='gbk'))   #unicode转换成gbk的bytes
        print(s.encode('utf-8'))   #unicode转换成utf-8的bytes
        print(s.encode('gbk'))     #unicode转换成gbk的bytes
 
        网络编程:只能传二进制
        照片和视频也是以二进制存储
        html网页爬取到的也是编码
 
 
    17.bytearray([source[, encoding[, errors]]]) 返回一个bytes数组,对数组进行取值,得到转化为十进制的数
                                    返回一个新字节数组。这个数组里的元素是可变的,并且每个元素的值范围: 0 <= x < 256。
        bytearray('王王王',encoding='utf')
            bytearray(b'\xe7\x8e\x8b\xe7\xa7\x8b\xe5\x8d\x8e')
 
        new_s = bytearray('王王王',encoding='utf')
        new_s_lst = []
        for i in new_s:
            new_s_lst.append(i)
        print(new_s_lst)
            [231, 142, 139, 231, 167, 139, 229, 141, 142]
 
    18.memoryview(bytes('hello,eva',encoding='utf-8'))  返回给定参数的内存查看对象(Momory view)。
                        所谓内存查看对象,是指对支持缓冲区协议的数据进行包装,在不需要复制对象基础上允许Python代码访问。
                        针对bytes类型进行字节类型的切片
        切片  ---- 字节类型的切片 不占内存
 
        s = memoryview(bytes('王王王',encoding='utf-8'))
        print(s[1])
 
 
    19.ord()  将unicode的1个字符转换成unicode的1个数字
        chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)
        作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。
        print(ord('f'))
            102
        print(ord('王'))
            29579
    20.chr()  将unicode的1个数字转换成unicode的1个字符
              用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。
        print(chr(97))
            a
 
    21.ascii() 只要是ascii码中的内容,就打印出来,不是就转换成\u
 
    22.repr()  用于%r格式化输出
        print(repr('1'))    '1'
        print(repr(1))      1
 
    23.diet() 字典
 
    24.set()集合
 
    25.frozenset([iterable])  返回一个冻结的集合,冻结后集合不能再添加或删除任何元素。
 
        >>>a = frozenset(range(10))     # 生成一个新的不可变集合
        >>> a
        frozenset([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
        >>> b = frozenset('runoob')
        >>> b
        frozenset(['b', 'r', 'u', 'o', 'n'])   # 创建不可变集合
        >>>
 
相关内置函数
 
    1.len()  长度
 
    2.enumerate(object)  函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,
                         同时列出数据和数据下标,一般用在 for 循环当中
 
        >>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
        >>>list(enumerate(seasons))
        [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
        >>>list(enumerate(seasons, start=1))       # 小标从 1 开始
        [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
 
        普通的 for 循环
            >>>i = 0
            >>>seq = ['one', 'two', 'three']
            >>>for element in seq:
            ...    print(i, seq[i])
            ...    i += 1
            ...
            0 one
            1 two
            2 three
 
        for 循环使用 enumerate
            >>>seq = ['one', 'two', 'three']
            >>>for i, element in enumerate(seq):
            ...    print(i, seq[i])
            ...
            0 one
            1 two
            2 three
 
    3.all(iterable)  如果iterable的所有元素不为0、''、False或者iterable为空,all(iterable)返回True,否则返回False;
                     注意:空元组、空列表返回值为True,这里要特别注意。
                     有一个False就为False
 
    4.any(iterable) 如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true
                    有1个为true就为true
        >>>any(['a', 'b', 'c', 'd'])  # 列表list,元素都不为空或0   True
        >>> any(['a', 'b', '', 'd'])   # 列表list,存在一个为空的元素   True
        >>> any([0, '', False])        # 列表list,元素全为0,'',false  False
        >>> any(('a', 'b', 'c', 'd'))  # 元组tuple,元素都不为空或0  True
        >>> any(('a', 'b', '', 'd'))   # 元组tuple,存在一个为空的元素  True
        >>> any((0, '', False))        # 元组tuple,元素全为0,'',false   False
        >>> any([]) # 空列表    False
        >>> any(()) # 空元组  False
 
    5.zip([iterable, ...]) 拉链方法:
        函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,
        这样做的好处是节约了不少的内存。我们可以使用 list() 转换来输出列表。
        如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
        >>>a = [1,2,3]
        >>> b = [4,5,6]
        >>> c = [4,5,6,7,8]
        >>> zipped = zip(a,b)     # 返回一个对象
        >>> zipped
        <zip object at 0x103abc288>
        >>> list(zipped)  # list() 转换为列表
        [(1, 4), (2, 5), (3, 6)]
        >>> list(zip(a,c))              # 元素个数与最短的列表一致
        [(1, 4), (2, 5), (3, 6)]
 
        >>> a1, a2 = zip(*zip(a,b))          # 与 zip 相反,*zip 可理解为解压,返回二维矩阵式
        >>> list(a1)
        [1, 2, 3]
        >>> list(a2)
        [4, 5, 6]
    6.filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
            该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
 
        exp1:
        def func(n):
            return n % 2 == 1
        ret = filter(func,[1,2,3,4,5,6,7,8,9])
        for i in ret:
            print(i)
        执行结果:1 3 5 7 9
        filter(func,[1,2,3,4,5,6,7,8,9])等同于
        [i for i in [1,2,3,4,5,6,7,8,9] if i % 2 == 1]
 
        exp2:
        过滤只要为字符串的信息:
        def func(s):
            if type(s) == str:
                return True
        ret = filter(func,[1, 'felix','love', 4, 5, 6,'alina'])
        for i in ret:
            print(i)
                felix
                love
                alina
 
        exp3:过滤空内容
        def is_str(s):
            return s and str(s).strip()
        ret = filter(is_str, [1, 'hello','','  ',None,[], 6, 7, 'world', 12, 17])
        print(ret)
        for i in ret:
            print(i)
                1
                hello
                6
                7
                world
                12
                17
        exp3:求1-100 平方根是整数的数
        import math
        def my_sqrt(s):
            #return (s**0.5) % 1 == 0
            return math.sqrt(s) % 1 == 0
        ret = filter(my_sqrt,range(1,101))
        for i in ret:
            print(i)
 
    7.map(function, iterable, ...) 根据提供的函数对指定序列做映射。
 
        >>>def square(x) :            # 计算平方数
        ...     return x ** 2
        ...
        >>> map(square, [1,2,3,4,5])   # 计算列表各个元素的平方
            [1, 4, 9, 16, 25]
        >>> map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函数
            [1, 4, 9, 16, 25]
 
        filter和map:都是返回一个迭代器
            filter
            1.执行filter的结果集合 <= 执行之前的结果
            2.filter只管筛选,不会改变原来的值
 
            map:
            1.执行前后元素个数不变
            2.值可能会发生改变
 
    8.sorted(iterable[, cmp[, key[, reverse]]]) 函数对所有可迭代的对象进行排序操作。
        sort 与 sorted 区别:
        sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
        list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,
        而内建函数sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
 
        >>>a = [5,7,6,3,4,1,2]
        >>> b = sorted(a)       # 保留原列表
        >>> a
        [5, 7, 6, 3, 4, 1, 2]
        >>> b
        [1, 2, 3, 4, 5, 6, 7]
 
        >>> L=[('b',2),('a',1),('c',3),('d',4)]
        >>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1]))   # 利用cmp函数
        [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
        >>> sorted(L, key=lambda x:x[1])               # 利用key
        [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
 
 
        >>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
        >>> sorted(students, key=lambda s: s[2])            # 按年龄排序
        [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
 
        >>> sorted(students, key=lambda s: s[2], reverse=True)       # 按降序
        [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
        >>>
 
        exp2:
        L = [1,-3,7,5,-2,-10]
        print(sorted(L,key=abs,reverse=True))
 
        L = ['sorted','sort','filter','map']
        print(sorted(L,key=len))

  

十、匿名函数

匿名函数
    lambda [arg1 [,arg2,.....argn]]:expression
 
    lambda只是一个表达式,函数体比def简单很多。
    lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
    lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
    虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
 
    exp:
        dic = {'k1': 10, 'k2': 50, 'k3': 100, 'k4': 80}
        print(max(dic,key=lambda k:dic[k]))
 
    内置函数中参数带key的有以下:
    max min filter map sorted
    以上都可以通过和lambda合用完成一些功能
 
    exp2:
    现有两元组tup1,tup2,请使用匿名函数生产列表lst
    tup1 = (('a'),('b'))
    tup2 = (('c'),('d'))
    lst = [{'a':'c'},{'b':'d'}]
 
    写法1:自己写的
    lst = lambda x,y: [{(x[i][0]):y[i][0]} for i in range(len(x))]
    print(lst(tup1,tup2))
        [{'a': 'c'}, {'b': 'd'}]
 
    写法2:
 
    tup1 = (('a'),('b'))
    tup2 = (('c'),('d'))
 
    # lst = [{'a':'c'},{'b':'d'}]
 
    # ret = zip(tup1,tup2)
 
    # def func(t):
    #     return {t[0]:t[1]}
    # func = lambda t:{t[0]:t[1]}
    # res = map(lambda t:{t[0]:t[1]},zip(tup1,tup2))
    print(list(map(lambda t:{t[0]:t[1]},zip(tup1,tup2))))
 
    exp3.以下代码的输出是什么?请给出答案并解释。
    def multipliers():
        return [lambda x:i*x for i in range(4)]
    print([m(2) for m in multipliers()])
    请修改multipliers的定义来产生期望的结果。
 
    解析:
        def multipliers():
            return [lambda x : i *x for i in range(4)]  #返回列表推导式 [lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]
 
        print([m(2) for m in multipliers()])
        # [m(2) for m in [lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]]
        # multipliersw()为[lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]
 
        # [m(2) for m in [lambda x : i *x,lambda x : i *x,lambda x : i *x,lambda x : i *x]]
        # m 为 lambda x : i *m,  4次
        # m(2)   [lambda x : i *2,lambda x : i *2,lambda x : i *2,lambda x : i *2]]
        #而此时multipliers()中的for循环已执行完,i最后的值为3
        # 所以 [lambda x : 3 *2,lambda x : 3 *2,lambda x : 3 *2,lambda x : 3 *2]]
        #[6, 6, 6, 6]
 
    exp4.以下代码的输出是什么?请给出答案并解释。
        def multipliers():
            return (lambda x : i *x for i in range(4))  #返回一个生成器 g =(lambda x : i *x for i in range(4)
 
        print([m(2) for m in multipliers()])
 
        # [m(2) for m in multipliers()]
        # [m(2) for m in (lambda x : i *x for i in range(4)]
        # [m(2) for m in (lambda x : 0 *x,lambda x : 1 *x,lambda x : 2 *x,lambda x : 3 *x]
        # [2 * 0,,2 * 1, 2 * 2,2 * 3]
        #[0,2,4,6]