Python高效技巧(三)---查缺补漏(时间处理、shutill模块、高阶函数、装饰器)

前言:

  本文假定读者已经有了一定的Python 基础,看完过几本入门书籍。本文也不是那种快速参考手册 (可以很快的查询某个模块下的某个函数)。旨在聚焦几个最重要的主题,演示几种可能的高效解决方案,作为一个自己提升的记录。

  使用 def 语句定义函数是所有程序的基础。本节的目标是讲解一些更加高级和不常见的函数定义与使用模式。涉及到的内容包括默认参数、任意数量参数、强制关键字参数、注解和闭包。另外,一些高级的控制流和利用回调函数传递数据的技术在这里也会讲解到。

函数

1、可接受任意数量参数的函数和关键词参数

问题:你想构造一个可接受任意数量参数的函数

为了能让一个函数接受任意数量的位置参数,可以使用一个 * 参数

def my_sum(*x):
    return x
my_sum(1,2,3,4,[5,6],"7")
>>>(1, 2, 3, 4, [5, 6], '7')

def my_sum1(**x):
    return x
my_sum1(x=[1,2,3,4],y=["sa",7,1.23])
>>>{'x': [1, 2, 3, 4], 'y': ['sa', 7, 1.23]}

  这里需要说明的是一个*号表示的是可接受任意多个参数,且类型可以不一致,所有的参数最后以元组的形式存储;但是两个**号表示的是任意数量关键词参数,首先明确它是关键词参数,它传参的时候必须带上关键词,而且它的结果以字典的形式存在。

所以下面的几种写法都是错误的:

def my_sum1(**x):
    return x
my_sum1(5,x=[1,2,3,4])
>
def my_sum1(**x):
    return x
my_sum1([1,2,3,4])

   注意点:一个 * 参数只能出现在函数定义中最后一个位置参数后面,而**参数只能出现在最后一个参数。有一点要注意的是,在 * 参数后面仍然可以定义其他参数。下面这种写法是正确的

def a(x, *args, y):
pass

def b(x, *args, y, **kwargs):
pass

2、匿名函数 lambda

  当一些函数很简单,仅仅只是计算一个表达式的值的时候,就可以使用 lambda 表达式来代替了def写法,这种方式在实际应用中很常见

add = lambda x, y: x + y
add(2,3)
>>>5
"""
 lambda 函数可以使用条件语句和循环语句。具体使用规则自行查阅
 """
add = lambda x: "是" if x > 0 else "否"
add(-5)
>>>'否'

二、其他

1、关于序列的各种方法

在这里插入图片描述

2、产生器表达式

text = '''"When I use a word," Humpty Dumpty said in rather a scornful tone,
"it means just what I choose it to mean - neither more nor less."'''

max([w.lower() for w in nltk.word_tokenize(text)])# 1
'word'

max(w.lower() for w in nltk.word_tokenize(text))# 2
'word'

  上面代码中两种方式,第一种是正常的列表推导式,第二行使用了产生器表达式。这不仅仅是标记(形式上看起来)方便:在许多语言处理的案例中,产生器表达式会更高效。在1中,链表对象的存储空间必须在 max()的值被计算之前分配。如果文本非常大的,这将会很慢。在2中,数据流向调用它的函数。由于调用的函数只是简单的要找最大值——按字典顺序排在最后的词——它可以处理数据流,而无需存储迄今为止的最大值以外的任何值。

三、 查缺补漏

1、时间处理

1. calendar.monthrange(year,month)函数

calendar.monthrange功能说明:
calendar.monthrange(year,month)方法可返回两个整数:
返回一个元组,包含两个整数
整数1:起始星期数
整数2:本月最大日期数

import calendar
calendar.monthrange(2022, 1)
# 2022年1月开始的第一天是周六(0-6:周一到周天),一共31天
(5, 31)

2、数据文件读取

1. 创建多级目录

os.makedirs(path, mode=0o777, exist_ok=False):
参数

  • path : 要创建的目录,绝对路径或者相对路径
  • mode: Linux 目录权限数字表示,windows 请忽略该参数
  • exist_ok:如果已经存在怎么处理,默认是 False ,即:已经存在程序报错。当为 True 时,创建目录的时候如果已经存在就不报错。

2. python shutil 模块

copy()

功能:复制文件
格式:shutil.copy(‘来源文件’,‘目标地址’)
返回值:复制之后的路径

copy2()

功能:复制文件,保留元数据
格式:shutil.copy2(‘来源文件’,‘目标地址’)
返回值:复制之后的路径

copyfileobj()

将一个文件的内容拷贝的另外一个文件当中
格式:shutil.copyfileobj(open(来源文件,‘r’),open(‘目标文件’,‘w’))
返回值:无

copyfile()

功能:将一个文件的内容拷贝的另外一个文件当中
格式:shutil.copyfile(来源文件,目标文件)
返回值:目标文件的路径

copytree()

功能:复制整个文件目录
格式:shutil.copytree(来源目录,目标目录)
返回值:目标目录的路径
注意:无论文件夹是否为空,均可以复制,而且会复制文件夹中的所有内容

copymode()

功能:拷贝权限

copystat()

功能:拷贝元数据(状态)

rmtree()

功能:移除整个目录,无论是否空
格式:shutil.rmtree(目录路径)
返回值:无

move()

功能:移动文件或者文件夹
格式:shutil.move(来源地址,目标地址)
返回值:目标地址

归档和解包操作

归档:将多个文件合并到一个文件当中,这种操作方式就是归档。
解包:将归档的文件进行释放。
压缩:压缩时将多个文件进行有损或者无损的合并到一个文件当中。
解压缩:就是压缩的反向操作,将压缩文件中的多个文件,释放出来。
注意:压缩属于归档!

make_archive()

功能:归档函数,归档操作
格式:shutil.make_archive(‘目标文件路径’,‘归档文件后缀’,‘需要归档的目录’)
返回值:归档文件的最终路径

unpack_archive()

功能:解包操作
格式:shutil.unpack_archive(‘归档文件路径’,‘解包目标文件夹’)
返回值:None
注意:文件夹不存在会新建文件夹

get_archive_formats()

功能:获取当前系统已注册的归档文件格式(后缀)
格式:shutil.get_archive_formats()
返回值:列表 [(后缀,解释),(后缀,解释),(后缀,解释)…]

get_unpack_formats()

功能:获取当前系统已经注册的解包文件格式(后缀)
格式:shutil.get_unpack_formats()
返回值:列表 [(后缀,解释),(后缀,解释),(后缀,解释)…]

3. Web应用

什么是异步、同步、阻塞和非阻塞?:
阻塞是指调用函数的时候当前线程被挂起
非阻塞是指调用函数的时候当前线程不会被挂起,而是立即返回
同步是指请求没有返回时不能干别的事情
异步是指请求了以后可以先干别的事情,等请求有了返回再接收返回值

3、NumPy

1.数组创建

创建数组有 6 种通用机制:

  1. 从其他 Python 结构(即列表和元组)转换

a1D = np.array([1, 2, 3, 4])
a2D = np.array([[1, 2], [3, 4]])
a3D = np.array([[[1, 2], [3, 4]],
[[5, 6], [7, 8]]])

2.内在的 NumPy 数组创建函数(例如 arange、1、0 等)

np.arange(10)
np.arange(2, 10, dtype=float)
np.linspace(1., 4., 6)
np.eye(3)
np.diag([1, 2, 3])
np.array([[1, 2], [3, 4]])

3.复制、加入或改变现有数组(当您将一个数组或其元素分配给一个新变量时,您必须显式指定numpy.copy该数组,否则该变量是原始数组的视图。)

a = np.array([1, 2, 3, 4])
b = a[:2].copy()
A = np.ones((2, 2))
B = np.eye((2, 2))
C = np.zeros((2, 2))
D = np.diag((-3, -4))
np.block([[A, B],
[C, D]])
array([[ 1., 1., 1., 0. ],
[ 1., 1., 0., 1. ],
[ 0., 0., -3., 0. ],
[ 0., 0., 0., -4. ]])

4.txt,csv读取数组

np.loadtxt(‘simple.csv’, delimiter = ‘,’, skiprows = 1)

2. 广播的原则

广播的原则:如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符,或其中的一方的长度为1,则认为它们是广播兼容的,广播会在缺失或长度为1的维度上进行。
在这里插入图片描述
在这里插入图片描述

3. 掩码数组

有时候数据集中存在缺失、异常或者无效的数值,我们可以标记该元素为被屏蔽(无效)状态。

import numpy as np
import numpy.ma as ma
x = np.array([1, 2, 3, -99, 5])
mx = ma.masked_array(x, mask=[0, 0, 0, 1, 0])
mx
masked_array(data=[1, 2, 3, --, 5],
             mask=[False, False, False,  True, False],
       fill_value=999999)
# 接下来可以计算平均值而不用考虑无效数据。
mx.mean()
Out[292]: 2.75

当只想访问有效数据时,我们可以使用掩码的逆作为索引。可以使用numpy.logical_not函数或简单使用~运算符计算掩码的逆:

x = ma.array([[1, 2], [3, 4]], mask=[[0, 1], [1, 0]])
x[~x.mask]

masked_array(data=[1, 4],
             mask=[False, False],
       fill_value=999999)

要取消屏蔽一个或多个特定数据条目,我们只需为它们分配一个或多个新的有效值:

x = ma.array([1, 2, 3], mask=[0, 0, 1])
x
Out[305]: 
masked_array(data=[1, 2, --],
             mask=[False, False,  True],
       fill_value=999999)
x[-1] = 5
x
Out[307]: 
masked_array(data=[1, 2, 5],
             mask=[False, False, False],
       fill_value=999999)

4、万能视频下载

import sys
from you_get import common as you_get#  导入you-get库

#  设置下载目录
directory=r'mp4\\'
#  要下载的视频地址
url='https://music.163.com/#/mv?id=14306186'
#  传参数
sys.argv=['you-get','-o',directory,'--format=flv',url]
you_get.main()

5、高阶函数

把函数作为参数传入,这样的函数称为高阶函数。

map/reduce
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素。map()函数的输出为的map()对象。需要我们使用for循环或使用list()方法对输出进行迭代。

def f(x):
    return x * x


r = map(f,[1, 2, 3, 4, 5, 6])
list(r)
[1, 4, 9, 16, 25, 36]

reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

from functools import reduce
def fn(x, y):
    return x * 10 + y

reduce(fn, [1, 3, 5, 7, 9])
13579

filter
filter()函数用于过滤序列。和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1,2,3,4,5,6,10,15]))
[1, 3, 5, 15]

sorted
排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

Python内置的sorted()函数就可以对list进行排序:

sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]

此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

6、 装饰器

由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。函数对象有一个__name__属性,可以拿到函数的名字。
现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

@log
def now():
    print('2015-3-25')

now()
call now():
2015-3-25

把@log放到now()函数的定义处,相当于执行了语句:now = log(now)

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

@log('execute')
def now():
    print('2015-3-25')

now()
execute now():
2015-3-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值