day04-函数编程进阶

周末班——day4

python之路:https://www.cnblogs.com/Eva-J/articles/7277026.html

各种推导式详解: https://www.cnblogs.com/Eva-J/articles/7276796.html

1.内容回顾

# 文件操作
    # 打开文件
        f = open('文件的路径',mode='r',encoding='utf-8')
        open('文件的路径',mode='w',encoding='utf-8')
        open('文件的路径',mode='a',encoding='utf-8')
        open('文件的路径',mode='rb')
        open('文件的路径',mode='wb')
        open('文件的路径',mode='ab')
    # 读写文件
        # 读
            read()  默认读所有
            read(n) 读n个字节/字符	# 以rb形式打开读的是字节,以r形式打开读的是字符
            readline() 每次读一行,不知道什么时候结束
            for lin in f:
        # 写
            write('想写啥写啥')
            write(b'abc')
    # 关闭文件
        f.close()
    # 删除和修改
        import os
        os.remove('文件的绝对路径')
        os.rename('原名','目的名')
        # 修改文件
            # 读a文件,写b文件
            # 删除a,重命名b->a
# 初识函数
    # 函数的定义
       # def 函数名(形参):
       #    函数体
       #    return 返回值
    # 调用
        # 变量 = 函数名(实参)
        # 变量就是函数的返回值
    # 返回值
        1.不写return 默认返回None
        2.只写return 表示函数结束,默认返回None
        3.return 值  值被返回给调用者
        4.return 值1,值2  接收到的返回值是(值1,值2)
    # 参数
        # 站在调用者的角度上
            # 按照位置传参数
                # *可以迭代的对象(可以被for循环)
            # 按照关键字传参
                # **字典
            # 混合 :先位置,再关键字
        # 站在定义函数的角度上
            # 位置参数
            # *args 动态参数
            # 默认参数
            # **kwargs 动态参数
def cal(a,b,c):
    pass
cal(1,2,3)
cal(a = 1,b = 2,c = 3)
cal(1,b = 2,c = 3)
cal(1,2,c = 3)
l = [1,2,3]
cal(*l)   # -->cal(l[0],l[1],l[2])
d = {'a':1,'b':2,'c':3}
cal(**d)

f = open('test',mode='rb')
content = f.read()
print(content)
msg = content.decode('utf-8')
print(msg)
f.close()

path = r'F:\python自动化27期\day4\test'
f = open(path,encoding='utf-8')
content = f.read()
print(content)

# 工作目录
# 在哪个路径下执行python程序,工作目录就是哪里
# 所以 如果希望在任何一个位置执行代码都不出现文件目录找不到的情况,就要用绝对路径,而不是相对路径

# pycharm下会有很多优化的机制
# 在执行代码的时候,会自动的把当前文件所在的目录作为工作目录

# 参数的陷阱,如果默认参数的值是一个可变数据类型
# 那么所有的调用者都共享这一个数据
# 这个变量是在定义的时候创建1次,而不会在调用的过程中再次被创建了
def func(a,l = []):
    print(id(l))
    l.append(a)
    print(l)
    return l

func(1)
l1 = func(2,[])
func(3)
func(4,[])   # [4]

2.4函数名的本质

def a():
    print('in a func')

a()
print(a)  # <function a at 0x00000000039C41E0>
b = a
print(b)
b()
# 并不是只有函数名()才能调用一个函数
# 只要是函数的地址对应的变量都可以通过()调用函数
l = [a]
print(l[0])
l[0]()

# 实际上函数的名字可以被赋值,也可以作为一个容器类型的元素,可以作为函数的参数,可以做返回值
# 变量怎么使用,函数的名字都可以怎么用
def a():
    '''可以作为函数的参数'''
    print('in a func')
def wahaha(f):
    f()
wahaha(a)



def wahaha():
    '''函数名可以作为返回值'''
    def a():
        print('in func a')
    return a

funca = wahaha()
funca()

2.5闭包

# 闭包 :如果一个内部的函数引用了外部函数的变量,那么这个内部函数就是一个闭包函数
def wahaha():
    name = 'alex'
    def a():
        # '''一旦内层函数引用了外层函数的变量,a就是一个闭包函数'''
        print('in func a',name)  # 闭包函数
    return a

a = wahaha()
print(a())


def func1():
    a = 1
    b = 2
    def inner():  # inner中没有用到a,b所以不是闭包
        print(1,2)

def func2():
    a = 1
    b = 2
    def inner(a,b):  # inner中虽然用到a,b,但用到的是自己的参数a,b,而不是外部的变量,所以不是闭包
        print(a,b)

def func2():
    a = 1
    b = 2
    def inner():  # 是闭包
        print(a,b)

def func2(a,b):
    def inner():  # 是闭包
        print(a,b)

a = 1
b = 2
def func2():
    def inner():  # 不是闭包
        print(a,b)

# 闭包有什么用?
from urllib import request   # url模块

ret = request.urlopen('https://www.cnblogs.com/Eva-J/p/7277026.html')
print(ret.read().decode('utf-8'))


def get_source_html(url):
    dic = {}
    def get_url():
        if url in dic:
            return dic[url]
        else:
            ret = request.urlopen(url)
            dic[url] = ret
            return ret.read().decode('utf-8')
    return get_url
get_url = get_source_html('https://www.cnblogs.com/Eva-J/p/7277026.html')
print(get_url())
print(get_url())
print(get_url())
print(get_url())
print(get_url())
print(get_url())




def wahaha():
    print(123)
    return wahaha
b = wahaha
b()


def wahaha():
    print(123)
    return wahaha
b = wahaha()
b()

def multipliers():
    return [lambda x: i * x for i in range(4)]
print([m(2) for m in multipliers()])

3.装饰器

import time  # 时间模块
# 别人写好的一些功能,放在一个模块里
# 和时间相关的功能,就放在了time模块

# 格林威治时间 - 19700101 08:00:00 北京
# 格林威治时间 - 19700101 00:00:00 伦敦
def timmer(funcname):   # funcname就是"func的内存地址"
    def inner(*args,**kwargs):
        # (1000000,20)  ()
        start = time.time()
        ret = funcname(*args,**kwargs)
        print(time.time() - start)
        return ret
    return inner

@timmer    # func = timmer(func) func = inner的内存地址
def func(n,m):
    print(n,m)
    sum_num = 0
    for i in range(n):
        sum_num += i
    return sum_num

@timmer  # func2 = timmer(func2) # func2 = inner的内存地址
def func2():
    sum_num = 0
    for i in range(10000000):
        sum_num += i
    return sum_num

timmer(func)
timmer(func2)
#
# 函数是写好的功能
# 使用别人写的函数
# timmer(func)
# 你的代码有1000处都用到了我写的func
# 把func改成timmer(func)改1000次

# 如果可以在不改变使用者的调用方式的情况下,能够添加上计算时间的这个功能 就好了
ret = func(100000,20)     # 想调用func,实际调的inner
ret2 = func2()
print(ret,ret2)

# 什么情况下用
    # 在已经写好发版的程序的基础上,需要对一个函数执行前后增加功能的时候
        # 开放封闭原则
                # 开放 :对扩展是开放的
                # 封闭 :对修改时封闭
    # 有的时候也会写好一些装饰器,加在需要装饰的函数上面
        # login  django框架里也这么用
        # log


def login():
    pass

@login     # 判断用户的登录状况
def 联系():
    pass

@login
def 管理():
    pass

@login
def 新随笔():
    pass

# 论坛程序
def log():
    pass

@log
def 发布帖子():
    pass

@log
def 评论():
    pass


# 装饰器的固定格式

def 装饰器的名字(func):
    def inner(*args,**kwargs):
        '''在执行被装饰的函数之前要做的事儿'''
        '''判断是否登录'''
        ret = func(*args,**kwargs)
        '''在执行被装饰的函数之后要做的事儿'''
        '''写log'''
        return ret
    return inner

@装饰器的名字
def wahaha():
    pass

wahaha()


import time
from functools import wraps

# 把这个函数看明白了,然后把原本打印在屏幕上的内容写到operate.log文件里,做成一个日志文件
def wrapper(func):
    @wraps(func)
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)
        t = time.strftime('%Y-%m-%d %H:%M:%S')
        with open('operate.log',mode= 'a',encoding='utf-8') as f:
            f.write('在%s[%s]执行了%s函数\n'%(t,args[0],func.__name__))
        return ret
    return inner

@wrapper
def login(name):
    print('%s登录啦'%name)

@wrapper
def register(name):
    print('%s注册啦'%name)

print([register.__name__])
login('alex')
register('alex')

def func(a,b):
    '''
#     函数的注释:这个函数时做什么用的
#     :param a:int 长放形的宽
#     :param b:int 长方形的长
#     :return: int 长方形的面积
#     '''
#     return a+b

print(func.__doc__)
print(func.__name__)

4.一个函数被多个装饰器装饰

def wrapper1(func):   # func = inner2
    def inner1(*args,**kwargs):
        print('before inner1')
        ret = func(*args,**kwargs)
        print('after inner1')
        return ret
    return inner1
#
def wrapper2(func):    # func = wahaha
    def inner2(*args,**kwargs):
        print('before inner2')
        ret = func(*args,**kwargs)
        print('after inner2')
        return ret
    return inner2
#
@wrapper1   # wahaha = wrapper1(inner2) = inner1
@wrapper2   # wahaha = wrapper2(wahaha) = inner2
def wahaha():
    print('WAHAHA')

wahaha()   # inner1


# timmer装饰器 计算被装饰的函数的执行时间
# login装饰器 检测被装饰的函数是不是登录,如果没有登录要先登录才能使用这个函数
# timmer装饰器永远紧贴着被装饰的函数
# login装饰器 可以任意的排列
# logger装饰器 可以任意的排列

5.带参数的装饰器

# 带参数的装饰器
# flask框架中 路由里用到了带参数的装饰器
import time
flag = False
def timmer(flag):   # flag = True
    def outer(func): # func = wahaha
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                print(time.time() - start)
            else:
                ret = func(*args, **kwargs)
            return ret
        return inner
    return outer

@timmer(flag) # @outer = wahaha=outer(wahaha)
def wahaha():
    print('in wahaha')

@timmer(flag)
def wahaha1():
    print('in wahaha1')

@timmer(flag)
def wahaha2():
    print('in wahaha2')

@timmer(flag)
def wahaha3():
    print('in wahaha3')

wahaha1()
wahaha2()
wahaha3()
wahaha()

from functools import wraps
import time
def log(filename):
    def wrapper(func):
        @wraps(func)
        def inner(*args,**kwargs):
            ret = func(*args,**kwargs)
            t = time.strftime('%Y-%m-%d %H:%M:%S')
            with open(filename,mode= 'a',encoding='utf-8') as f:
                f.write('在%s[%s]执行了%s函数\n'%(t,args[0],func.__name__))
            return ret
        return inner
    return wrapper

@log('login.log')
def login(name):
    print('%s登录啦'%name)

@log('register.log')
def register(name):
    print('%s注册啦'%name)

print([register.__name__])
login('alex')
register('alex')

6.迭代器

# 需要一个从1-1000000的数字序列
# python2.7 range(100000000) 真的在内存中生成100000000个数
        #   xrange(100000000)并不是在执行的时候生成100000000个数
# python3.x range(100000000) 并不是在执行的时候生成100000000个数

ran = range(0,5)
print(ran)
# 找这个ran拿衣服了
# ran变成一个迭代器
iterator = ran.__iter__()
print(iterator)
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
# 迭代器:
    # 1.一个一个的取值,而不是一次性把所有数据都创建出来,迭代器中的数据不取不创建
    # 2.只能按照顺序取,不能跳过也不能回头
    # 3.一个迭代器中的数据只能从头到尾取一次
# 可迭代器协议: 如果一个数据类型中有 iter方法 ,那么这个数据类型就是可迭代类型
# 迭代器协议:如果一个数据类型中有iter和next方法,那么这个数据类型就是一个迭代器类型
print('__iter__' in dir(123))
print('__iter__' in dir(123.43))

# 只是可迭代类型而不是迭代器
    print('__iter__' in dir('abc'))
    print('__iter__' in dir([1,2,3]))
    print('__iter__' in dir({1,2,3}))
    print('__iter__' in dir((1,2,3)))
    print('__iter__' in dir({1:3}))
    print('__iter__' in dir(range(10)))
# 文件操作符是一个迭代器
    f = open(r'F:\python自动化27期\day4\test',encoding='utf-8')
    print('__iter__' in dir(f))
    f.close()

# 迭代器的特点:节省内存空间
# 除了文件操作符以外你见过的所有内容都不是迭代器类型
# 都只是可迭代类型
# 可迭代类型是可以通过某些方法转换成迭代器的

# 可迭代类型.__iter__方法可以把可迭代类型转换成迭代器
l = [1,2,3,4,5,6]
iter = l.__iter__()
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())

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

# 所有能被for循环的至少是一个可迭代类型
# 今后如果我说xxx是一个迭代器,知道这个xxx并不是直接存储了内容,而是需要for循环才能获取每一个值

def make_cloth_simple(n):
    '''
    生成器函数,没有return 只有yield
    :param n:
    :return:
    '''
    print('做第一件衣服')
    yield 1    # 暂停键
    print('做第二件衣服')
    yield 2
    print('做第三件衣服')
    yield 3

ret = make_cloth_simple(1000000)
print(ret)   # generator 生成器 生成器的本质就是一个迭代器
# print(ret.__next__())
# print(ret.__next__())
# print(ret.__next__())
for i in ret:
    print(i)

7.生成器函数

def make_cloth_simple(n):
    '''
    生成器函数,没有return 只有yield
    :param n:
    :return:
    '''
    for i in range(n):
        yield '第%s件衣服'%i
#
ret = make_cloth_simple(1000000)
print(ret)   # generator 生成器 生成器的本质就是一个迭代器
for n in range(20):
    print(ret.__next__())
#
print('='*50)
for i in range(5):
    print(ret.__next__())

# 监听文件内的输入,
# 在python中监听一个文件的输入事件,只要用户输入了新内容,就打印到屏幕中来
# f.readline + while循环
# 打开文件
# 循环
    # 读
# 关闭文件

def listen():
    f = open('test',mode='r',encoding='utf-8')
    while True:   # 2000
        content = f.readline().strip()
        if 'error' in content:
            yield content
#
for content in listen():
    print(content)

   
# 写文件
while True:
    f = open('test', 'a', encoding='utf-8')
    content = input('>>>')
    f.write(content)
    f.close()

# 将来你写的所有的代码 最好都把读文件的操作写成一个生成器
def get_user(file):
    line_lst = []
    with open(file,mode = 'r',encoding='utf-8') as f:
        for line in f:
            usr,pwd = line.strip().split('|')
            line_lst.append((usr,pwd))
    return line_lst
#
def login():
    user = input('username :')
    passwd = input('password :')
    print(get_user('userinfo'))
    for usr,pwd in get_user('userinfo'):
        if usr == user and pwd == passwd:
            print('登录成功')
            break
    else:
        print('登录失败')

login()

# 登录
    # 读文件
# 注册
    # 检测是不是已经存在相同的用户名
def get_user(file):
    with open(file,mode = 'r',encoding='utf-8') as f:
        for line in f:
            usr,pwd = line.strip().split('|')
            yield usr,pwd
#
def login():
    user = input('username :')
    passwd = input('password :')
    for usr,pwd in get_user('userinfo'):
        if usr == user and pwd == passwd:
            print('登录成功')
            break
    else:
        print('登录失败')
#
login()

# 所有的读文件和写文件 尽量都拆分到其他函数中
# 不要嵌到你写好的功能函数中
# 比如 登录 函数中不要写读文件的逻辑
# 比如 注册 函数中不要写读\写文件的逻辑


def func():
    for i in range(10):
        yield 'a%s'%i
g = func()
for i in g:
    print(i)
#
for i in g:
    print(i)

def func():
    for i in range(10):
        yield 'a%s'%i
for i in func():
    print(i)
for i in func():
    print(i)

def func():
    for i in range(10):
        yield 'a%s'%i
g1 = g2 = func()
for i in g1:
    print(i)
for i in g2:
    print(i)

def func():
    for i in range(10):
        yield 'a%s'%i
g1 = func()
g2 = func()
for i in g1:
    print(i)
for i in g2:
    print(i)

8.列表推导式

l = [1,2,3,4,5]
ls = []
for i in l:
    ls.append(i*2)
print(ls)
ls = [i*2 for i in l]
print(ls)

l = [1,2,3,4,5]
# 所有的偶数都放到新的列表中
ls = [i for i in range(100) if i%2 == 0]
print(ls)

# 练习1:30以内所有能被3整除的数
ls = [i for i in range(30) if i%3 == 0]
print(ls)
# 练习2:30以内所有能被3整除的数的平方
ls = [i*i for i in range(30) if i%3 == 0]
print(ls)

# 找到嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
print('alexander'.count('e'))
print('alexander'.count('n'))
ls = [name for lst in names for name in lst if name.count('e') == 2]
print(ls)

9.生成器表达式

# 生成器表达式
# 列表推导式的[] 换成() 就变成了生成器表达式了

lst= [i*2 for i in range(5)]
print(lst) # lst中的所有元素已经在内存里了

gen = (i*2 for i in range(5))
print(gen) # gen里什么也没有

print('-->',gen.__next__())
print(list(gen))
for i in gen:
    print(i)

# 迭代器 是一个可以被for循环的节省内存的类型
# 生成器 是程序员能够自己写的迭代器
    # 生成器函数 yield
        #  g = 生成器函数()
    # 生成器表达式
        # g = (表达式)
        # 列表推导式和生成器表达式所使用的的 "表达式是相同的"
# 所有的生成器都符合迭代器的特点
    1.一个一个的取值,而不是一次性把所有数据都创建出来,迭代器中的数据不取不创建
    2.只能按照顺序取,不能跳过也不能回头
    3.一个迭代器中的数据只能从头到尾取一次
# 从迭代器中取值的三种方式
    1.gen.__next__
    2.for n in gen:pass
    3.list(gen)

# 简单的for循环生成新列表 -->列表推导式联系起来
# 只要用到列表推导式 --> 把列表推导式转成生成器表达式
# 生成器函数 --> 处理文件

# 面试题一 : 生成器函数 + 生成器表达式
def demo():
    for i in range(4):
        yield i

g=demo()

g1=(i for i in g)
g2=(i for i in g1)

print(list(g1))
print(list(g2))
# 生成器中的值只能从头到尾取一次

# 面试题二:重点内容 : 生成器 + for循环
    # for循环一定要拆
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)

print(list(g))

10.三元运算符

a = 10
b = 1
# max_num = 0
# if a>b:
#     max_num = a
# else:
#     max_num = b

max_num = a if a>b else b
print(max_num)

11.匿名函数

# 如果一个函数中的功能非常小,只有一句代码
# 这个时候我们就可以把这个函数创建成一个匿名函数

# lambda表达式 == 匿名函数
def func1(a,b):
    return a+b
ret = func1(1,2)
print(ret)
# lambda 参数:返回值
func2 = lambda a,b : a+b
ret = func2(3,4)
print(ret)

print(func1.__name__)
print(func2.__name__)


# lambda表达式 a,b两个值,求比较大的值
# lambda表达式 a为参数,求a的奇\偶性
# lambda表达式 a为参数,求a的绝对值

func1 = lambda a,b : a if a>b else b
ret = func1(10,2)
print(ret)

func2 = lambda a : '偶数' if a%2 == 0 else '奇数'
ret = func2(11)
print(ret)

func3 = lambda a:a if a>0 else -a
ret = func3(-2)
print(ret)
ret = func3(6)
print(ret)

func = lambda :2+3+4
ret = func()
print(ret)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值