后端编程Python3-图形处理类(python图形化编程工具哪个好)
off999 2024-10-19 07:15 18 浏览 0 评论
本节是第五讲的第十四小节,本节参照上一节所讲的python面向对象的知识,以一个图形处理的类讲解如何创建聚集组合数据的类。
创建聚集组合数据的类(Creating Classes That Aggregate Collections)
用于表示2D颜色图像的一个简单方法是使用一个2维数组,每个数组元素代表一种颜色。因此,如果需要表示一个100x100的图像,我们就必须存储10000个颜色。 对Image类(在文件Image.py中),我们将釆取一种具有更加高效的潜力的做法。Image 存储一种单一的背景色,图像中各个点的颜色则不同于背景色。这是通过将字典用作稀疏数组实现的,字典中的每个键是一个(x,y)坐标,对应的值则为该点的颜色。如果我们有一个100x100的图像,并且其中半数的点都与背景色相同,那么只需要存储 5 000 + 1种颜色,从而大幅节省内存资源。
Image.py模块釆用了我们现在应该已经熟悉的模式:模块从一个shebang行开始,之后是注释中的版权信息。再之后是模块的docstring以及一些doctests/接下来是导入语句,本模块中需要导入os模块与pickle模块。在讲解图像的加载与保存时,我们将简要讲述Pickle模块的使用。在导入相应模块之后,我们创建一些自定义异常类:
class lmageError(Exception): pass
class CoordinateError(lmageError): pass
我们只是展示了头两个异常类,其他异常类(LoadError、SaveError、ExportError 与NoFilenameError)的创建方式是相同的,并且也都继承自ImageError。
Image类的使用者可以对任一种特定的异常进行测试,也可以只对基类的ImageError异常进行测试。
该模块的余下部分包括Image类的主体,最后则是用于运行模块的doctests的标准的三行代码。在具体讲解该类及其方法之前,我们先看一下该类如何使用:
border_color =“#FF0000" # red
square_color = "#0000FF” # blue
width, height = 240, 60
midx,midy = width // 2, height // 2
image = Image.Image(width, height, "square_eye.img")
for x in range(width):
for y in range(height):
if x < 5 or x >= width - 5 or y < 5 or y >= height - 5:
image[x, y] = border_color
elif midx - 20 < x < midx + 20 and midy - 20 < y < midy + 20:
image[x, y] = square_color
image.save()
image.export("square_eye.xpm")
注意,我们可以使用项存取操作符([])来设置图像中的颜色。方括号也可以用于对特定(x,y)坐标的颜色进行获取或删除,也可以有效地将其颜色设置为背景色。坐标是以单独的元组对象的形式进行传递的(借助于其中的逗号操作符),就像我们使用 image[(x, y)]这种表达方式一样。在Python中,实现这种无缝的语法整合是容易的 ——我们只需要实现适当的特殊方法,比如,对项存取操作符,对应的特殊方法包括 __getitem__()、__setitem__()与__delitem__()。
Image类使用HTML风格的十六进制字符串表示颜色。在创建图像时就必须设置背景色,否则就默认为白色。在存储与加载图像时,Image类使用其自定义格式,但也可以使用.xpm格式导出,该格式很多图像处理应用程序都可以理解。如图展示了上面的代码段生成的.xpm图像。
现在我们来看Image类的方法,从class行与初始化程序开始。创建Image时,使用者(该类的使用者)必须指定宽度与高度,但文件名与背景色则是可选的,因为有默认值。字典self.__data的键是(x, y)坐标,值为颜色字符串。集合self.__colors使用背景色进行初始化,并用于追踪图像中使用的各种排他性的颜色。
除文件名外,所有数据属性都是私有属性,因此,必须提供一种途径,以便使用者可以对这些属性进行存取。通过使用特性,可以容易地做到这一点。
class Image:
def __init__(self, width, height, filename=“”,background=“#FFFFFF"):
self.filename = filename
self.__background = background
self.__data = {}
self.__width = width
self.__height = height
self.__colors = {self.__background}
@property
def background(self):
return self.__background
@property
def width(self):
return self.__width
@property
def height(self):
return self.__height
@property
def colors(self):
return set(self.__colors)
在返回对象的某个数据属性时,我们需要知道该属性是属于可变类型还是固定类型,返回固定类型总是安全的,因为这种类型的数据属性不能改变,但对于可变类型的数据属性,我们必须考虑某种折衷。返回对可变属性的引用是非常快速高效的,因为并没有实际的复制操作发生——但这也意味着调用者可以对对象的内部状态进行存取,并可能在对其改变时导致对象无效。一种解决方案是总是返回可变数据属性的副本,除非有证据表明这种做法会对性能产生很大的负面影响。(这种情况下,保证颜色集合有效的一种替代方法是在需要颜色集合时,总是返回set(self.__data.values()) | {self.__background}。)
#这一方法将返回给定坐标的颜色(使用项存取操作符[])
def__getitem__(self, coordinate):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
return self.__data.get(tuple(coordinate), self.__background)
下表列出了用于项存取操作符的特殊方法以及其他一些组合类型相关的特殊方法。
特殊方法 使用 描述
__contains__(self,x) x in y 如果x在序列y中或x是映射y中的键,就返回True
__delitem__(self,k) del y[k] 删除序列y中的第k项或映射y中键为k的项
__getitem__(self,k) y[k] 返回序列y中的第k项或映射y中键为k的项的值
__iter__(self) for x in y: pass 返回序列y中的项或映射y中键的迭代子
__len__(self) len(y) 返回y中项的个数
__reversed__(self) reversed(y) 返回序列y中的项或映射y中键的反向迭代子
__setitem__(self, k, v) y[k] = v 将序列y中的第k项(或映射y中键为k的项)设置为v
def__setitem__(self, coordinate, color):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
if color == self.__background:
self.__data.pop(tuple(coordinate), None)
else:
self.__data[tuple(coordinate)] = color
self.__colors.add(color)
我们对项存取釆用了两种策略。第一种策略的使用前提是,传递给项存取方法的坐标是长度为2的序列(通常是二元组),并使用断言来确保满足这一约束。第二种策略是接受任意的坐标值,如果超过取值范围,就产生自定义异常。
我们使用dict.get()方法来取回给定坐标的颜色(默认值为背景色),通过这一方法, 如果该坐标处的颜色尚未设置,就正确地返回背景色,而不是产生KeyError异常。
如果使用者将某坐标值设置为背景色,我们可以简单地将相应的字典项删除,因为字典中没有包含的坐标都假定使用背景色。为此,我们必须使用dict.pop()并给定另 一个单元参数,而不是使用del语句,因为这样可以保证在键(坐标)不存在于字典中的情况下,也可以避免产生KeyError异常。
如果颜色不同于背景色,我们就将给定的坐标指定为该颜色,并将该颜色添加到图像使用的颜色集中。
def __delitem__(self, coordinate):
assert len(coordinate) == 2, "coordinate should be a 2-tuple”
if (not (0 <= coordinate[0] < self.width) or not (0 <= coordinate!!] < self.height)):
raise CoordinateError(str(coordinate))
self.__data.pop(tuple(coordinate),None)
如果某坐标的颜色被删除,那么该坐标的颜色被设置为背景色。这里仍然需要使用dict.pop()来移除相应项,因为不管给定的坐标项是否存在于字典中,这一方法总是可以正确工作,而不会产生异常。
我们没有提供__len__()的实现,因为对二维对象而言,这一函数没有实际意义。 另外,我们也没有提供表象形式,因为Image不能仅通过调用Image()就完全实现,因 此,我们也没有提供__repr__()(或__str__())的实现。如果用户对Image对象调用repr() 或str(),那么object.__repr__()这一基类实现将返回适当的字符串,比如'<Image.Image object at 0x9c794ac>'。这是用于无法使用eval()评估的对象的标准格式,十六进制数字是对象ID—这是独一无二的(通常是对象在内存中所在地址),但是短暂的。
我们希望Image类的使用者可以保存与加载其图像数据,因此,我们提供了两个方法来完成这两个任务,分别为save()与load()。
为保存数据,我们采用的做法是对其进行pickling,在Python中,pickling是将 Python对象进行序列化(转换为字节序列,或转换为字符串)的一种方法。pickling 之所以强大,是因为进行pickling处理的对象可以是组合数据类型,比如列表或字典, 并且,即便要进行pickling处理的对象内部包含其他对象(包含其他组合类型,其中又可以嵌套地包含其他组合类型),仍然可以统一进行pickling处理——并且不会使得对象重复出现。
pickle可以直接地读入到Python变量中——我们并不需要进行任何分析或解释处理,因此,使用pickle是存取与加载数据的特别集合时的一种理想选择,尤其对小程序以及个人使用的程序。然而,pickle没有安全机制(没有加密,也没有数字签名),因此,加载来自不可信源的pickle可能是危险的。鉴于此,对那些不纯粹用于个人目的的程序,最好是创建一种专用于该程序的自定义文件格式。
def save(self, filename=None):
if filename is not None:
self.filename = filename
if not self.filename:
raise NoFilenameError()
fh = None
try:
data = [self.width, self.height, self.__background,self.__data]
fh = open(self.filename, "wb")
pickle.dump(data, fh, pickle.HIGHEST_PROTOCOL)
except (EnvironmentError, pickle.PicklingError) as err:
raise SaveError(str(err))
finally:
if fh is not None:
fh.close()
该函数的第一部分纯粹用于处理文件名。如果创建Image对象时没有指定文件名或没有设置文件名,就必须对save()方法给定显式的文件名(对这种情况,可以釆用 “另存为"的方式,并设置内部使用的文件名)。如果没有指定文件名,就使用当前的文件名;如果没有当前使用的文件名,也没有指定文件名,就会产生异常。我们创建一个列表(data)用于存放待存储的对象,包括self.__data字典(其中存放坐标-颜色项),但不包含颜色集,因为该数据集可能被重构。之后,我们以二进制写模式打开文件,并调用pickle.dump()函数将数据对象写入到文件中。这一部分功能实现完毕!pickle模块可以使用多种格式(在文档中称为protocols)对数据进行序列化,不同格式由pickle.dump()的第三个参数指定。Protocol 0表示的是ASCII,在调试时是有用的。我们使用了 protocol 3 (pickle.HIGHEST_PROTOCOL), 一种紧凑的二进制格式,这也是为什么要以二进制格式打开文件。
def load(self, filename=None):
if filename is not None:
self.filename = filename
if not self.filename:
raise NoFilenameError()
fh = None
try:
fh = open(self.filename,"rb")
data = pickle.load(fh)
(self.__width, self.__height, self.__background,self. __data) = data
self.__colors = (set(self.__data.values()) |{self.__background})
except (EnvironmentError, pickle.UnpicklingError) as err:
raise LoadError(str(err))
finally:
If fh is not None:
fh.dose()
读取pickle时,没有指定protocol——pickle.load()函数完全可以推断出用于自己的protocol。
这一函数开始时与save()函数类似,获取待加载文件的文件名。文件必须以二进制读模式打开,并使用语句data = pickle.load(fh)读入数据。data对象是对保存的数据的精确重建,因此,这里实际上是一个列表,包括宽度与长度整数值、背景色字符串以及包含坐标-颜色项的字典。我们使用元组拆分来将data列表的项赋值到适当的变量中,因此,此前存放的图像数据将丢失(可接受的)。
颜色集合的重建是通过提取字典(包含坐标-颜色项)中的所有颜色,之后添加背景色实现的。
def export(self, filename):
if filename.lower().endswith(".xpm"):
self.__export_xpm(filename)
else:
raise ExportError("unsupported export format:" +os.path.splitext(filename)[1])
我们提供了一个通用的导出方法,该方法使用文件扩展名确定调用哪一个私有方 法一对无法导出的文件格式,则产生异常。这里,我们仅支持保存到.xpm文件(仅对包含少于8930种颜色的图像)。我们没有给出__export_xpm()方法,因为该方法并不与本章的主题真正相关,但本书源代码中仍然包含了该方法。
以上内容部分摘自视频课程05后端编程Python14图形处理类,更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。
相关推荐
- 大文件传不动?WinRAR/7-Zip 入门到高手,这 5 个技巧让你效率翻倍
-
“这200张照片怎么传给女儿?微信发不了,邮箱附件又超限……”62岁的张阿姨对着电脑犯愁时,儿子只用了3分钟就把照片压缩成一个文件,还教她:“以后用压缩软件,比打包行李还方便!”职场人更懂这...
- 电脑解压缩软件推荐——7-Zip:免费、高效、简洁的文件管理神器
-
在日常工作中,我们经常需要处理压缩文件。无论是下载软件包、接收文件,还是存储大量数据,压缩和解压缩文件都成为了我们日常操作的一部分。而说到压缩解压软件,7-Zip绝对是一个不可忽视的名字。今天,我就来...
- 设置了加密密码zip文件要如何打开?这几个方法可以试试~
-
Zip是一种常见的压缩格式文件,文件还可以设置密码保护。那设置了密码的Zip文件要如何打开呢?不清楚的小伙伴一起来看看吧。当我们知道密码想要打开带密码的Zip文件,我们需要用到适用于Zip格式的解压缩...
- 大文件想要传输成功,怎么把ZIP文件分卷压缩
-
不知道各位小伙伴有没有这样的烦恼,发送很大很大的压缩包会受到限制,为此,想要在压缩过程中将文件拆分为几个压缩包并且同时为所有压缩包设置加密应该如何设置?方法一:使用7-Zip免费且强大的文件管理工具7...
- 高效处理 RAR 分卷压缩包:合并解压操作全攻略
-
在文件传输和存储过程中,当遇到大文件时,我们常常会使用分卷压缩的方式将其拆分成多个较小的压缩包,方便存储和传输。RAR作为一种常见的压缩格式,分卷压缩包的使用频率也很高。但很多人在拿到RAR分卷...
- 2个方法教你如何删除ZIP压缩包密码
-
zip压缩包设置了加密密码,每次解压文件都需要输入密码才能够顺利解压出文件,当压缩包文件不再需要加密的时候,大家肯定想删除压缩包密码,或是忘记了压缩包密码,想要通过删除操作将压缩包密码删除,就能够顺利...
- 速转!漏洞预警丨压缩软件Winrar目录穿越漏洞
-
WinRAR是一款功能强大的压缩包管理器,它是档案工具RAR在Windows环境下的图形界面。该软件可用于备份数据,缩减电子邮件附件的大小,解压缩从Internet上下载的RAR、ZIP及其它类...
- 文件解压方法和工具分享_文件解压工具下载
-
压缩文件减少文件大小,降低文件失效的概率,总得来说好处很多。所以很多文件我们下载下来都是压缩软件,很多小伙伴不知道怎么解压,或者不知道什么工具更好,所以今天做了文件解压方法和工具的分享给大家。一、解压...
- [python]《Python编程快速上手:让繁琐工作自动化》学习笔记3
-
1.组织文件笔记(第9章)(代码下载)1.1文件与文件路径通过importshutil调用shutil模块操作目录,shutil模块能够在Python程序中实现文件复制、移动、改名和删除;同时...
- Python内置tarfile模块:读写 tar 归档文件详解
-
一、学习目标1.1学习目标掌握Python内置模块tarfile的核心功能,包括:理解tar归档文件的原理与常见压缩格式(gzip/bz2/lzma)掌握tar文件的读写操作(创建、解压、查看、过滤...
- 使用python展开tar包_python拓展
-
类Unix的系统,打包文件经常使用的就是tar包,结合zip工具,可以方便的打包并解压。在python的标准库里面有tarfile库,可以方便实现生成了展开tar包。使用这个库最大的好处,可能就在于不...
- 银狐钓鱼再升级:白文件脚本化实现GO语言后门持久驻留
-
近期,火绒威胁情报中心监测到一批相对更为活跃的“银狐”系列变种木马。火绒安全工程师第一时间获取样本并进行分析。分析发现,该样本通过阿里云存储桶下发恶意文件,采用AppDomainManager进行白利...
- ZIP文件怎么打开?2个简单方法教你轻松搞定!
-
在日常工作和生活中,我们经常会遇到各种压缩文件,其中最常见的格式之一就是ZIP。ZIP文件通过压缩数据来减少文件大小,方便我们进行存储和传输。然而,对于初学者来说,如何打开ZIP文件可能会成为一个小小...
- Ubuntu—解压多个zip压缩文件.zip .z01 .z02
-
方法将所有zip文件放在同一目录中:zip_file.z01,zip_file.z02,zip_file.z03,...,zip_file.zip。在Zip3.0版本及以上,使用下列命令:将所有zi...
- 如何使用7-Zip对文件进行加密压缩
-
7-Zip是一款开源的文件归档工具,支持多种压缩格式,并提供了对压缩文件进行加密的功能。使用7-Zip可以轻松创建和解压.7z、.zip等格式的压缩文件,并且可以通过设置密码来保护压缩包中的...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)