九 函数

什么是函数?
为什么要用函数?
函数的分类:内置函数与自定义函数
如何自定义函数
  语法
  定义有参数函数,及有参函数的应用场景
  定义无参数函数,及无参函数的应用场景
  定义空函数,及空函数的应用场景
调用函数
    如何调用函数
    函数的返回值
    函数参数的应用:形参和实参,位置参数,关键字参数,默认参数,*args,**kwargs
高阶函数(函数对象)
函数嵌套
作用域与名称空间
装饰器
迭代器与生成器及协程函数
三元运算,列表解析、生成器表达式
函数的递归调用
内置函数
面向过程编程与函数式编程

本节课程重点

一:为何用函数之不使用函数的问题    #组织结构不清晰    #代码冗余    #无法统一管理且维护难度大

二:函数分类:    1. 内置函数    2. 自定义函数

三:为何要定义函数    函数即变量,变量必须先定义后使用,未定义而直接引用函数,就相当于在引用一个不存在的变量名    代码演示?

四:定义函数都干了哪些事?    只检测语法,不执行代码

五:如何定义函数(函数名要能反映其意义)    def ...

六:定义函数的三种形式    无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印    有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值    空函数:设计代码结构

七 :函数的调用    1 先找到名字    2 根据名字调用代码    函数的返回值?  0->None  1->返回1个值  多个->元组

  什么时候该有?    调用函数,经过一系列的操作,最后要拿到一个明确的结果,则必须要有返回值    通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果  什么时候不需要有?    调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值    通常无参函数不需要有返回值

八:函数调用的三种形式  1 语句形式:foo()  2 表达式形式:3*len(‘hello‘)  4 当中另外一个函数的参数:range(len(‘hello‘))

九:函数的参数: 1 形参和实参定义 2 形参即变量名,实参即变量值,函数调用则将值绑定到名字上,函数调用结束,解除绑定 3 具体应用    位置参数:按照从左到右的顺序定义的参数        位置形参:必选参数        位置实参:按照位置给形参传值

关键字参数:按照key=value的形式定义实参        无需按照位置为形参传值        注意的问题:                1. 关键字实参必须在位置实参右面                2. 对同一个形参不能重复传值

默认参数:形参在定义时就已经为其赋值        可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)        注意的问题:                1. 只在定义时赋值一次                2. 默认参数的定义应该在位置形参右面                3. 默认参数通常应该定义成不可变类型

可变长参数:        针对实参在定义时长度不固定的情况,应该从形参的角度找到可以接收可变长实参的方案,这就是可变长参数(形参)        而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参也应该有两种解决方案,分别是*args,**kwargs
 ===========*args===========
        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,3,4,5)

        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,*[3,4,5])

        def foo(x,y,z):
            print(x,y,z)
        foo(*[1,2,3])

        ===========**kwargs===========
        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,a=1,b=2,c=3)

        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,**{‘a‘:1,‘b‘:2,‘c‘:3})

        def foo(x,y,z):
            print(x,y,z)
        foo(**{‘z‘:1,‘x‘:2,‘y‘:3})

        ===========*args+**kwargs===========

        def foo(x,y):
            print(x,y)

        def wrapper(*args,**kwargs):
            print(‘====>‘)
            foo(*args,**kwargs)
  命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递  可以保证,传入的参数中一定包含某些关键字
        def foo(x,y,*args,a=1,b,**kwargs):
            print(x,y)
            print(args)
            print(a)
            print(b)
            print(kwargs)

        foo(1,2,3,4,5,b=3,c=4,d=5)
        结果:
            1
            2
            (3, 4, 5)
            1
            3
            {‘c‘: 4, ‘d‘: 5}
十 阶段性练习

1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作
2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数

3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。

4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。

6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
PS:字典中的value只能是字符串或列表

#题目一
def modify_file(filename,old,new):
    import os
    with open(filename,‘r‘,encoding=‘utf-8‘) as read_f,        open(‘.bak.swap‘,‘w‘,encoding=‘utf-8‘) as write_f:
        for line in read_f:
            if old in line:
                line=line.replace(old,new)
            write_f.write(line)
    os.remove(filename)
    os.rename(‘.bak.swap‘,filename)

modify_file(‘/Users/jieli/PycharmProjects/爬虫/a.txt‘,‘alex‘,‘SB‘)

#题目二
def check_str(msg):
    res={
        ‘num‘:0,
        ‘string‘:0,
        ‘space‘:0,
        ‘other‘:0,
    }
    for s in msg:
        if s.isdigit():
            res[‘num‘]+=1
        elif s.isalpha():
            res[‘string‘]+=1
        elif s.isspace():
            res[‘space‘]+=1
        else:
            res[‘other‘]+=1
    return res

res=check_str(‘hello name:aSB passowrd:alex3714‘)
print(res)

#题目三:略

#题目四
def func1(seq):
    if len(seq) > 2:
        seq=seq[0:2]
    return seq
print(func1([1,2,3,4]))

#题目五
def func2(seq):
    return seq[::2]
print(func2([1,2,3,4,5,6,7]))

#题目六
def func3(dic):
    d={}
    for k,v in dic.items():
        if len(v) > 2:
            d[k]=v[0:2]
    return d
print(func3({‘k1‘:‘abcdef‘,‘k2‘:[1,2,3,4],‘k3‘:(‘a‘,‘b‘,‘c‘)}))

题目答案

=======================本节课新内容==========================    一:函数对象:函数是第一类对象,即函数可以当作数据传递    1 可以被引用    2 可以当作参数传递    3 返回值可以是函数    3 可以当作容器类型的元素        #利用该特性,优雅的取代多分支的if        def foo():            print(‘foo‘)

def bar():            print(‘bar‘)

dic={            ‘foo‘:foo,            ‘bar‘:bar,        }        while True:            choice=input(‘>>: ‘).strip()            if choice in dic:                dic[choice]()

二:函数的嵌套        1 函数的嵌套调用            def max(x,y):                return x if x > y else y

def max4(a,b,c,d):                res1=max(a,b)                res2=max(res1,c)                res3=max(res2,d)                return res3            print(max4(1,2,3,4))

2 函数的嵌套定义            def f1():                def f2():                    def f3():                        print(‘from f3‘)                    f3()                f2()

f1()            f3() #报错

三 名称空间和作用域:        名称空间:存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)        加载顺序是?        名字的查找顺序?(在全局无法查看局部的,在局部可以查看全局的)
        # max=1        def f1():            # max=2            def f2():                # max=3                print(max)            f2()        f1()        print(max)

作用域即范围       - 全局范围:全局存活,全局有效       - 局部范围:临时存活,局部有效          - 作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
      x=1      def f1():          def f2():              print(x)          return f2

      def f3(func):          x=2          func()

      f3(f1())

查看作用域:globals(),locals()

global        nonlocal

LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__        locals 是函数内的名字空间,包括局部变量和形参        enclosing 外部嵌套函数的名字空间(闭包中常见)        globals 全局变量,函数定义所在模块的名字空间        builtins 内置模块的名字空间

四:闭包:内部函数包含对外部作用域而非全局作用域的引用       提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来喽,包起呦,包起来哇

def counter():            n=0            def incr():                nonlocal n                x=n                n+=1                return x            return incr

c=counter()        print(c())        print(c())        print(c())        print(c.__closure__[0].cell_contents) #查看闭包的元素

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域    应用领域:延迟计算(原来我们是传参,现在我们是包起来)    from urllib.request import urlopen

def index(url):        def get():            return urlopen(url).read()        return get

baidu=index(‘http://www.baidu.com‘)    print(baidu().decode(‘utf-8‘))

五: 装饰器(闭包函数的一种应用场景)

1 为何要用装饰器:        开放封闭原则:对修改封闭,对扩展开放

2 什么是装饰器       装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。       强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式       装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

3. 先看简单示范        import time        def timmer(func):            def wrapper(*args,**kwargs):                start_time=time.time()                res=func(*args,**kwargs)                stop_time=time.time()                print(‘run time is %s‘ %(stop_time-start_time))                return res            return wrapper

@timmer        def foo():            time.sleep(3)            print(‘from foo‘)        foo()

4    def auth(driver=‘file‘):        def auth2(func):            def wrapper(*args,**kwargs):                name=input("user: ")                pwd=input("pwd: ")

if driver == ‘file‘:                    if name == ‘egon‘ and pwd == ‘123‘:                        print(‘login successful‘)                        res=func(*args,**kwargs)                        return res                elif driver == ‘ldap‘:                    print(‘ldap‘)            return wrapper        return auth2

@auth(driver=‘file‘)    def foo(name):        print(name)

foo(‘egon‘)

5 装饰器语法:        被装饰函数的正上方,单独一行        @deco1        @deco2        @deco3        def foo():            pass

foo=deco1(deco2(deco3(foo)))

  6 装饰器补充:wraps
from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    ‘‘‘哈哈哈哈‘‘‘
    print(‘from index‘)

print(index.__doc__)
 7 装饰器练习

一:编写函数,(函数执行的时间是随机的)
二:编写装饰器,为函数加上统计时间的功能
三:编写装饰器,为函数加上认证的功能

四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval(‘{"name":"egon","password":"123"}‘)转成字典格式

五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录

六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果

七:为题目五编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中

扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中

八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作

九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
注意:时间格式的获取
import time
time.strftime(‘%Y-%m-%d %X‘)

#题目一:略
#题目二:略
#题目三:略
#题目四:
db=‘db.txt‘
login_status={‘user‘:None,‘status‘:False}
def auth(auth_type=‘file‘):
    def auth2(func):
        def wrapper(*args,**kwargs):
            if login_status[‘user‘] and login_status[‘status‘]:
                return func(*args,**kwargs)
            if auth_type == ‘file‘:
                with open(db,encoding=‘utf-8‘) as f:
                    dic=eval(f.read())
                name=input(‘username: ‘).strip()
                password=input(‘password: ‘).strip()
                if name in dic and password == dic[name]:
                    login_status[‘user‘]=name
                    login_status[‘status‘]=True
                    res=func(*args,**kwargs)
                    return res
                else:
                    print(‘username or password error‘)
            elif auth_type == ‘sql‘:
                pass
            else:
                pass
        return wrapper
    return auth2

@auth()
def index():
    print(‘index‘)

@auth(auth_type=‘file‘)
def home(name):
    print(‘welcome %s to home‘ %name)

# index()
# home(‘egon‘)

#题目五
import time,random
user={‘user‘:None,‘login_time‘:None,‘timeout‘:0.000003,}

def timmer(func):
    def wrapper(*args,**kwargs):
        s1=time.time()
        res=func(*args,**kwargs)
        s2=time.time()
        print(‘%s‘ %(s2-s1))
        return res
    return wrapper

def auth(func):
    def wrapper(*args,**kwargs):
        if user[‘user‘]:
            timeout=time.time()-user[‘login_time‘]
            if timeout < user[‘timeout‘]:
                return func(*args,**kwargs)
        name=input(‘name>>: ‘).strip()
        password=input(‘password>>: ‘).strip()
        if name == ‘egon‘ and password == ‘123‘:
            user[‘user‘]=name
            user[‘login_time‘]=time.time()
            res=func(*args,**kwargs)
            return res
    return wrapper

@auth
def index():
    time.sleep(random.randrange(3))
    print(‘welcome to index‘)

@auth
def home(name):
    time.sleep(random.randrange(3))
    print(‘welcome %s to home ‘ %name)

index()
home(‘egon‘)

#题目六:略
#题目七:简单版本
import requests
import os
cache_file=‘cache.txt‘
def make_cache(func):
    def wrapper(*args,**kwargs):
        if not os.path.exists(cache_file):
            with open(cache_file,‘w‘):pass

        if os.path.getsize(cache_file):
            with open(cache_file,‘r‘,encoding=‘utf-8‘) as f:
                res=f.read()
        else:
            res=func(*args,**kwargs)
            with open(cache_file,‘w‘,encoding=‘utf-8‘) as f:
                f.write(res)
        return res
    return wrapper

@make_cache
def get(url):
    return requests.get(url).text

# res=get(‘https://www.python.org‘)

# print(res)

#题目七:扩展版本
import requests,os,hashlib
engine_settings={
    ‘file‘:{‘dirname‘:‘./db‘},
    ‘mysql‘:{
        ‘host‘:‘127.0.0.1‘,
        ‘port‘:3306,
        ‘user‘:‘root‘,
        ‘password‘:‘123‘},
    ‘redis‘:{
        ‘host‘:‘127.0.0.1‘,
        ‘port‘:6379,
        ‘user‘:‘root‘,
        ‘password‘:‘123‘},
}

def make_cache(engine=‘file‘):
    if engine not in engine_settings:
        raise TypeError(‘egine not valid‘)
    def deco(func):
        def wrapper(url):
            if engine == ‘file‘:
                m=hashlib.md5(url.encode(‘utf-8‘))
                cache_filename=m.hexdigest()
                cache_filepath=r‘%s/%s‘ %(engine_settings[‘file‘][‘dirname‘],cache_filename)

                if os.path.exists(cache_filepath) and os.path.getsize(cache_filepath):
                    return open(cache_filepath,encoding=‘utf-8‘).read()

                res=func(url)
                with open(cache_filepath,‘w‘,encoding=‘utf-8‘) as f:
                    f.write(res)
                return res
            elif engine == ‘mysql‘:
                pass
            elif engine == ‘redis‘:
                pass
            else:
                pass

        return wrapper
    return deco

@make_cache(engine=‘file‘)
def get(url):
    return requests.get(url).text

# print(get(‘https://www.python.org‘))
print(get(‘https://www.baidu.com‘))

#题目八
route_dic={}

def make_route(name):
    def deco(func):
        route_dic[name]=func
    return deco
@make_route(‘select‘)
def func1():
    print(‘select‘)

@make_route(‘insert‘)
def func2():
    print(‘insert‘)

@make_route(‘update‘)
def func3():
    print(‘update‘)

@make_route(‘delete‘)
def func4():
    print(‘delete‘)

print(route_dic)

#题目九
import time
import os

def logger(logfile):
    def deco(func):
        if not os.path.exists(logfile):
            with open(logfile,‘w‘):pass

        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            with open(logfile,‘a‘,encoding=‘utf-8‘) as f:
                f.write(‘%s %s run\n‘ %(time.strftime(‘%Y-%m-%d %X‘),func.__name__))
            return res
        return wrapper
    return deco

@logger(logfile=‘aaaaaaaaaaaaaaaaaaaaa.log‘)
def index():
    print(‘index‘)

index()
   六:迭代器        迭代的概念:重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值            # while True: #只满足重复,因而不是迭代            #     print(‘====>‘)

#迭代            l=[1,2,3]            count=0            while count < len(l): #只满足重复,因而不是迭代                print(‘====>‘,l[count])                count+=1

为何要有迭代器?        可迭代的对象?        哪些是可迭代对象?        迭代器?            l={‘a‘:1,‘b‘:2,‘c‘:3,‘d‘:4,‘e‘:5}            i=l.__iter__() #等于i=iter(l)

print(next(i))            print(next(i))            print(next(i))        StopIteration?

for循环

迭代器的优缺点:            优点:                提供统一的且不依赖于索引的迭代方式                惰性计算,节省内存            缺点:                无法获取长度                一次性的,只能往后走,不能往前退

迭代器协议

  练习:判断以下对象哪个是可迭代对象,哪个是迭代器对象

s=‘hello‘
l=[1,2,3,4]
t=(1,2,3)
d={‘a‘:1}
set={1,2,3}
f=open(‘a.txt‘)

   七 生成器   yield:    把函数做成迭代器    对比return,可以返回多次值,挂起函数的运行状态
    # def foo():
    #     return 1
    #     return 2
    #     return 3
    #
    # res=foo()
    # print(res)

    def foo():
        yield 1
        yield 2
        yield 3

    res=foo()
    print(res)

    from collections import Iterable,Iterator
    print(isinstance(res,Iterator))

    print(next(res))
    print(next(res))
    print(next(res))

    应用一:
        def counter(n):
            print(‘start‘)
            i=0
            while i < n:
                yield i
                i+=1
            print(‘end‘)

        c=counter(5)
        # print(next(c)) #0
        # print(next(c)) #1
        # print(next(c)) #2
        # print(next(c)) #3
        # print(next(c)) #4
        # print(next(c)) #5 --->没有yield,抛出StopIteration

        for i in counter(5):
            print(i)

    应用二:管道tail -f a.txt |grep ‘python‘
    import time
    def tail(filepath):
        with open(filepath,encoding=‘utf-8‘) as f:
            f.seek(0,2)
            while True:
                line=f.readline()
                if line:
                    yield line
                else:
                    time.sleep(0.5)

    def grep(pattern,lines):
        for line in lines:
            if pattern in line:
                yield line

    for i in grep(‘python‘,tail(‘a.txt‘)):
        print(i)

    #协程函数
        def eater(name):
            print(‘%s说:我开动啦‘ %name)
            food_list=[]
            while True:
                food=yield food_list
                food_list.append(food)
                print(‘%s 吃了 %s‘ %(name,food))

        e=eater(‘egon‘)
        e.send(None) #next(e) #初始化装饰器,
        e.close() #关闭

    面向过程编程:
        import os
        def init(func):
            def wrapper(*args,**kwargs):
                g=func(*args,**kwargs)
                next(g)
                return g
            return wrapper

        def search(file_dir,target):
            for par_dir,_,files in os.walk(file_dir):
                for file in files:
                    filepath=‘%s\%s‘ %(par_dir,file)
                    target.send(filepath)

        @init
        def opener(target):
            while True:
                filepath=yield
                with open(filepath) as f:
                    target.send((f,filepath))
        @init
        def cat(target):
            while True:
                res=False
                f,filepath=yield res
                for line in f:
                    print(line,end=‘‘)
                    res=target.send((line,filepath))
                    if res:
                        break

        @init
        def grep(pattern,target):
            res = False
            while True:
                line,filepath=yield res
                res=False
                if pattern in line:
                    res=True
                    target.send(filepath)

        @init
        def printer():
            while True:
                filepath=yield
                print(filepath)

        search(r‘C:\Users\Administrator\PycharmProjects\test\字符编码\a‘,
               opener(cat(grep(‘python‘,printer()))))

#注意:target.send(...)在拿到target的返回值后才算执行结束
import os

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init
def search(target):
    while True:
        search_dir=yield
        for par_dir,_,files in os.walk(search_dir):
            for file in files:
                file_abs_path=r‘%s\%s‘ %(par_dir,file)
                # print(file_abs_path)
                target.send(file_abs_path)
@init
def opener(target):
    while True:
        file_abs_path=yield
        with open(file_abs_path,encoding=‘utf-8‘) as f:
            target.send((file_abs_path,f))
@init
def cat(target):
    while True:
        file_abs_path,f=yield
        print(‘检索文件‘,file_abs_path)
        for line in f:
            tag=target.send((file_abs_path,line))
            print(‘检索文件的行: %s‘ %line)
            if tag:
                break

@init
def grep(pattern,target):
    tag=False
    while True:
        file_abs_path,line=yield tag
        tag=False
        if pattern in line:
            tag=True
            target.send(file_abs_path)
@init
def printer():
    while True:
        file_abs_path=yield
        print(‘过滤出的结果=========>‘,file_abs_path)

search_dir=r‘C:\Users\Administrator\PycharmProjects\test\函数备课\a‘
e=search(opener(cat(grep(‘python‘,printer()))))
e.send(search_dir)

备注

八:三元表达式,列表推导式,生成器表达式

==============================#三元表达式
name=‘alex‘
name=‘linhaifeng‘
res=‘SB‘ if name == ‘alex‘ else ‘shuai‘
print(res)

==============================列表推导式
------------------1:引子
生一筐鸡蛋
egg_list=[]
for i in range(10):
egg_list.append(‘鸡蛋%s‘ %i)

egg_list=[‘鸡蛋%s‘ %i for i in range(10)] #列表解析

------------------2:语法
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
类似于
res=[]
for item1 in iterable1:
if condition1:
for item2 in iterable2:
if condition2
...
for itemN in iterableN:
if conditionN:
res.append(expression)

------------------3:优点
方便,改变了编程习惯,声明式编程

------------------4:应用
l1=[3,-4,-1,5,7,9]

[i**i for i in l1]

[i for i in l1 if i >0]

s=‘egon‘
[(i,j) for i in l1 if i>0 for j in s] #元组合必须加括号[i,j ...]非法

==============================生成器表达式
------------------1:引子
生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
egg_list=[]
for i in range(10):
egg_list.append(‘鸡蛋%s‘ %i)

chicken=(‘鸡蛋%s‘ %i for i in range(10))
>>> chicken
<generator object <genexpr> at 0x10143f200>
>>> next(chicken)
‘鸡蛋5‘

------------------2:语法
语法与列表推导式类似,只是[]->()

(expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
)

------------------3:优点
省内存,一次只产生一个值在内存中

------------------4:应用
读取一个大文件的所有内容,并且处理行
f=open(‘a.txt‘)
g=(line.strip() for line in f)

list(g) #因g可迭代,因而可以转成列表

------------------5:示例
#一
with open(‘a.txt‘) as f:
    print(max(len(line) for line in f))
    print(sum(len(line) for line in f)) #求包换换行符在内的文件所有的字节数,为何得到的值为0?

#二
print(max(len(line) for line in open(‘a.txt‘)))
print(sum(len(line) for line in open(‘a.txt‘)))

#三
with open(‘a.txt‘) as f:
    g=(len(line) for line in f)
print(sum(g)) #为何报错?

==============================声明式编程
文件a.txt内容
apple 10 3
tesla 100000 1
mac 3000 2
lenovo 30000 3
chicken 10 3

f=open(‘a.py‘)
#求花了多少钱
g=(line.split() for line in f)

sum(float(price)*float(count) for _,price,count in g)

模拟数据库查询
>>> f=open(‘a.txt‘)
>>> g=(line.split() for line in f)
>>> goods_l=[{‘name‘:n,‘price‘:p,‘count‘:c} for n,p,c in g]

过滤查询
>>> goods_l=[{‘name‘:n,‘price‘:p,‘count‘:c} for n,p,c in g if float(p) > 10000]

九:匿名函数lambda

匿名就是没有名字
def func(x,y,z=1):
return x+y+z

匿名
lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
func=lambda x,y,z=1:x+y+z 
func(1,2,3)
#让其有名字就没有意义

有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能

匿名函数:一次性使用,随时随时定义

应用:max,min,sorted,map,reduce,filter

十 内建函数

注意:内置函数id()可以返回一个对象的身份,返回值为整数。这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以内存地址为准。is运算符用于比较两个对象的身份,等号比较两个对象的值,内置函数type()则返回一个对象的类型

字典的运算:最小值,最大值,排序
salaries={
    ‘egon‘:3000,
    ‘alex‘:100000000,
    ‘wupeiqi‘:10000,
    ‘yuanhao‘:2000
}

迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
‘yuanhao‘
>>> min(salaries)
‘alex‘

可以取values,来比较
>>> max(salaries.values())
>>> min(salaries.values())
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
‘alex‘
>>> min(salaries,key=lambda k:salary[k])
‘yuanhao‘

也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys()) 

先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, ‘alex‘)

salaries_and_names是迭代器,因而只能访问一次
>>> min(salaries_and_names)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence

sorted(iterable,key=None,reverse=False)

#字符串可以提供的参数 ‘s‘ None
>>> format(‘some string‘,‘s‘)
‘some string‘
>>> format(‘some string‘)
‘some string‘

#整形数值可以提供的参数有 ‘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‘

format(了解即可)

十一:内建函数补充(结合lambda)

字典的运算:最小值,最大值,排序
salaries={
‘egon‘:3000,
‘alex‘:100000000,
‘wupeiqi‘:10000,
‘yuanhao‘:2000
}

迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
‘yuanhao‘
>>> min(salaries)
‘alex‘

可以取values,来比较
>>> max(salaries.values())
100000000
>>> min(salaries.values())
2000
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
‘alex‘
>>> min(salaries,key=lambda k:salary[k])
‘yuanhao‘

也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys())

先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, ‘alex‘)

salaries_and_names是迭代器,因而只能访问一次
>>> min(salaries_and_names)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence

sorted(iterable,key=None,reverse=False)

#eval与compile

eval(str,[,globasl[,locals]])
eval(‘1+2+max(3,9,100)+1.3‘)

my_globals={‘x‘:1}
my_locals={‘x‘:2}
eval(‘1+x‘,my_globals,my_locals)

exec(‘for i in range(10):print("i")‘)
同样可以指定自己的名称空间

compile(str,filename,kind)
filename:用于追踪str来自于哪个文件,如果不想追踪就可以不定义
kind可以是:single代表一条语句,exec代表一组语句,eval代表一个表达式

s=‘for i in range(10):print(i)‘
code=compile(s,‘‘,‘exec‘)
exec(code)

s=‘1+2+3‘
code=compile(s,‘‘,‘eval‘)
eval(code)
  十二:函数的递归调用

        图解:递推和回溯

        # salary(5)=salary(4)+300
        # salary(4)=salary(3)+300
        # salary(3)=salary(2)+300
        # salary(2)=salary(1)+300
        # salary(1)=100
        #
        # salary(n)=salary(n-1)+300     n>1
        # salary(1) =100                n=1

        def salary(n):
            if n == 1:
                return 100
            return salary(n-1)+300

        print(salary(5))
函数在调用时,直接或间接调用了自身,就是递归调用

def fac(n):#阶乘运算
if n == 1:return 1
else:return n*fib(n-1)

递归效率低,需要在进入下一次递归时保留当前的状态,见51cto博客
解决方法是尾递归,即在函数的最后一步(而非最后一行)调用自己
但是python又没有尾递归,且对递归层级做了限制

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
尾递归优化:http://egon09.blog.51cto.com/9161406/1842475

>>> sys.getrecursionlimit()
1000

>>> n=1
>>> def test():
... global n
... n+=1
... print(n)
... test()
...
>>> test()

>>> sys.setrecursionlimit(10000)
>>> test() #可以递归10000层了

虽然可以设置,但是因为不是尾递归,仍然要保存栈,内存大小一定,不可能无限递归

  十三 阶段性练习:

1 文件内容如下,标题为:姓名,性别,年纪,薪资

egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000
yuanhao female 28 10000

要求:
从文件中取出每一条记录放入列表中,
列表的每个元素都是{‘name‘:‘egon‘,‘sex‘:‘male‘,‘age‘:18,‘salary‘:3000}的形式

2 根据1得到的列表,取出薪资最高的人的信息
3 根据1得到的列表,取出最年轻的人的信息
4 根据1得到的列表,将每个人的信息中的名字映射成首字母大写的形式
5 根据1得到的列表,过滤掉名字以a开头的人的信息
6 使用递归打印斐波那契数列(前两个数的和得到第三个数)
0 1 1 2 3 4 7...

7 l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]]
  一个列表嵌套很多层,用递归取出所有的值
#1
with open(‘db.txt‘) as f:
    items=(line.split() for line in f)
    info=[{‘name‘:name,‘sex‘:sex,‘age‘:age,‘salary‘:salary}           for name,sex,age,salary in items]

print(info)
#2
print(max(info,key=lambda dic:dic[‘salary‘]))

#3
print(min(info,key=lambda dic:dic[‘age‘]))

# 4
info_new=map(lambda item:{‘name‘:item[‘name‘].capitalize(),
                          ‘sex‘:item[‘sex‘],
                          ‘age‘:item[‘age‘],
                          ‘salary‘:item[‘salary‘]},info)

print(list(info_new))

#5
g=filter(lambda item:item[‘name‘].startswith(‘a‘),info)
print(list(g))

#6
#非递归
def fib(n):
    a,b=0,1
    while a < n:
        print(a,end=‘ ‘)
        a,b=b,a+b
    print()

fib(10)
#递归
def fib(a,b,stop):
    if  a > stop:
        return
    print(a,end=‘ ‘)
    fib(b,a+b,stop)

fib(0,1,10)

#7
l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]]

def get(seq):
    for item in seq:
        if type(item) is list:
            get(item)
        else:
            print(item)
get(l)
  十四:二分法

        l=[1,2,10,2,30,40,33,22,99,31]
        def search(num,l):
            print(l)
            if len(l) > 1:
                mid=len(l)//2
                if num > l[mid]:
                    #in the right
                    l=l[mid:]
                    search(num,l)
                elif num < l[mid]:
                    #in the left
                    l=l[:mid]
                    search(num,l)
                else:
                    print(‘find it‘)
            else:
                if num == l[0]:
                    print(‘find it‘)
                else:
                    print(‘not exists‘)

        search(100,l)
def search(seq,num):
    print(seq)
    if len(seq) == 1:
        if num == seq[0]:
            print(‘you find it‘)
        else:
            print(‘not exist‘)
        return
    mid=len(seq)//2
    if num > seq[mid]:
        #in the right
        seq=seq[mid:]
        search(seq,num)
    elif num < seq[mid]:
        #in the left
        seq=seq[:mid]
        search(seq,num)
    else:
        print(‘find it‘)

search(l,3)

十五:面向过程编程,函数式编程

峰哥原创面向过程解释:

函数的参数传入,是函数吃进去的食物,而函数return的返回值,是函数拉出来的结果,面向过程的思路就是,把程序的执行当做一串首尾相连的函数,一个函数吃,拉出的东西给另外一个函数吃,另外一个函数吃了再继续拉给下一个函数吃。。。

面向过程:机械式思维,流水线式编程

例如:
用户登录流程:前端接收处理用户请求-》将用户信息传给逻辑层,逻辑词处理用户信息-》将用户信息写入数据库
验证用户登录流程:数据库查询/处理用户信息-》交给逻辑层,逻辑层处理用户信息-》用户信息交给前端,前端显示用户信息。

array=[1,3,4,71,2]

ret=[]
for i in array:
ret.append(i**2)
print(ret)

#如果我们有一万个列表,那么你只能把上面的逻辑定义成函数
def map_test(array):
ret=[]
for i in array:
ret.append(i**2)
return ret

print(map_test(array))

#如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样
def add_num(x):
return x+1
def map_test(func,array):
ret=[]
for i in array:
ret.append(func(i))
return ret

print(map_test(add_num,array))
#可以使用匿名函数
print(map_test(lambda x:x-1,array))

#上面就是map函数的功能,map得到的结果是可迭代对象
print(map(lambda x:x-1,range(5)))

map

from functools import reduce
#合并,得一个合并的结果
array_test=[1,2,3,4,5,6,7]
array=range(100)

#报错啊,res没有指定初始值
def reduce_test(func,array):
l=list(array)
for i in l:
res=func(res,i)
return res

# print(reduce_test(lambda x,y:x+y,array))

#可以从列表左边弹出第一个值
def reduce_test(func,array):
l=list(array)
res=l.pop(0)
for i in l:
res=func(res,i)
return res

print(reduce_test(lambda x,y:x+y,array))

#我们应该支持用户自己传入初始值
def reduce_test(func,array,init=None):
l=list(array)
if init is None:
res=l.pop(0)
else:
res=init
for i in l:
res=func(res,i)
return res

print(reduce_test(lambda x,y:x+y,array))
print(reduce_test(lambda x,y:x+y,array,50))

reduce

movie_people=[‘alex‘,‘wupeiqi‘,‘yuanhao‘,‘sb_alex‘,‘sb_wupeiqi‘,‘sb_yuanhao‘]

def tell_sb(x):
return x.startswith(‘sb‘)

def filter_test(func,array):
ret=[]
for i in array:
if func(i):
ret.append(i)
return ret

print(filter_test(tell_sb,movie_people))

#函数filter,返回可迭代对象
print(filter(lambda x:x.startswith(‘sb‘),movie_people))

filter

#当然了,map,filter,reduce,可以处理所有数据类型

name_dic=[
{‘name‘:‘alex‘,‘age‘:1000},
{‘name‘:‘wupeiqi‘,‘age‘:10000},
{‘name‘:‘yuanhao‘,‘age‘:9000},
{‘name‘:‘linhaifeng‘,‘age‘:18},
]
#利用filter过滤掉千年王八,万年龟,还有一个九千岁
def func(x):
age_list=[1000,10000,9000]
return x[‘age‘] not in age_list

res=filter(func,name_dic)
for i in res:
print(i)

res=filter(lambda x:x[‘age‘] == 18,name_dic)
for i in res:
print(i)

#reduce用来计算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))
print(reduce(lambda x,y:x+y,range(1,101)))

#用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb
name=[‘alex‘,‘wupeiqi‘,‘yuanhao‘]

res=map(lambda x:x+‘_sb‘,name)
for i in res:
print(i)

总结

一 数据结构和算法

‘‘‘
不可变:数字,字符串,元组
可变:列表,字典

原子:数字,字符串
容器:列表,元组,字典

直接访问:数字
顺序:字符串,列表,元组
映射访问:字典

‘‘‘

#一一对应
a,b,c,d,e=‘hello‘
print(e,d)

#少一个报错
# a,b,c=‘hello‘

#*号的使用
a,*_,e=‘hello‘
print(a,e)

#列表中的元素解压也是一一对应的关系
data=[‘mac‘,10000,[2016,10,12]]
name,price,date=data
print(name,price,date)

#截取子元素
name,price,[year,month,day]=data
print(name,price,year,month,day)

#无用的元素用_代替
data=[‘mac‘,10000,[2016,10,12]]
_,price,_=data
print(price)

#头截取,尾截取
record=[‘lhf‘,‘male‘,18,‘[email protected]‘,‘1861131211‘]
*_,phone=record
name,*_=record
print(phone)
print(name)

#解压可迭代对象赋值给多个值
#一个八个月的业绩与前七个月的平均值比较

sales_record=[11,12,3,7,9,6,3,5]
*head,tail=sales_record
print(head,tail)
print(sum(head)/len(head))
if tail > sum(head)/len(head):
    print(‘第八个月业绩高于前七个月平均值‘)
elif tail == sum(head)/len(head):
    print(‘第八个月业绩等于前七个月平均值‘)
else:
    print(‘第八个月业绩小于前七个月平均值‘)

#解压元素在函数中的应用

records=[
    (‘say_hi‘,‘hello‘),
    (‘calculate‘,10,20,30,40),
    (‘dic_handle‘,‘name‘,‘lhf‘)
]

def say_hi(msg):
    print(msg)

def calculate(l):
    res=0
    for i in l:
        res+=i
    print(res)

def dic_handle(l):
    key,val=l
    dic={key:val}
    print(dic)

for func,*args in records:
    if func == ‘say_hi‘:
        say_hi(args)
    elif func == ‘calculate‘:
        calculate(args)
    elif func == ‘dic_handle‘:
        dic_handle(args)

#linux系统中用户记录
record=‘root:x:0:0:super user:/root:/bin/bash‘
*head,home_dir,_=record.split(‘:‘)
print(‘家目录‘,home_dir)

解压序列赋值给多个变量

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
from collections import deque

# #实现队列,不指定大小则无限添加
# d=deque(maxlen=3)
# d.append(1)
# d.append(2)
# d.append(3)
# print(d)
# d.append(4)
# print(d)
# d.appendleft(5)
# print(d)
# print(d.pop())
# print(d.popleft())

def search(file,pattern,max_len=5):
    pre_lines=deque(maxlen=max_len)
    for line in file:
        if pattern in line:
            yield pre_lines,line
        pre_lines.append(line)

if __name__ == ‘__main__‘:
    with open(‘测试文件‘) as file:
        for pre_l,line in search(file,‘Exchange‘):
            print(‘-‘*60)
            for i in pre_l:
                print(i)
            print(‘匹配行----->‘,line)

保留最后n个元素

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘

import heapq

nums=[1,2,3,-10,100,30,200,21,9,7]
print(heapq.nlargest(3,nums))
print(heapq.nsmallest(3,nums))

portfolio=[
    {‘name‘:‘IBM‘,‘shares‘:100,‘price‘:91.1},
    {‘name‘:‘AAPL‘,‘shares‘:50,‘price‘:532.1},
    {‘name‘:‘FB‘,‘shares‘:200,‘price‘:21.01},
    {‘name‘:‘HPQ‘,‘shares‘:35,‘price‘:32.75},
    {‘name‘:‘YHOO‘,‘shares‘:45,‘price‘:16.35},
    {‘name‘:‘ACME‘,‘shares‘:75,‘price‘:115.65}
]

cheap=heapq.nsmallest(3,portfolio,key=lambda x:x[‘price‘])
print(cheap)

‘‘‘
如果你想在一个集合中查找最小或最大的N个元素,
并且N小于集合元素数量, 那么这些函数提供了很好的性能。
因为在底层实现里面,首先会先将集合数据进行堆
排序后放入一个列表中
‘‘‘

heapq.heapify(nums)
print(nums)
‘‘‘
堆数据结构最重要的特征是heap[0]永远是最小的元素。
并且剩余的元素可以很 容易的通过调用heap.heappop()方法得到,
该方法会先将第一个元素弹出来,然后 用下一个最小的元素来取代被弹出元素
(这种操作时间复杂度仅仅是O(log N),N是堆大小。)比如,如果想要查找最小的3个元素,
你可以这样做:
‘‘‘
print(heapq.heappop(nums))
print(heapq.heappop(nums))
print(heapq.heappop(nums))

‘‘‘
nlarges(),nsmallest():当要查找的元素个数相对较小时使用
min(),max():就是要找唯一一个最大的或者最小的值时使用
sort[items][n:m]:当要查找的元素个数相接近items长度时使用
‘‘‘

查找最大或最小的n个元素

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
import heapq

class PriotryQueue:
    def __init__(self):
        self._queue=[]
        self._index=0

    def push(self,item,priotry):
        heapq.heappush(self._queue,(-priotry,self._index,item))
        self._index+=1

    def pop(self):
        return heapq.heappop(self._queue)[-1]

class Item:
    def __init__(self,name):
        self.name=name

    def __str__(self):
        return self.name

    def __repr__(self):
        # return self.name
        return ‘Item({!r})‘.format(self.name)
q=PriotryQueue()
q.push(Item(‘镇长‘),1)
q.push(Item(‘省长‘),4)
q.push(Item(‘主席‘),5)
q.push(Item(‘市长‘),3)
q.push(Item(‘县长‘),2)

print(q._queue)

print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())

基于heapq实现优先级队列

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘

‘‘‘
一个字典就是一个键对应一个单值的映射。
如果你想要一个键映射多个值,那么你就需
要将这多个值放到另外的容器中,比如列表
或者集合里面。比如,你可以像下面 这样构造这样的字典:
‘‘‘

people={
    ‘name‘:[‘alex‘,‘李杰‘],
    ‘hobby‘:[‘play‘,‘coding‘]
}

project={
    ‘company‘:{‘IBM‘:‘CTO‘,‘Lenovo‘:‘CEO‘,‘baidu‘:‘COO‘,‘Alibaba‘:‘UFO‘},
    ‘applicant‘:[‘小白‘,‘lhf‘,‘武藤兰‘]
}

‘‘‘
选择使用列表还是集合取决于你的实际需求。
如果你想保持元素的插入顺序就应该使用列表,
如果想去掉重复元素就使用集合(并且不关心元素的顺序问题)。
你可以很方便的使用collections模块中的defaultdict来构造这样的字典。             的一个特征是它会自动初始化每个     刚开始对应的值,所以你只需要 关注添加元素操作了。比如:
‘‘‘
from collections import defaultdict
d=defaultdict(list)
d[‘teacher‘].append(‘alex‘)
d[‘teacher‘].append(‘wupeiqi‘)
d[‘teacher‘].append(‘wuqiqi‘)
d[‘boss‘].append(‘oldboy‘)
d[‘boss‘].append(‘alex‘)

d_set=defaultdict(set)
d_set[‘a‘].add(1)
d_set[‘a‘].add(2)
d_set[‘a‘].add(3)

print(d,d_set)

#setdefault
d={}

d.setdefault(‘a‘,[]).append(1)
d.setdefault(‘a‘,[]).append(2)
d.setdefault(‘a‘,[]).append(2)
print(d)

#自己实现一个一键多值字典
l=[
    (‘teacher‘,‘alex‘),
    (‘teacher‘,‘lhf‘),
    (‘teacher‘,‘papa‘),
    (‘boss‘,‘alex‘),
    (‘boss‘,‘wupeiqi‘),
]
d={}
for k,v in l:
    if k not in d:
       d[k]=[]
    d[k].append(v)
print(d)

#用defaultdict实现,更优雅
d=defaultdict(list)
for k,v in l:
    d[k].append(v)

print(d)

实现一个multidict

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘

from collections import OrderedDict
d=OrderedDict()
d[‘dream1‘]=‘先挣他妈一个亿‘
d[‘dream2‘]=‘然后周游全世界‘
d[‘dream3‘]=‘再娶他妈七八个媳妇‘
d[‘dream4‘]=‘洗洗脸,然后梦就醒了‘

for key in d:
    print(key,d[key])

# import json
# print(json.dumps(d))

‘‘‘
OrderedDict内部维护着一个根据键插入顺序排序的双向链表每次当一个新的元素
插入进来的时候,它会被放到链表的尾部对于一个已经存在的键的重复赋值不会改变
键的顺序。需要注意的是,一个OrderedDict的大小是一个普通字典的两倍,因为它
内部维 护着另外一个链表。所以如果你要构建一个需要大量OrderedDict实例的数
据结构的时候,那么你就得仔细 权衡一下是否使用OrderedDict带来的好处要大过
额外内存消耗的影响。
‘‘‘

创建有序字典

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
prices={
    ‘ACME‘:45.23,
    ‘AAPL‘:612.78,
    ‘IBM‘:205.55,
    ‘HPQ‘:37.20,
    ‘FB‘:10.75
}

#zip()创建的是只能访问一次的迭代器,下面的max()会报错
# prices_and_names=zip(prices.values(),prices.keys())
# min_price=min(prices_and_names)
# max_price=max(prices_and_names)

#单纯的min(prices)是按照key来取值

min_price=min(zip(prices.values(),prices.keys()))
max_price=max(zip(prices.values(),prices.keys()))

print(min_price)
print(max_price)

print(min(prices,key=lambda k:prices[k]))
print(max(prices,key=lambda k:prices[k]))

‘‘‘
需要注意的是在计算操作中使用到了(值,键)对。当多个实体
拥有相同的值的时 候,键会决定返回结果。比如,在执行min()
和max()操作的时候,如果恰巧最小或 最大值有重复的,那么拥
有最小或最大键的实体会返回
‘‘‘
prices={‘A‘:45.23,‘Z‘:45.23}

print(min(zip(prices.values(),prices.keys())))

字典的运算

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
a={
    ‘x‘:1,
    ‘y‘:2,
    ‘z‘:3,
}

b={
    ‘w‘:1,
    ‘x‘:2,
    ‘y‘:3,
}

print(a.keys() & b.keys())
print(a.keys() - b.keys())
print(a.items() - b.keys())

#生成一个新的字典,去掉某些key

c={key:a[key] for key in a.keys() - {‘z‘,‘w‘}}
print(c)

查找俩字典的相同点

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘

a=[1,5,2,1,9,1,5,10]

#如果想简单去重,可以使用set,但是set是无序的
# print(set(a))

#如果序列的值都是hashable类型,那么可以简单利用集合或者生成器来解决这个问题
def dedupe(items):
    seen=set()
    for i in items:
        if i not in seen:
            yield i
            seen.add(i)
print(list(dedupe(a)))

#如果序列元素是不可hashable类型
a=[
    {‘name‘:‘alex‘,‘age‘:18},
    {‘name‘:‘alex‘,‘age‘:100},
    {‘name‘:‘alex‘,‘age‘:100},
    {‘name‘:‘lhf‘,‘age‘:18},

]

def dedupe(items,key=None):
    seen=set()
    for i in items:
        k=i if not key else key(i)
        if k not in seen:
            yield i
            seen.add(k)
print(list(dedupe(a,key=lambda k:(k[‘name‘],k[‘age‘]))))

#去除文件中相同的内容用第一种方法即可

去除序列中重复的值且保持顺序

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘

#普通切片,一堆硬编码
record=‘苍井空‘
record1=‘abcde‘
print(record[1:3])
print(record1[1:3])

#命名切片,减少硬编码
record=‘苍井空 18621452550 沙河汇德商厦‘
phone=slice(4,15)
addr=slice(16,21)
print(record[phone])
print(record[addr])

‘‘‘
一般来讲,代码中如果出现大量的硬编码下标值会使
得可读性和可维护性大大降 低。比如,如果你回过来
看看一年前你写的代码,你会摸着脑袋想那时候自己到
底想 干嘛啊。这里的解决方案是一个很简单的方法让
你更加清晰的表达代码到底要做什么。内置的slice()
函数创建了一个切片对象,可以被用在任何切片允许使用
的地方。
‘‘‘

s=slice(5,50,2)
print(s.start)
print(s.stop)
print(s.step)

命名切片

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
from collections import Counter
words=[‘if‘, ‘you‘, ‘were‘, ‘a‘,
       ‘you,I‘, ‘would‘, ‘never‘,‘if‘,
       ‘would‘, ‘if‘]
# d={}
# for word in words:
#     if word not in d:
#         d[word]=1
#     else:
#         d[word]+=1
# print(d)

word_counts=Counter(words)
# print(word_counts)

#统计出现频率最高的3个单词
print(word_counts.most_common(2))

#可以像字典一样取值
print(word_counts[‘if‘])

#新增单词
more_words=[‘if‘,‘if‘]
for word in more_words:
    word_counts[word]+=1

print(word_counts)
#或者直接使用
word_counts.update(more_words)
print(word_counts)

#counter实例可以进行数学运算

a=Counter(words)
b=Counter(more_words)
print(a)
print(b)
print(a-b)
print(b-a)
print(a+b)

Counter统计出现次数最多的元素

文件conf.txt内容
global
        log 127.0.0.1 local2
        daemon
        maxconn 256
        log 127.0.0.1 local2 info
defaults
        log global
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
        option  dontlognull

listen stats :8888
        stats enable
        stats uri       /admin
        stats auth      admin:1234

frontend oldboy.org
        bind 0.0.0.0:80
        option httplog
        option httpclose
        option  forwardfor
        log global
        acl www hdr_reg(host) -i www.oldboy.org
        use_backend www.oldboy.org if www

backend www.oldboy.org
        server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000

原配置文件

deque_test.py内容

from collections import deque
import re

def conf_dic(f):
    dic={}
    for line in f:
        if re.match(‘[a-zA-Z]‘,line):
            key=line
        elif re.match(‘^ ‘,line):
            dic.setdefault(key,[]).append(line)

    return dic

if __name__ == ‘__main__‘:
    with open(‘conf.txt‘,encoding=‘utf-8‘) as f:
        dic=conf_dic(f)

    for i in dic:
        print(‘%s‘ %i,end=‘‘)
        for line in dic[i]:
            print(line,end=‘‘)
        print(‘-‘*20)

读取配置文件组成字典

#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘
from operator import itemgetter

rows=[
    {‘fname‘:‘Brian1‘,‘lname‘:‘Jones1‘,‘uid‘:1003},
    {‘fname‘:‘Brian2‘,‘lname‘:‘Jones2‘,‘uid‘:1002},
    {‘fname‘:‘Brian3‘,‘lname‘:‘Jones3‘,‘uid‘:1001},
    {‘fname‘:‘Brian4‘,‘lname‘:‘Jones4‘,‘uid‘:1004},
]
# rows_by_uid=sorted(rows,key=lambda rows:rows[‘uid‘])
# for i in rows_by_uid:
#     print(i)
#
#
#
# rows_by_uid=sorted(rows,key=itemgetter(‘uid‘))
# for i in rows_by_uid:
#     print(i)

rows_by_lfname=sorted(rows,key=itemgetter(‘lname‘,‘fname‘))
print(rows_by_lfname)
for i in rows_by_lfname:
    print(i)

字典通过关键字排序

#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘

#要生成列表
l=[]
for i in range(6):
   i*=2
   l.append(i)
print(l)

y=[i*2 for i in range(6)]
print(y)

def func(n):
    return n+10
z=[func(i) for i in range(6)]
print(z)

l=[1,2,3,-1,-10,4,5]
#过滤掉负数
l_new=[i for i in l if i >= 0]
print(l_new)

列表解析

#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘

#生成器,取一次生成一个值,只能next不能回退,因为只有一个

l=[i for i in range(10000000)] #机器卡死
g=(i for i in range(1000000)) #一秒生成
g.__next__()
#next到最后报异常

def fib(n1,n2,count=0):
    if count > 10:return
    if count == 0:
        print(‘‘,n1,end=‘‘)

    x=n2
    n2=(n1+n2)
    n1=x
    print(‘ ‘,n2,end=‘‘)
    count+=1
    fib(n1,n2,count)

#
# 0 1 1 2 3 5 8 13 21

# fib(0,1)
#
def fib2(max=10):
    n,a,b=0,0,1
    while n < max:
        # x=b
        # b=b+a
        # a=x
        yield b
        a,b=b,a+b
        # print(‘ ‘,b,end=‘‘)

        n+=1
    return ‘done‘

x=fib2()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()
x.__next__()

# while True:
#     try:
#         print(x.__next__())
#     except Exception as e:
#         print(e)
#         break

生成器

#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘
import time

def consumer(name):
    print(‘[%s]准备吃包子啦‘ %name)
    while True:
        baozi=yield

        print(‘包子[%s]来了,被[%s]吃了‘ %(baozi,name))

# c=consumer(‘alex‘)
# c.__next__()
# c.send(‘韭菜馅的‘)

def producter():
    c1=consumer(‘alex‘)
    c2=consumer(‘wupeiqi‘)
    c1.__next__()
    c2.__next__()
    print(‘开始做包子啦‘)
    for i in range(10):
        time.sleep(1)
        c1.send(i)
        c2.send(i)

producter()

f=open(‘a.txt‘)
f.__next__()

生成器并行运算

#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘
name=‘lhf‘
passwd=‘123‘

def auth(auth_type):
    def inner_auth(func):
        def _wrapper(*args,**kwargs):
            username=input(‘username: ‘)
            password=input(‘passwd: ‘)
            if auth_type == ‘local‘:
                if username ==  name and password ==passwd:
                    print(‘user login successfull‘)
                    res=func(*args,**kwargs)

                else:
                    exit(‘log err‘)
            elif auth_type == ‘ldap‘:
                print(‘搞毛线ldap,谁特么会‘)

        return _wrapper
    return inner_auth

def index():
    print(‘welcome to index page‘)

@auth(auth_type=‘local‘)
def home():
    print("welcome to home page")

@auth(auth_type=‘ldap‘)
def bbs():
    print(‘welcome to bbs page‘)

index()
home()
bbs()

带参数装饰器

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
prices={
    ‘ACME‘:45.23,
    ‘AAPL‘:612.78,
    ‘IBM‘:205.55,
    ‘HPQ‘:37.20,
    ‘FB‘:10.75
}
prices_new={key:val for key,val in prices.items() if val > 200}
print(prices_new)

从字典中提取子集

#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
from collections import namedtuple
#商品,购买个数,单价
records=[
    (‘mac‘,2,20000),
    (‘lenovo‘,1,3000),
    (‘apple‘,0,10),
    (‘tesla‘,10,1000000)
]
‘‘‘
命名元组的一个主要用途是将你的代码从下标操作中解脱出来。
因此,如果你从数 据库调用中返回了一个很大的元组列表,通
过下标去操作其中的元素,当你在表中添 加了新的列的时候你
的代码可能就会出错了。但是如果你使用了命名元组,那么就不
会有这样的顾虑。
为了说明清楚,下面是使用普通元组的代码:
‘‘‘
cost=0.0
for rec in records:
    cost+=rec[1]*rec[2]
    print(‘商品:%s 购买个数:%s,总价格为:%s‘ %(rec[0],rec[1],cost))

#使用命名元祖后
sk=namedtuple(‘Stock‘,[‘name‘,‘count‘,‘price‘])
for rec in records:
    s=sk(*rec)
    print(s.count*s.price)

p=namedtuple(‘People‘,[‘name‘,‘gender‘,‘age‘])
l=[‘alex‘,‘femal‘,18]
p1=p(*l)
print(p1)
print(p1.name)
print(p1.age)
print(p1.gender)

‘‘‘
命名元组另一个用途就是作为字典的替代,
因为字典存储需要更多的内存空间。如果
你需要构建一个非常大的包含字典的数据结构,
那么使用命名元组会更加高效。但 是需要注意的是,
不像字典那样,一个命名元组是不可更改的。比如:
‘‘‘
p=namedtuple(‘People‘,[‘name‘,‘gender‘,‘age‘])
l=[‘alex‘,‘femal‘,18]
p1=p(*l)
print(p1.name)
# p1.name=‘sb‘#报错,不可修改
p1=p1._replace(name=‘sb‘)#需要重新赋值给p1
print(p1.name)

#可以新建一个函数,弥补必须使用_replace才能修改元素的缺点
p=namedtuple(‘People‘,[‘name‘,‘gender‘,‘age‘])
p1=p(‘‘,‘‘,None)
def dict_to_stock(s):
    return p1._replace(**s)

print(dict_to_stock({‘name‘:‘alex‘,‘gender‘:‘f‘,‘age‘:18}))
print(dict_to_stock({‘name‘:‘sb‘,‘gender‘:‘f‘,‘age‘:18}))

nametuple命名元组

				
时间: 2024-10-17 10:06:27

九 函数的相关文章

python学习笔记(九)-函数2

交换两个变量的值 a = 2 b = 1 b = 1 a = 2 #方式一: b,a = a,b #交换两个变量的值 print(a,b) #方式二: a = a + b #3 b = a - b #2 a = a - b #3-2 #列表推导式 nums = [0,1,3,4,5,6,7] new_nums = [x-1 for x in nums] print(new_nums) return多个值 函数如果有多个return值,那么会把这几个return的值都放到一个元组里面,然后返回 d

python回顾(九)——函数高级

函数默认参数 默认参数概念 默认参数指函数/方法在定义时为形参赋值,对应的形参称为默认参数 默认参数是一个参数定义期的概念,与调用无关 默认参数作用 如果参数定义默认参数,在调用函数/方法时,未对该参数进行传值,则使用默认值作为该参数的值 默认参数基本语法 定义格式: def 函数名(形参1 = 值1,-): 函数体    -- 调用格式一(同普通参数,无特殊): 函数名(实参) 使用实参作为形参的值,不使用默认值 调用格式二: 函数名()使用默认值作为形参的值 注意事项 1.默认参数的定义必须

Python基础九函数进阶(一)

Q:Python运行代码时,遇到函数是怎么做到的? A:从Python解释器开始执行之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读入内存,表示知道这个函数存在了,至于函数内部的变量跟逻辑,解释器根本不关心. 当执行到函数调用的时候,Python解释器会再开辟一块内存来存储这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中,函数中的变量只能在函数内部使用

Python基础九函数进阶(二)

回顾一下 函数名的本质就是函数的内存地址 1可以被引用 2可以当做容器类性的元素 3可以当做函数的参数和返回值 一.闭包 闭包的含义:内部函数引用外部作用域(非全局)的变量  (内部函数指的是函数内部定义的函数) 有与有了作用域的关系,我们就不能拿到函数内部的变量和函数了.如果我们有需求就是想拿到那怎么做呢?返回呀!我们都知道函数内的变量我们想要在函数外不用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢? 是不是直接就把这个函数名字返回就好了呢? 这才是闭包函数最常用的方法

C语言库函数大全及应用实例九

原文:C语言库函数大全及应用实例九                                                [编程资料]C语言库函数大全及应用实例九 函数名: mktemp 功 能: 建立唯一的文件名 用 法: char *mktemp(char *template); 程序例: #i nclude #i nclude int main(void) { /* fname defines the template for the temporary file. */ char

文成小盆友python-num15 - JavaScript基础

一.JavaScript简介 JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能. 二.组成部分 ECMAScript,描述了该语言的语法和基本对象 文档对象模型(DOM),描述处理网页内容的方法和接口. 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口. 三. Jav

JS基础笔记集

three.js:3D框架  svgtween:动画框架 一.js事件的组成:on+事件名,当触发某个事件做一些事情:   如:onclick:当点击鼠标,触发的事件: 二.在写一个页面时,结构(html).样式(css)和行为(js)是要分离出来的:    好处:代码可复用,可读性好,可维护性好: 三.通过js获取元素方法:    1>通过元素中的id名,获取元素:document.getElementById("id名"):    2>通过元素名,直接获取元素:getE

1.1 OC类的认识

一.import的作用 功能和include一样,是将右边的文件拷贝到当前import的位置,为了降低程序员的负担,防止重复导入,避免程序员去书写头文件卫士:预处理指令,会自动防止重复拷贝 框架地址:工具箱地址                                                              /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SD

《sqlite权威指南》读书笔记 (一)

一 常量 字符串常量   (使用单引号括住.如果常量中有单引号,使用两个单引号来表示.大小写敏感) 数字常量 二进制常量 二 关键字 关键字大小写不敏感 三 注释 单行注释使用 --XXXXXXX 多行注释使用/*XXXXXX*/ 四 创建表 CREATE [TEMP | TEMPORARY] TABLE table_name (column_definitions [constraints,]); 五 修改表 ALTER TABLE table_name {RENAME TO new_tabl