在记录今天重点内容的笔记之前,我想要先记录一下匿名函数,因为之前对匿名函数的理解仅停留在了解的状态,以至于实际应用很困难,近两天的内容刚好碰到类似的应用,遂再次深入的解析一下。



一、匿名函数

python 使用 lambda 来创建匿名函数。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

在一些情况下,我们通常会需要对一些有规律命名规则的文件进行一定的排序,但是单纯使用 sorted() 获取的文件名列表是按照 ascii 码排序的,例如:1.pdf, 10.pdf, 11.pdf, 2.pdf ··· ···

sort 与 sorted 区别:

sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。

list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。

sorted() 的语法是

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

'''
参数说明:
iterable -- 可迭代对象。
key      -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse  -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
'''

当我们需要把一个可迭代对象进行排序操作的时候,那么 key 值进行比较的元素通常就可以使用 lambda 函数获取到。

如果我们需要把下面的列表中的对象以数字的顺序排序,我们使用 lambda 实现就方便多了

File=['1.pdf', '10.pdf', '7.pdf', '2.pdf', '21.pdf', '6.pdf', '3.pdf', '34.pdf']

首先我们需要确定数字的下标 

d[0:-4]

'''
个位数以 1.pdf 为例,从左边开始 1 的下标为 0,从右边开始 1 的下标为 -4,[0:-4]取到的值为 1
多位数以 31.pdf 为例,从左边开始 3 的下标为 0,从右边开始 1 的下标为 -4,[0:-4]取到的值为 31
'''

取到用于比较的元素之后,在使用 sorted 排序就简单多了

File=['1.pdf', '10.pdf', '7.pdf', '2.pdf', '22.pdf', '6.pdf', '3.pdf', '31.pdf']
# newFiles = sorted(File, key=lambda d: int(d.split(".pdf")[0])) 此方法亦可行,但不适用于首位不为数字的名称
newFiles = sorted(File, key=lambda d:int(d[0:-4]))
print(newFiles)


''' 运行结果
['1.pdf', '2.pdf', '3.pdf', '6.pdf', '7.pdf', '10.pdf', '22.pdf', '31.pdf']
'''

那么当名称的开头是字母不为数字时,如 'chapter1.pdf', 'chapter10.pdf' 之类,我们就只能从中间取值,比如

listD=['chapter1.pdf', 'chapter10.pdf', 'chapter11.pdf', 'chapter12.pdf', 'chapter13.pdf', 'chapter14.pdf', 'chapter15.pdf', 'chapter16.pdf', 'chapter17.pdf', 'chapter18.pdf', 'chapter19.pdf', 'chapter2.pdf', 'chapter20.pdf', 'chapter21.pdf', 'chapter22.pdf', 'chapter23.pdf', 'chapter24.pdf', 'chapter25.pdf', 'chapter26.pdf', 'chapter3.pdf', 'chapter4.pdf', 'chapter5.pdf', 'chapter6.pdf', 'chapter7.pdf', 'chapter8.pdf', 'chapter9.pdf']

d[0:-4]

'''
个位数以 chapter1.pdf 为例,从左边开始 1 的下标为 7,从右边开始 1 的下标为 -4,[0:-4]取到的值为 1
多位数以 chapter26.pdf 为例,从左边开始 2 的下标为 7,从右边开始 6 的下标为 -4,[0:-4]取到的值为 26
'''

接着,我们可以这样实现

files=sorted(listD,key=lambda x:int(x[7:-4]))
print(files)

''' 运行结果
['chapter1.pdf', 'chapter2.pdf', 'chapter3.pdf', 'chapter4.pdf', 'chapter5.pdf', 'chapter6.pdf', 'chapter7.pdf', 'chapter8.pdf', 'chapter9.pdf', 'chapter10.pdf', 'chapter11.pdf', 'chapter12.pdf', 'chapter13.pdf', 'chapter14.pdf', 'chapter15.pdf', 'chapter16.pdf', 'chapter17.pdf', 'chapter18.pdf', 'chapter19.pdf', 'chapter20.pdf', 'chapter21.pdf', 'chapter22.pdf', 'chapter23.pdf', 'chapter24.pdf', 'chapter25.pdf', 'chapter26.pdf']
'''



二、合并PDF

首先我们需要安装 PyPDF2 模块

pip install PyPDF2

具体实现代码如下

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/10 20:07
# @Author  : zhouyuyao
# @File    : demon1.py

import codecs
import PyPDF2
import os

filename="E:/GitHub/Python-Learning/LIVE_PYTHON/2018-06-07/deal-with-pdf/aminglinux"
files = list()
for fileName in os.listdir(filename):
    if fileName.endswith(".pdf"):
        files.append(fileName)

newFiles = sorted(files,key=lambda x:int(x[7:-4]))
print(newFiles)

os.chdir(filename)
pdfWriter = PyPDF2.PdfFileWriter()                 # 生成一个空白的pdf
for item in newFiles:
    pdfReader = PyPDF2.PdfFileReader(open(item, "rb"))
    for page in range(pdfReader.numPages):
        pdfWriter.addPage(pdfReader.getPage(page))

with codecs.open("aminglinux.pdf", "wb") as f:     # 命名一个PDF文件 并以二进制写入的方式打开
    pdfWriter.write(f)                             # 将内容写进PDF

运行结果

'''
运行结果,生成了一个aminglinux.pdf的文件,内容为所选 pdf 文件内容的汇总
'''



三、处理图片

PIL (Python Image Library) 是 Python 平台处理图片的事实标准,兼具强大的功能和简洁的 API。



3.1 安装

Pillow 库则是 PIL 的一个分支,维护和开发活跃,Pillow 兼容 PIL 的绝大多数语法,在这里我们也是推荐使用pillow。

pip install pillow



3.2 新建一个 Image 类的实例

PIL 的主要功能定义在 Image 类当中,而 Image 类定义在同名的 Image 模块当中。使用 PIL 的功能,一般都是从新建一个 Image 类的实例开始。新建 Image 类的实例有多种方法。你可以用 Image 模块的 open() 函数打开已有的图片档案,也可以处理其它的实例,或者从零开始构建一个实例。

from PIL import Image
sourceFileName = "source.png"
avatar = Image.open(sourceFileName)

上述代码引入了 Image 模块,并以 open() 方法打开了 source.png 这个图像,构建了名为 avatar 的实例。如果打开失败,则会抛出 IOError 异常。

接下来你可以使用 show() 方法来查看实例。

注意,PIL 会将实例暂存为一个临时文件,而后打开它,具体实现代码如下

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/11 16:38
# @Author  : zhouyuyao
# @File    : demon4.py

from PIL import Image
sourceFileName = "E:/GitHub/Python-Learning/LIVE_PYTHON/2018-06-10/theWayToGo.png"
avatar = Image.open(sourceFileName)    # 打开图片,并构建 avatar 为名的实例
avatar.show()                          # 查看实例

运行之后将会打开图片

python pdf按照文件内容指定命名_Image



3.3 查看实例的属性

Image 类的实例有 5 个属性,分别是:



1)format

以 string 返回图片档案的格式(JPG, PNG, BMP, None, etc.);如果不是从打开文件得到的实例,则返回 None。



2)mode

 以 string 返回图片的模式(RGB, CMYK, etc.);完整的列表参见 官方说明·图片模式列表



3)size

以二元 tuple 返回图片档案的尺寸 (width, height)



4)palette

仅当 mode 为 P 时有效,返回 ImagePalette 示例



5)info

以字典形式返回示例的信息

如果我们想要得到图片的格式、尺寸和模式,则可以加入如下操作

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/11 16:38
# @Author  : zhouyuyao
# @File    : demon4.py
from PIL import Image
sourceFileName = "E:/GitHub/Python-Learning/LIVE_PYTHON/2018-06-10/theWayToGo.png"
avatar = Image.open(sourceFileName)
# avatar.show()

'''获取图片的格式、尺寸和模式'''
print("The picture's format is {0}, the size is {1}, the mode is {2}.".format(avatar.format, avatar.size, avatar.mode))

运行结果

The picture's format is PNG, the size is (718, 726), the mode is RGBA.

这里我们看到返回了图片的格式 PNG、图片的大小 (718, 726) 和图片的模式 RGBA。



3.4 实例的方法

Image 类定义了许多方法,官方说明取自 http://effbot.org/imagingbook/image.htm

# image的方法
# image.show()
# image.open(file)
# image.save(outputfile)
# image.crop(left, upper, right, lower)            #抠图



1)图片 IO - 转换图片格式

Image 模块提供了 open() 函数打开图片档案,Image 类则提供了 save() 方法将图片实例保存为图片档案。

save() 函数可以以特定的图片格式保存图片档案。比如 save('target.jpg', 'JPG') 将会以 JPG 格式将图片示例保存为 target.jpg。不过,大多数时候也可以省略图片格式。此时,save() 方法会根据文件扩展名来选择相应的图片格式。

我们以一个转换图片格式的脚本进行分析。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/11 16:38
# @Author  : zhouyuyao
# @File    : demon4.py

import os, sys
from PIL import Image

for infile in sys.argv[1:]:
    f, e = os.path.splitext(infile)
    outfile = f + ".jpg"
    if infile != outfile:
        try:
            Image.open(infile).save(outfile)
        except IOError:
            print("cannot convert", infile)

这里,f 是除去扩展名之外的文件名。在 try 语句中,我们尝试打开图片档案,然后以 .jpg 为扩展名保存图片档案。save() 方法会根据扩展名,将图片以 JPG 格式保存为档案。如果图片档案无法打开,则在终端上打印无法转换的消息。

代码中需要我们进行传参,在 PyCharm 中如下所示

python pdf按照文件内容指定命名_python_02

运行之后的结果,可以生成图片,但是图片错误不能打开,查了内外网大部分都只是展现了代码,官网给出的解释比较笼统,具体原因待查证

python pdf按照文件内容指定命名_Image_03

后来查了下,是因为选取的那张图片无法转换格式,遂从网上下载了一个图片,则可以转换成功。



2)制作缩略图

Image 类的 thumbnail() 方法可以用来制作缩略图。它接受一个二元数组作为缩略图的尺寸,然后将示例缩小到指定尺寸。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/11 22:15
# @Author  : zhouyuyao
# @File    : demon5.py

import os, sys
from PIL import Image

for infile in sys.argv[1:]:
    outfile = os.path.splitext(infile)[0] + ".thumbnail"
    if infile != outfile:
        try:
            im   = Image.open(infile)
            x, y = im.size
            im.thumbnail((x//2, y//2))
            im.save(outfile, "JPEG")
        except IOError:
            print("cannot create thumbnail for", infile)

这里我们用 im.size 获取原图档的尺寸,然后以 thumbnail() 制作缩略图,大小则是原先图档的四分之一。同样,如果图档无法打开,则在终端上打印无法执行的提示。



3)剪裁图档

按照 horizon 和 vertic 两个变量切割当前目录下所有图片(包括子目录)

import Image as img
import os

imgTypes = ['.png','.jpg','.bmp']

horizon = 8
vertic  = 1

for root, dirs, files in os.walk('.'):
    for currentFile in files:
        crtFile = root + '\\' + currentFile
        if crtFile[crtFile.rindex('.'):].lower() in imgTypes:
            crtIm = img.open(crtFile)
            crtW, crtH = crtIm.size
            hStep = crtW // horizon
            vStep = crtH // vertic
            for i in range(vertic):
                for j in range(horizon):
                    crtOutFileName = crtFile[:crtFile.rindex('.')] + \
                        '_' + str(i) + '_' + str(j)\
                        + crtFile[crtFile.rindex('.'):].lower()
                    box = (j * hStep, i * vStep, (j + 1) * hStep, (i + 1) * vStep)
                    cropped = crtIm.crop(box)
                    cropped.save(crtOutFileName)



4)变形与粘贴

transpose() 方法可以将图片左右颠倒、上下颠倒、旋转 90°、旋转 180° 或旋转 270°。paste() 方法则可以将一个 Image 示例粘贴到另一个 Image 示例上。

我们尝试将一张图片的左半部分截取下来,左右颠倒之后旋转 180°;将图片的右半边不作更改粘贴到左半部分;最后将修改过的左半部分粘贴到右半部分。
 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/11 22:53
# @Author  : zhouyuyao
# @File    : demon6.py
from PIL import Image

imageFName = 'E:/GitHub/Python-Learning/LIVE_PYTHON/2018-06-10/theWayToGo.png'

def iamge_transpose(image):
    '''
        Input: a Image instance
        Output: a transposed Image instance
        Function:
            * switches the left and the right part of a Image instance
            * for the left part of the original instance, flips left and right\
                and then make it upside down.
    '''
    xsize, ysize = image.size
    xsizeLeft    = xsize // 2 # while xsizeRight = xsize - xsizeLeft

    boxLeft      = (0, 0, xsizeLeft, ysize)
    boxRight     = (xsizeLeft, 0, xsize, ysize)
    boxLeftNew   = (0, 0, xsize - xsizeLeft, ysize)
    boxRightNew  = (xsize - xsizeLeft, 0, xsize, ysize)

    partLeft     = image.crop(boxLeft).transpose(Image.FLIP_LEFT_RIGHT).\
        transpose(Image.ROTATE_180)
    partRight    = image.crop(boxRight)

    image.paste(partRight, boxLeftNew)
    image.paste(partLeft, boxRightNew)
    return image

avatar = Image.open(imageFName)
avatar = iamge_transpose(avatar)
avatar.show()

运行之后,图片通过代码实现了另一种展示效果

python pdf按照文件内容指定命名_python_04



四、生成验证码

首先需要安装模块 “Pillow”

pip install pillow

代码实现如下

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2018/6/11 15:11
# @Author  : zhouyuyao
# @File    : demon3.py

import random
import string
from PIL import Image, ImageDraw, ImageFont, ImageFilter

class VerCode(object):
    def __init__(self):
        # 字体的位置,不同版本的系统会有不同
        self.font_path = 'E:/GitHub/Python-Learning/LIVE_PYTHON/2018-06-10/msyh.ttc'
        # 生成几位数的验证码
        self.number = 4
        # 生成验证码图片的高度和宽度
        self.size = (100, 30)
        # 背景颜色,默认为白色
        self.bgcolor = (255, 255, 255)
        # 字体颜色,默认为蓝色
        self.fontcolor = (0, 0, 255)
        # 干扰线颜色。默认为红色
        self.linecolor = (255, 0, 0)
        # 是否要加入干扰线
        self.draw_line = True
        # 加入干扰线条数的上下限
        self.line_number = 20

    # 用来随机生成一个字符串
    def gene_text(self):
        self.source = list(string.ascii_letters)
        for self.index in range(0, 10):
            self.source.append(str(self.index))
        return ''.join(random.sample(self.source, self.number))     # number是生成验证码的位数

    # 用来绘制干扰线
    def gene_line(self, draw, width, height):
        self.begin = (random.randint(0, width), random.randint(0, height))
        self.end = (random.randint(0, width), random.randint(0, height))
        draw.line([self.begin, self.end], fill=self.linecolor)

    # 生成验证码
    def gene_code(self):
        self.width, self.height = self.size                                      # 宽和高
        self.image = Image.new('RGBA', (self.width, self.height), self.bgcolor)  # 创建图片
        self.font = ImageFont.truetype(self.font_path, 25)                       # 验证码的字体
        self.draw = ImageDraw.Draw(self.image)                                   # 创建画笔
        self.text = self.gene_text()                                             # 生成字符串
        self.font_width, self.font_height = self.font.getsize(self.text)
        self.draw.text(((self.width - self.font_width) / self.number, (self.height - self.font_height) / self.number),
                       self.text, font=self.font, fill=self.fontcolor)           # 填充字符串
        if self.draw_line:
            for i in range(self.line_number):
                self.gene_line(self.draw, self.width, self.height)

    def effect(self):
        # self.image = self.image.transform((self.width + 20, self.height + 10), Image.AFFINE, (1, -0.3, 0, -0.1, 1, 0), Image.BILINEAR)                                            # 创建扭曲
        self.image = self.image.filter(ImageFilter.EDGE_ENHANCE_MORE)            # 滤镜,边界加强
        self.image.save('validateCodePic.png')                                   # 保存验证码图片
        # self.image.show()

if __name__ == "__main__":
    # 进行封装
    vco = VerCode()
    vco.gene_code()
    vco.effect()

运行之后,我们得到的一个验证码图片如下所示,实际应用中我们每次调用都会重新生成

python pdf按照文件内容指定命名_c/c++_05

 



参考资料

1. http://www.runoob.com/python3/python3-function.html 菜鸟教程

2. http://www.runoob.com/python3/python3-func-sorted.html 菜鸟教程

3. http://blog.51cto.com/286577399/2062340 51. Python 数据处理(2)

4.  Django之路 - 实现登录随机验证码

5. https://liam0205.me/2015/04/22/pil-tutorial-basic-usage/ PIL 简明教程 - 基本用法

6. https://liam0205.me/2014/01/27/Py-Incise-Images/ 【Life on Python】批量切割图片

7.  Python开发【笔记】:sort排序大法