后端编程Python3-图形处理类(python图形化编程工具哪个好)
off999 2024-10-19 07:15 14 浏览 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图形处理类,更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。
相关推荐
- 推荐一款Python的GUI可视化工具(python 可视化工具)
-
在Python基础语法学习完成后,进一步开发应用界面时,就需要涉及到GUI了,GUI全称是图形用户界面(GraphicalUserInterface,又称图形用户接口),采用图形方式显示的计算机操...
- 教你用Python绘制谷歌浏览器的3种图标
-
前两天在浏览matplotlib官方网站时,笔者无意中看到一个挺有意思的图片,就是用matplotlib制作的火狐浏览器的logo,也就是下面这个东东(网页地址是https://matplotlib....
- 小白学Python笔记:第二章 Python安装
-
Windows操作系统的python安装:Python提供Windows、Linux/UNIX、macOS及其他操作系统的安装包版本,结合自己的使用情况,此处仅记录windows操作系统的python...
- Python程序开发之简单小程序实例(9)利用Canvas绘制图形和文字
-
Python程序开发之简单小程序实例(9)利用Canvas绘制图形和文字一、项目功能利用Tkinter组件中的Canvas绘制图形和文字。二、项目分析要在窗体中绘制图形和文字,需先导入Tkinter组...
- 一文吃透Python虚拟环境(python虚拟环境安装和配置)
-
摘要在Python开发中,虚拟环境是一种重要的工具,用于隔离不同项目的依赖关系和环境配置。本文将基于windows平台介绍四种常用的Python虚拟环境创建工具:venv、virtualenv、pip...
- 小白也可以玩的Python爬虫库,收藏一下
-
最近,微软开源了一个项目叫「playwright-python」,作为一个兴起项目,出现后受到了大家热烈的欢迎,那它到底是什么样的存在呢?今天为你介绍一下这个传说中的小白神器。Playwright是...
- python环境安装+配置教程(python安装后怎么配置环境变量)
-
安装python双击以下软件:弹出一下窗口需选择一些特定的选项默认选项不需要更改,点击next勾选以上选项,点击install进度条安装完毕即可。到以下界面,证明安装成功。接下来安装库文件返回电脑桌面...
- colorama,一个超好用的 Python 库!
-
大家好,今天为大家分享一个超好用的Python库-colorama。Github地址:https://github.com/tartley/coloramaPythoncolorama库是一...
- python制作仪表盘图(python绘制仪表盘)
-
今天教大家用pyecharts画仪表盘仪表盘(Gauge)是一种拟物化的图表,刻度表示度量,指针表示维度,指针角度表示数值。仪表盘图表就像汽车的速度表一样,有一个圆形的表盘及相应的刻度,有一个指针...
- 总结90条写Python程序的建议(python写作)
-
1.首先 建议1、理解Pythonic概念—-详见Python中的《Python之禅》 建议2、编写Pythonic代码 (1)避免不规范代码,比如只用大小写区分变量、使用容易...
- [oeasy]python0137_相加运算_python之禅_import_this_显式转化
-
变量类型相加运算回忆上次内容上次讲了是从键盘输入变量input函数可以有提示字符串需要有具体的变量接收输入的字符串输入单个变量没有问题但是输入两个变量之后一相加就非常离谱添加图片注释,不超过1...
- Python入门学习记录之一:变量(python中变量的规则)
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- 掌握Python的"魔法":特殊方法与属性完全指南
-
在Python的世界里,以双下划线开头和结尾的"魔法成员"(如__init__、__str__)是面向对象编程的核心。它们赋予开发者定制类行为的超能力,让自定义对象像内置类型一样优雅工...
- 11个Python技巧 不Pythonic 实用大于纯粹
-
虽然Python有一套强大的设计哲学(体现在“Python之禅”中),但总有一些情况需要我们“打破规则”来解决特定问题。这触及了Python哲学中一个非常核心的理念:“实用主义胜于纯粹主义”...
- Python 从入门到精通 第三课 诗意的Python之禅
-
导言:Python之禅,英文名是TheZenOfPython。最早由TimPeters在Python邮件列表中发表,它包含了影响Python编程语言设计的20条软件编写原则。它作为复活节彩蛋...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python字典遍历 (54)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (60)
- python读取文件夹下所有文件 (59)
- java调用python脚本 (56)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)