Disqus 取代 Convore 参加 PyCon 2012!

原文: https://www.blog.pythonlibrary.org/2012/03/09/disqus-replaces-convore-for-pycon-2012/

对于那些不知道的人来说,康沃不在了,看起来迪斯克斯在了: https://pycon.disqus.com/

我认为去年的 Convore 相当有趣,尽管有一些小问题。我很想听听人们对 disqus 系统和 convore 系统的看法。

如何分发 wxPython 应用程序

原文: https://www.blog.pythonlibrary.org/2019/03/19/distributing-a-wxpython-application/

假设您使用 wxPython 完成了一个精彩的 GUI 应用程序。如何与世界分享?当你完成一个惊人的程序时,这总是一个两难的选择。幸运的是,有几种方法可以共享您的代码。如果你想和其他开发者分享你的代码,那么 Github 或者类似的网站绝对是一个不错的选择。我不会在这里讨论使用 Git 或 Mercurial。相反,您将在这里学习如何将您的应用程序转换成可执行文件。

通过将您的代码转换为可执行文件,您可以允许用户只下载二进制文件并运行它,而不需要他们下载 Python、您的源代码和您的依赖项。所有这些都将被打包成可执行文件。

有许多工具可以用来生成可执行文件:

  • py2exe
  • py2app
  • PyInstaller
  • cx_Freeze
  • bbfreeze
  • 在本教程中,您将使用 PyInstaller 。使用 PyInstaller 的主要好处是它可以为 Windows、Mac 和 Linux 生成可执行文件。注意,它不 支持交叉编译。这意味着您不能在 Linux 上运行 PyInstaller 来创建 Windows 可执行文件。相反,PyInstaller 将只为运行它的操作系统创建一个可执行文件。换句话说,如果您在 Windows 上运行 PyInstaller,它将只创建一个 Windows 可执行文件。

    安装 PyInstaller

    安装 PyInstaller 包非常简单明了。你只需要匹普。

    下面是将 PyInstaller 安装到 Python 系统的方法:

    pip install pyinstaller

    您还可以使用 Python 的 venv 模块或 virtualenv 包将 PyInstaller 安装到虚拟 Python 环境中。

    生成可执行文件

    PyInstaller 的优点是开箱即用非常容易。你所需要做的就是运行“pyinstaller”命令,后跟你要转换成可执行文件的应用程序主文件的路径。

    下面是一个不起作用的例子:

    pyinstaller path/to/main/script.py

    如果没有找到 PyInstaller 应用程序,您可能需要指定它的完整路径。默认情况下,PyInstaller 安装到 Python 的 Scripts 子文件夹,该文件夹将位于您的系统 Python 文件夹或虚拟环境中。

    让我们从我即将出版的 中选取一个简单的应用程序,并把它变成一个可执行程序。例如,您可以使用第 3 章中的 image _ viewer _ slide show . py :

    # image_viewer_slideshow.py import glob import os import wx class ImagePanel(wx.Panel): def __init__(self, parent): super().__init__(parent) self.max_size = 240 self.photos = [] self.current_photo = 0 self.total_photos = 0 self.layout() self.slideshow_timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.on_next, self.slideshow_timer) def layout(self): Layout the widgets on the panel self.main_sizer = wx.BoxSizer(wx.VERTICAL) btn_sizer = wx.BoxSizer(wx.HORIZONTAL) img = wx.Image(self.max_size, self.max_size) self.image_ctrl = wx.StaticBitmap(self, wx.ID_ANY, wx.Bitmap(img)) self.main_sizer.Add(self.image_ctrl, 0, wx.ALL|wx.CENTER, 5) self.image_label = wx.StaticText(self, label="") self.main_sizer.Add(self.image_label, 0, wx.ALL|wx.CENTER, 5) btn_data = [("Previous", btn_sizer, self.on_previous), ("Slide Show", btn_sizer, self.on_slideshow), ("Next", btn_sizer, self.on_next)] for data in btn_data: label, sizer, handler = data self.btn_builder(label, sizer, handler) self.main_sizer.Add(btn_sizer, 0, wx.CENTER) self.SetSizer(self.main_sizer) def btn_builder(self, label, sizer, handler): Builds a button, binds it to an event handler and adds it to a sizer btn = wx.Button(self, label=label) btn.Bind(wx.EVT_BUTTON, handler) sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5) def on_next(self, event): Loads the next picture in the directory if not self.photos: return if self.current_photo == self.total_photos - 1: self.current_photo = 0 else: self.current_photo += 1 self.update_photo(self.photos[self.current_photo]) def on_previous(self, event): Displays the previous picture in the directory if not self.photos: return if self.current_photo == 0: self.current_photo = self.total_photos - 1 else: self.current_photo -= 1 self.update_photo(self.photos[self.current_photo]) def on_slideshow(self, event): Starts and stops the slideshow btn = event.GetEventObject() label = btn.GetLabel() if label == "Slide Show": self.slideshow_timer.Start(3000) btn.SetLabel("Stop") else: self.slideshow_timer.Stop() btn.SetLabel("Slide Show") def update_photo(self, image): Update the currently shown photo img = wx.Image(image, wx.BITMAP_TYPE_ANY) # scale the image, preserving the aspect ratio W = img.GetWidth() H = img.GetHeight() if W > H: NewW = self.max_size NewH = self.max_size * H / W else: NewH = self.max_size NewW = self.max_size * W / H img = img.Scale(NewW, NewH) self.image_ctrl.SetBitmap(wx.Bitmap(img)) self.Refresh() def reset(self): img = wx.Image(self.max_size, self.max_size) bmp = wx.Bitmap(img) self.image_ctrl.SetBitmap(bmp) self.current_photo = 0 self.photos = [] class MainFrame(wx.Frame): def __init__(self): super().__init__(None, title='Image Viewer', size=(400, 400)) self.panel = ImagePanel(self) self.create_toolbar() self.Show() def create_toolbar(self): Create a toolbar self.toolbar = self.CreateToolBar() self.toolbar.SetToolBitmapSize((16,16)) open_ico = wx.ArtProvider.GetBitmap( wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (16,16)) openTool = self.toolbar.AddTool( wx.ID_ANY, "Open", open_ico, "Open an Image Directory") self.Bind(wx.EVT_MENU, self.on_open_directory, openTool) self.toolbar.Realize() def on_open_directory(self, event): Open a directory dialog with wx.DirDialog(self, "Choose a directory", style=wx.DD_DEFAULT_STYLE) as dlg: if dlg.ShowModal() == wx.ID_OK: self.folderPath = dlg.GetPath() photos = glob.glob(os.path.join(self.folderPath, '*.jpg')) self.panel.photos = photos if photos: self.panel.update_photo(photos[0]) self.panel.total_photos = len(photos) else: self.panel.reset() if __name__ == '__main__': app = wx.App(redirect=False) frame = MainFrame() app.MainLoop()

    如果您想将其转换为可执行文件,您可以运行以下命令:

    pyinstaller image_viewer_slideshow.py

    确保在运行该命令时,当前工作目录是包含要转换为可执行文件的脚本的目录。PyInstaller 将在当前工作目录下创建输出。

    当您运行这个命令时,您应该在终端中看到类似这样的内容:

    PyInstaller 将在与您正在转换的脚本相同的文件夹中创建两个文件夹,分别名为 dist build 。如果 PyInstaller 成功完成,您将在 dist 文件夹中找到您的可执行文件。除了您的可执行文件, dist 文件夹中还有许多其他文件。这些是运行可执行文件所必需的文件。

    现在让我们尝试运行您新创建的可执行文件。当我运行我的副本时,我注意到一个终端/控制台出现在我的应用程序后面。

    背景中带有控制台的图像查看器

    这是正常的,因为 PyInstaller 的默认行为是将您的应用程序构建为命令行应用程序,而不是 GUI。

    您需要添加 - noconsole 标志来移除控制台:

    pyinstaller image_viewer_slideshow.py --noconsole

    现在,当您运行结果时,您应该不会再看到一个控制台窗口出现在您的应用程序后面。

    分发大量文件可能会很复杂,因此 PyInstaller 有另一个命令,您可以使用它将所有内容打包成一个可执行文件。该命令是 - onefile 。顺便说一下,您在 PyInstaller 中使用的许多命令都有较短的别名。例如,您也可以使用“- noconsole”的一个更短的别名: -w 。注意`-w '中的单破折号。

    因此,让我们利用这些信息,让 PyInstaller 创建一个没有控制台的可执行文件:

    dist folder.

    PyInstaller 有规范文件的概念。它们有点像是一个 setup.py 脚本,你可以在 Python 的 distutils 中使用它。这些规范文件告诉 PyInstaller 如何构建您的可执行文件。PyInstaller 将自动为您生成一个与脚本中传递的名称相同的文件,但是带有一个 。规格 扩展。所以如果你传入了 image _ viewer _ slide show . py ,那么在运行 PyInstaller 之后你应该会看到一个 image _ viewer _ slide show . spec 文件。该规格文件将创建在与应用程序文件相同的位置。

    下面是上次运行 PyInstaller 时创建的规范文件的内容:

    # -*- mode: python -*- block_cipher = None a = Analysis(['image_viewer.py'], pathex=['C:\\Users\\mdriscoll\\Documents\\test'], binaries=[], datas=[], hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name='image_viewer', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, runtime_tmpdir=None, console=False )

    虽然 PyInstaller 可以很好地处理图像查看器示例,但您可能会发现,如果您有其他依赖项,如 NumPy 或 Pandas,它就不能开箱即用了。如果您遇到 PyInstaller 的问题,它有非常详细的日志,您可以使用它来帮助您解决问题。一个很好的位置是“build/cli/warn-cli.txt”文件。您可能还想在不使用`-w '命令的情况下进行重建,以便可以在控制台窗口中看到输出到 stdout 的内容。

    还有一些选项可以在构建过程中更改日志级别,这可能有助于发现问题。

    如果这些都不起作用,试试谷歌或者去 PyInstaller 的 支持页面 获得帮助。

    为 Mac 创建可执行文件

    虽然相同的命令在 Mac OSX 上应该和在 Windows 上一样有效,但是我发现我需要运行以下命令来生成一个有效的可执行文件:

    pyinstaller image_viewer_slideshow.py --windowed

    PyInstaller 生成的输出会略有不同,结果是一个应用程序文件。

    在 Mac 上生成应用程序的另一个流行选项是名为 py2app 的 Python 包。

    为 Linux 创建可执行文件

    对于 Linux,通常建议您用旧版本的 glibc 构建可执行文件,因为新版本的 glibc 是向后兼容的。通过使用旧版本的 Linux 进行构建,您通常可以针对更广泛的 Linux 版本。但是您的里程可能会有所不同。

    文件生成后,您可以将它们打包成一个 gzipped tarball (.tax.gz)。如果您愿意,您甚至可以使用您在本书中创建的归档应用程序来完成这项工作。

    另一种方法是学习如何创建一个大多数 Linux 版本都可以安装的. deb 或相关文件。

    了解关于 PyInstaller 的更多信息

    本文并不是 PyInstaller 的深入指南。它的变化可能比 wxPython 快得多,所以建议您阅读 PyInstaller 的文档。它将永远是您获取项目所需信息的最新位置。

    安装工呢?

    Windows 用户知道,大多数时候你都有一个安装程序,你可以运行它在你的计算机上安装你的应用程序,并在这里或那里放一些快捷方式。有几个有用的免费程序,你可以用来创建一个 Windows Installer 以及一些付费的

    以下是我看到提及最多的两个免费软件应用:

  • Inno Setup
  • 我曾多次使用 Inno Setup 创建 Windows installer。它很容易使用,只需要阅读一点文档就可以工作。我以前没有用过 NSIS,但我想它也很容易使用。

    让我们以 Inno Setup 为例,看看如何用它生成一个安装程序。

    使用 Inno Setup 创建安装程序

    Inno Setup 是一个很好的免费软件应用程序,可以用来创建专业外观的安装程序。它可以在大多数版本的 Windows 上运行。我个人用了好几年了。虽然 Inno Setup 不是开源的,但它仍然是一个非常好的程序。你需要从网站下载并安装它。

    安装完成后,您可以使用该工具为您在本章前面创建的可执行文件创建一个安装程序。

    要开始,只需运行 Inno Setup,您应该会看到以下内容:

    Inno 安装程序的启动页面

    虽然 Inno Setup 默认打开一个现有的文件,但你要做的是从顶部选择第二个选项:“使用脚本向导创建一个新的脚本文件”。然后按**确定* *。

    您现在应该会看到 Inno 设置脚本向导的第一页。只需点击**下一个* *这里,因为你没有别的办法。

    现在,您应该会看到类似这样的内容:

    Inno 设置脚本向导应用程序信息页

    您可以在此输入应用程序名称、版本信息、发行商名称和应用程序网站。我预先填写了一些例子,但你可以在这里输入你想输入的任何内容。

    继续按下 下一个 ,您应该会看到第 3 页:

    Inno 设置脚本向导应用程序文件夹页

    在向导的这一页,您可以设置应用程序的安装目录。在 Windows 上,大多数应用程序安装到**程序文件* *,这也是这里的默认设置。这也是您为应用程序设置文件夹名称的地方。这是将出现在程序文件中的文件夹的名称。或者,您可以选中底部的框,表示您的应用程序根本不需要文件夹。

    让我们进入下一页:

    Inno 设置脚本向导应用程序文件页

    这里是您选择主可执行文件的地方。在这种情况下,您希望选择使用 PyInstaller 创建的可执行文件。如果您没有使用 - onefile 标志创建可执行文件,那么您可以使用 添加文件来添加其他文件... 按钮。如果您的应用程序需要任何其他特殊文件,如 SQLite 数据库文件或图像,这也是您想要添加它们的地方。

    默认情况下,当安装程序完成时,此页面将允许用户运行您的应用程序。很多安装程序都这样做,所以实际上这是大多数用户所期望的。

    让我们继续:

    Inno 设置脚本向导应用程序快捷方式页

    这是 应用程序快捷方式 页面,它允许您管理为您的应用程序创建了什么快捷方式以及它们应该去哪里。这些选项非常简单明了。我通常只使用默认值,但是你可以随意更改它们。

    让我们看看文档页面上有什么:

    Inno 设置脚本向导应用程序文档页

    向导的 文档页面 是您添加应用程序许可文件的地方。例如,如果你要发布一个开源应用程序,你可以在那里添加 GPL 或者 MIT 或者任何你需要的许可文件。如果这是一个商业应用程序,您可以在这里添加您的最终用户许可协议(EULA)文件。

    让我们看看接下来会发生什么:

    Inno 设置脚本向导设置语言页

    在这里您可以设置应该包括哪些安装语言。Inno Setup 支持相当多的语言,默认选择是英语。

    现在让我们来看看什么是编译器设置:

    Inno 设置脚本向导编译器设置页面

    通过 编译器设置 页面,您可以命名输出设置文件,默认为 setup 。您可以在这里设置输出文件夹,添加自定义安装文件图标,甚至为安装文件添加密码保护。我通常只保留默认值,但是如果你手边有一个很好的图标文件,这是一个给设置添加一些品牌的机会。

    下一页是为预处理器准备的:

    Inno 设置脚本向导预处理程序页

    预处理器主要用于捕捉 Inno 设置脚本文件中的错别字。它主要是在编译时向 Inno 设置脚本添加一些有用的选项。

    查看 文档 了解全部细节。

    点击 下一步 ,您应该会看到向导的最后一页:

    Inno 设置脚本向导结束页

    点击 完成 ,Inno Setup 将生成一个 Inno Setup 脚本(。iss)文件。完成后,它会问你是否愿意编译这个文件。

    继续并接受该对话框,您应该看到以下内容:

    Inno 安装脚本

    这是 Inno 安装脚本编辑器,其中预加载了您新生成的脚本。上半部分是生成的脚本,下半部分显示编译器的输出。在这个屏幕截图中,它显示安装文件已成功生成,但也显示了一个警告,提示您可能需要重命名安装文件。

    此时,您应该有一个工作的安装程序可执行文件,它会将您的程序和它所依赖的任何文件安装到正确的位置。它还会在 Windows“开始”菜单和您在向导中指定的任何其他位置创建快捷方式。

    脚本文件本身可以编辑。它只是一个文本文件,语法在 Inno Setup 的网站上有很好的记录。

    Windows 和 Mac OSX 更喜欢应用程序由公司或开发者签名。否则你会看到一个警告,提示你正在使用一段未签名的代码或软件。这很重要的原因是它保护你的应用程序不被其他人修改。您可以将代码签名视为应用程序中的一种嵌入式 MD5 哈希。已签名的应用程序可以追溯到签名者,这使得它更值得信任。

    如果你想在 Mac OSX 上签署代码,你可以使用 XCode

    Windows 有几个签名代码的选项。这里有一个 URL,可以让您的应用程序 获得 Windows 的认证

    也可以从各种专门做代码签名的公司购买证书,比如 digicert

    还有自签名证书的概念,但这不是针对生产或最终用户的。您将只为内部测试、概念验证等进行自签名。你可以自己查找如何做到这一点。

    您现在已经学习了如何在 Windows、Mac 和 Linux 上使用 PyInstaller 生成可执行文件。生成可执行文件的命令在所有平台上都是相同的。虽然您不能通过在 Linux 上运行 PyInstaller 来创建 Windows 可执行文件,但它对于为目标操作系统创建可执行文件仍然非常有用。

    您还了解了如何使用 Inno Setup 为 Windows 创建安装程序。现在,您可以使用这些技能为您自己的应用程序或本书中创建的一些其他应用程序创建可执行文件!

    进一步阅读

  • bbfreeze 教程-构建二进制序列!
  • 包装 wxPyMail for Distribution
  • Python 101 -记录您的代码

    原文: https://www.blog.pythonlibrary.org/2021/09/12/documenting-code/

    在早期记录代码比大多数新开发人员意识到的要重要得多。软件开发中的文档是指给你的变量、函数和其他标识符起一个描述性的名字。也指添加好的评论。当你沉浸于开发你的最新作品时,用非描述性的名字创建变量和函数是很容易的。一个月或一年后,当你不可避免地回到你的代码时,你将花费大量的时间试图弄清楚你的代码做什么。

    通过使您的代码自文档化(即,使用描述性名称)并在必要时添加注释,您将使您的代码对于您自己和任何可能使用您代码的人来说更具可读性。这也将使更新代码和重构代码变得更加容易!

    在本章中,您将了解以下主题:

  • 文档字符串
  • pep 8-Python 风格指南
  • 用于记录代码的其他工具
  • 让我们从了解评论开始。

    什么是评论?

    注释是为您编写的代码,不是为您的计算机编写的。我的意思是,注释基本上是给你自己的一个注解,解释在你的代码部分发生了什么。你使用注释来解释你为什么做某事或者一段代码是如何工作的。当你开始作为一个新的开发人员时,最好给自己留下大量的评论以供参考。但是一旦你学会了如何正确命名你的函数和变量,你会发现你不再需要注释了。

    但是仍然建议使用注释,尤其是对于复杂的、乍一看不容易理解的代码。根据你工作的公司,你也可以使用注释来记录错误修复。例如,如果您正在修复一个 bug,您可以在注释中提到您正在修复的 bug,以帮助解释您为什么必须更改它。

    您可以使用 # 符号后跟一些描述性文本来创建注释。

    这里有一个例子:

    # This is a bad comment
    x = 10
    

    在上面的代码中,第一行演示了如何创建一个简单的注释。当 Python 执行这段代码时,它会看到#符号,并忽略它后面的所有文本。实际上,Python 将跳过这一行,尝试执行第二行。

    此评论被标记为“差评”。虽然它有利于演示,但它根本没有描述它后面的代码。这就是为什么它不是一个好的评论。好的注释描述了后面的代码。一个好的注释可以描述 Python 脚本的目的、代码行或其他内容。注释是代码的文档。如果他们不提供信息,那么他们应该被删除。

    您还可以创建内嵌注释:

    x = 10  # 10 is being assigned to x
    

    这里您再次将 10 赋给变量x,但是您添加了两个空格和一个#符号,这允许您添加关于代码的注释。当您可能需要解释特定的代码行时,这很有用。如果你给你的变量起了一个描述性的名字,那么你很可能根本不需要注释。

    你会经常听到“注释掉代码”这个术语。这是将#符号添加到代码开头的做法。这将有效地禁用您的代码。

    例如,您可能有这样一行代码:

    number_of_people = 10
    

    如果您想将其注释掉,可以执行以下操作:

    # number_of_people = 10
    

    当您尝试不同的解决方案或调试代码时,您可以注释掉代码,但您不想删除代码。Python 将忽略被注释掉的代码,允许您尝试其他东西。大多数 Python 代码编辑器(和文本编辑器)提供了一种方法来突出显示多行代码,并注释掉或取消注释掉整个代码块。

    一些编程语言,比如 C++,提供了创建多行注释的能力。Python 风格指南(PEP8)说英镑符号是首选。但是,您可以使用带三重引号的字符串作为多行注释。

    这里有一个例子:

    >>> '''This is a 
    multiline comment'''
    >>> """This is also a 
    multiline comment"""
    

    当您创建三重引号字符串时,您可能会创建一个文档字符串

    让我们看看什么是 docstrings 以及如何使用它们!

    了解文档字符串

    Python 有 PEP 或 Python 增强提案的概念。这些 pep 是 Python 指导委员会讨论并同意的 Python 语言的建议或新特性。

    PEP 257 描述了文档字符串约定。如果你想知道完整的故事,你可以去看看。可以说,docstring 是一个字符串文字,应该作为模块、函数、类或方法定义中的第一条语句出现。你现在不需要理解所有这些术语。事实上,在本书的后面你会学到更多。

    docstring 是使用三重双引号创建的。

    这里有一个例子:

    This is a docstring with multiple lines

    Python 会忽略文档字符串。他们不能被处决。但是,当您使用 docstring 作为模块、函数等的第一条语句时,docstring 将成为一个特殊的属性,可以通过__doc__访问。在关于类的章节中,你会学到更多关于属性和文档字符串的知识。

    文档字符串可以用于单行或多行字符串。

    下面是一个一行程序的示例:

    """This is a one-liner"""
    

    单行 docstring 就是只有一行文本的 docstring。

    以下是函数中使用的文档字符串的示例:

    def my_function():
        """This is the function's docstring"""
    

    上面的代码展示了如何向函数中添加 docstring。你可以在第 14 章学到更多关于函数的知识。一个好的 docstring 描述了函数应该完成什么。

    注意:虽然三个双引号是推荐标准,但是三个单引号、单个双引号和单个单引号都可以(但是单个双引号和单个单引号只能包含一行,不能包含多行)。

    现在让我们根据 Python 的风格指南来学习编码。

    Python 的风格指南:PEP8

    风格指南是描述好的编程实践的文档,通常是关于单一语言的。一些公司有特定的公司风格指南,开发人员无论使用什么编程语言都必须遵循。

    早在 2001 年,Python 风格指南被创建为 PEP8 。它记录了 Python 编程语言的编码约定,这些年来已经更新了几次。

    如果你打算经常使用 Python,你真的应该看看这个指南。它会帮助你写出更好的 Python 代码。

    此外,如果你想为 Python 语言本身做出贡献,你的所有代码必须符合风格指南,否则你的代码将被拒绝。

    遵循风格指南将使你的代码更容易阅读和理解。这将有助于您和将来使用您代码的任何人。

    不过,记住所有的规则可能很难。幸运的是,一些勇敢的开发人员已经创建了一些实用程序来提供帮助!

    有帮助的工具

    有很多优秀的工具可以帮助你写出优秀的代码。以下是几个例子:

  • pycodestyle-https://pypi.org/project/pycodestyle/-检查你的代码是否遵循 PEP8
  • 皮林特-https://www.pylint.org/-一个深入的静态代码测试工具,可以发现代码中的常见问题
  • py flakes-https://pypi.org/project/pyflakes/-Python 的另一个静态代码测试工具
  • flake 8-https://pypi.org/project/flake8/-一个包裹着 PyFlakes、pycodestyle 和 McCabe 脚本的包装
  • 布莱克-https://black.readthedocs.io/en/stable/-一个主要遵循 PEP8 的代码格式化程序
  • 您可以针对您的代码运行这些工具,以帮助您找到代码中的问题。我发现 Pylint 和 PyFlakes / flake8 是最有用的。如果您在团队中工作,并且希望每个人的代码都遵循相同的格式,黑色会很有帮助。可以将 Black 添加到您的工具链中,为您格式化代码。

    更高级的 Python IDEs 提供了 Pylint 等的一些检查。实时提供。例如,PyCharm 会自动检查这些工具会发现的许多问题。WingIDE 和 VS 代码也提供了一些静态代码检查。您应该查看各种 ide,看看哪一个最适合您。

    Python 提供了几种不同的方法来记录代码。你可以使用注释来解释一行或多行代码。这些应该在适当的时候适度使用。您还可以使用 docstrings 来记录您的模块、函数、方法和类。

    您还应该查看一下 PEP8 中的 Python 风格指南。这将帮助您开发良好的 Python 编码实践。Python 还有其他几个风格指南。例如,你可能想要查找 Google 的风格指南或者 NumPy 的 Python 风格指南。有时看看不同的风格指南也会帮助你发展良好的实践。

    最后,您了解了几个可以用来帮助您改进代码的工具。如果你有时间,我鼓励你去看看 PyFlakes 或 Flake8,特别是因为它们在指出你的代码中常见的编码问题时非常有帮助。

    想了解更多关于 Python 的功能吗?查看这些教程:

    matplotlib–用 Python 创建图表的介绍

    Python 101: 使用 JSON 的介绍

    Python 101 - 创建多个流程

    python 101-用 pdb 调试你的代码

    Python 101—使用 Python 启动子流程

    用 wxPython 做淡入

    原文:https://www.blog.pythonlibrary.org/2008/04/14/doing-a-fade-in-with-wxpython/

    今天我们将讨论如何让你的应用程序做一个“淡入”。Windows 用户通常会在 Microsoft Outlook 的电子邮件通知中看到这一点。它淡入淡出。wxPython 提供了一种设置任何顶层窗口的 alpha 透明度的方法,这会影响放置在顶层小部件上的小部件。

    在这个例子中,我将使用一个框架对象作为顶层对象,并使用一个计时器来改变 alpha 透明度,单位为每秒 5。计时器的事件处理程序将使帧淡入视图,然后再次退出。值的范围是 0 - 255,0 表示完全透明,255 表示完全不透明。

    代码如下:

    import wx class Fader(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title='Test') self.amount = 5 self.delta = 5 panel = wx.Panel(self, wx.ID_ANY) self.SetTransparent(self.amount) ## ------- Fader Timer -------- ## self.timer = wx.Timer(self, wx.ID_ANY) self.timer.Start(60) self.Bind(wx.EVT_TIMER, self.AlphaCycle) ## ---------------------------- ## def AlphaCycle(self, evt): self.amount += self.delta if self.amount >= 255: self.delta = -self.delta self.amount = 255 if self.amount <= 0: self.amount = 0 self.SetTransparent(self.amount) if __name__ == '__main__': app = wx.App(False) frm = Fader() frm.Show() app.MainLoop()

    如您所见,要更改顶级小部件的透明度,您只需调用该小部件的 SetTransparent()方法,并向其传递要设置的数量。实际上,我在自己的一个应用程序中使用了这种方法,它会在一个对话框中淡入提醒我 Zimbra 电子邮件帐户中有新邮件。

    欲了解更多信息,请查看以下资源:

    对以下代码进行了测试:

    操作系统:Windows XP
    Python:2 . 5 . 2
    wxPython:2.8.8.1 和 2.8.9.1

    用 Python 下载加密和压缩文件

    原文:https://www.blog.pythonlibrary.org/2010/10/20/downloading-encrypted-and-compressed-files-with-python/

    今年早些时候,我负责创建一个应用程序,使用 Python 从我们组织的网站下载信息。棘手的部分是,它将被加密、压缩,有效载荷将是 JSON。Python 能做到这一切吗?这正是我想知道的。现在是时候让你知道我的发现了。

    Python 和加密

    当务之急是找出加密的东西。有效载荷应该是 AES 加密的。虽然 Python 似乎没有为这类事情内置的模块,但有一个用于 Python 2.x 的优秀的 PyCrypto 包,运行得很好。不幸的是,他们的主网站没有列出如何在 Windows 上安装它。你需要自己做一些编译工作(我想是用 Visual Studio),或者你可以在这里下载迈克尔·福德的版本。我选择了后者。

    以下是我最终使用的基本代码:

    from Crypto.Cipher import AES cipher = AES.new(key, AES.MODE_ECB) gzipData = cipher.decrypt(encData).strip('\000')

    encData 变量就是使用 urllib2 下载的文件。我们很快就会看到如何做到这一点。耐心点。密钥是由我的一个开发伙伴提供的。无论如何,一旦你解密了它,你就得到 gzipped 数据了。

    解压缩 Gzipped 文件

    关于 gzipped 的文档相当混乱。你用 gzip 还是 zlib?我花了不少时间反复试验才弄明白,主要是因为我的同事给了我错误的文件格式。这一部分实际上也非常容易完成:

    import zlib jsonTxt = zlib.decompress(gzipData)

    如果你这样做了,你将得到解压缩的数据。是的,就是这么简单。

    JSON 和 Python

    从 Python 2.6 开始,Python 中提供了一个 json 模块。你可以在这里阅读。如果你坚持使用旧版本,那么你可以从 PyPI 下载这个模块。或者你可以使用 simplejson 包,我用的就是这个包。

    import simplejson json = simplejson.loads(jsonTxt )

    现在,您将拥有一个嵌套字典列表。基本上,你会想做这样的事情来使用它:

    data = json['keyName']

    这将返回另一个包含不同数据的字典。您需要稍微研究一下数据结构,以找出访问所需内容的最佳方式。

    把所有的放在一起

    现在,让我们将它们放在一起,并向您展示完整的脚本:

    import simplejson import urllib2 import zlib from Crypto.Cipher import AES from platform import node from win32api import GetUserName version = "1.0.4" uid = GetUserName().upper() machine = node() #---------------------------------------------------------------------- def getData(url, key): Downloads and decrypts gzipped data and returns a JSON string headers = {"X-ActiveCalls-Version":version, "X-ActiveCalls-User-Windows-user-ID":uid, "X-ActiveCalls-Client-Machine-Name":machine} request = urllib2.Request(url, headers=headers) f = urllib2.urlopen(request) encData = f.read() cipher = AES.new(key, AES.MODE_ECB) gzipData = cipher.decrypt(encData).strip('\000') jsonTxt = zlib.decompress(gzipData) return jsonTxt except: msg = "Error: Program unable to contact update server. Please check configuration URL" print msg if __name__ == "__main__": json = getData("some url", "some AES key")

    在这个特定的例子中,我还需要让服务器知道哪个版本的应用程序正在请求数据,用户是谁,以及请求来自哪台机器。为此,我们使用 urllib2 的 Request 方法向服务器传递一个包含该信息的特殊头。代码的其余部分应该是不言自明的

    我希望这些都有意义,并且对您的 Python 冒险有所帮助。如果没有,请查看我在各个部分提供的链接,并做一点研究。玩得开心!

    用枕头和 Python 绘制圆角矩形

    原文:https://www.blog.pythonlibrary.org/2021/05/12/drawing-rectangles-with-rounded-corners-with-pillow-and-python/

    Pillow 是一个致力于用 Python 处理图像的包。从 Pillow 8.2 开始,有了一种新的绘图类型:圆角矩形。圆角矩形允许您对矩形的角进行圆角处理。所以你得到的不是尖角,而是圆角!您可以在枕头文档中阅读所有关于新绘图类型的信息。

    确保你有最新版本的枕头。如果你的 Pillow 版本早于 8.2,那么你将不能使用这种新的绘图类型。

    以下是升级枕头的方法:

    python3 -m pip install pillow --upgrade
    

    现在您已经安装或升级了 Pillow,您可以使用新的绘图类型。

    绘制圆角矩形

    你现在可以画一个圆角矩形了。在您喜欢的 Python IDE 中打开一个新文件,并添加以下代码:

    # draw_rounded_rectangle.py
    from PIL import Image, ImageDraw
    def rectangle(output_path):
        image = Image.new("RGB", (400, 400), "green")
        draw = ImageDraw.Draw(image)
        # Draw a regular rectangle
        draw.rectangle((200, 100, 300, 200), fill="red")
        # Draw a rounded rectangle
        draw.rounded_rectangle((50, 50, 150, 150), fill="blue", outline="yellow",
                               width=3, radius=7)
        image.save(output_path)
    if __name__ == "__main__":
        rectangle("rounded_rectangle.jpg")
    

    rounded_rectangle() 函数接受一个由四个整数组成的元组。这些整数定义了边界框的两点。半径定义了拐角的圆角程度。你可以用一种颜色填充矩形。您也可以使用轮廓参数添加边框。宽度是边框的像素宽度。

    当您运行此代码时,它将创建一个包含一个常规矩形和一个圆角矩形的图像,如下所示:

    左边的蓝色矩形显示了圆角矩形的样子。如果将半径设置为零,那么拐角根本不会被倒圆。半径值越大,弯道上的曲线越大。

    虽然这种新的绘图类型并不令人惊讶,但它是添加到您的绘图工具包中的一个很好的新工具。如果你坚持使用 8.2 之前的 Pillow 版本,有一些替代的方法可以在 StackOverflow 上创建圆角矩形。玩得开心!

    用 Python 和 Pillow 在图像上绘制形状

    原文:https://www.blog.pythonlibrary.org/2021/02/23/drawing-shapes-on-images-with-python-and-pillow/

    Pillow 提供了一个名为ImageDraw的绘图模块,你可以用它在你的Image对象上创建简单的 2D 图形。根据 Pillow 的文档,“你可以使用这个模块来创建新的图像,注释或修饰现有的图像,并动态生成图形供网络使用。”

    如果你需要比 Pillow 更高级的绘图功能,你可以得到一个名为 aggdraw 的单独包。

    在本文中,您将重点关注枕头附带的内容。具体来说,您将了解以下内容:

  • 绘制饼图切片
  • 绘制多边形
  • 当使用 Pillow 绘图时,它使用与 Pillow 其他部分相同的坐标系。比如左上角还是(0,0)。如果您在图像边界之外绘制,这些像素将被丢弃。

    如果您想指定一种颜色,您可以像使用PIL.Image.new()一样使用一系列数字或元组。对于“1”、“L”和“I”图像,使用整数。对于“RGB”图像,使用包含整数值的三元组。您也可以使用在第 2 章中了解到的 Pillow 支持的颜色名称。

    当你去使用各种绘图方法时,你会发现它们有许多共同的参数。您将提前了解这些参数,而不是在每一节中解释相同的参数!

    正常男性染色体组型

    大多数绘图方法都有一个xy参数,用于设置要在其中绘制图形的矩形区域。这可以通过以下两种方式来定义:

  • ((左上 x,左上 y),(右下 x,右下 y))或者干脆((x1,y1),(x2,y2))
  • (x1,y1,x2,y2)的盒元组
  • 在绘制直线、多边形或点时,可以通过以下任一方式指定多个坐标:

  • (x1, y1, x2, y2, x3, y3...)
  • ((x1, y1), (x2, y2), (x3, y3)...)
  • line()方法将画一条直线,连接每个点。polygon()将在每个点连接的地方画一个多边形。最后,point()会在每个点上画一个 1 像素的点。

    参数fill用于设置填充形状的颜色。设置fill的方式由图像模式决定:

  • RGB:使用(R,G,B)或颜色名称设置每个颜色值(0-255)
  • L(灰度):设置一个整数值(0-255)
  • 默认为None或不填充。

    outline设置绘图的边框颜色。其规格与您用于fill的规格相同。

    默认为None,表示无边框。

    现在你已经知道了常用的参数,你可以继续学习如何开始绘画了!

    你将学习的第一种绘画是如何在枕头上画线。所有的形状都是由线条组成的。在 Pillow 的例子中,通过告诉 Pillow 在开始和结束坐标之间画线来画线。或者,您可以传入一系列 XY 坐标,Pillow 将绘制连线来连接这些点。

    下面是line()方法定义:

    def line(self, xy, fill=None, width=0, joint=None):
        """Draw a line, or a connected sequence of line segments."""
    

    您可以看到它接受几个不同的参数。在上一节中,您已经了解了其中一些参数的含义。width参数用于控制线条的宽度。

    在你学会如何使用joint之前,你应该学会如何不用它画线。但是首先,你需要一张图片来画画。你将使用这张麦迪逊县大桥的图片:

    麦迪逊县廊桥

    现在打开您的 Python 编辑器,创建一个名为draw_line.py的新文件,并向其中添加以下代码:

    # draw_line.py
    import random
    from PIL import Image, ImageDraw
    def line(image_path, output_path):
        image = Image.open(image_path)
        draw = ImageDraw.Draw(image)
        colors = ["red", "green", "blue", "yellow",
                  "purple", "orange"]
        for i in range(0, 100, 20):
            draw.line((i, 0) + image.size, width=5, 
                      fill=random.choice(colors))
        image.save(output_path)
    if __name__ == "__main__":
        line("madison_county_bridge_2.jpg", "lines.jpg")
    

    这里你打开 Pillow 中的图像,然后将Image对象传递给ImageDraw.Draw(),后者返回一个ImageDraw对象。现在你可以在你的图像上画线了。在这种情况下,您使用一个for循环在图像上绘制五条线。在第一个循环中,起始图像从(0,0)开始。然后 X 位置在每次迭代中改变。端点是图像的大小。

    您可以使用random模块从颜色列表中选择一种随机颜色。当您运行这段代码时,输出如下所示:

    画在图像上的线条

    现在你可以尝试创建一系列的点,并以这种方式画线。创建一个名为draw_jointed_line.py的新文件,并将以下代码放入您的文件中:

    # draw_jointed_line.py
    from PIL import Image, ImageDraw
    def line(output_path):
        image = Image.new("RGB", (400, 400), "red")
        points = [(100, 100), (150, 200), (200, 50), (400, 400)]
        draw = ImageDraw.Draw(image)
        draw.line(points, width=15, fill="green", joint="curve")
        image.save(output_path)
    if __name__ == "__main__":
        line("jointed_lines.jpg")
    

    这一次,你使用枕头而不是在你自己的枕头上画画来创建一个图像。然后创建一个点列表。为了使线条连接看起来更好,您可以将joint参数设置为“曲线”。如果你看一下line()方法的源代码,你会发现除了None之外,“曲线”是赋予它的唯一有效值。这可能会在枕头的未来版本中改变。

    当您运行这段代码时,您的图像将如下所示:

    绘制接合线

    现在试着从代码中删除joint参数,并重新运行这个例子。您的输出将如下所示:

    没有接头的线条

    joint设置为“曲线”,输出会稍微顺眼一些。

    现在你已经准备好学习用枕头画弧线了!

    弧是一条曲线。你也可以用枕头画弧线。下面是arc()方法规范:

    def arc(self, xy, start, end, fill=None, width=1):
        """Draw an arc."""
    

    也可以使用xy点生成一个arc()start参数定义了起始角度,单位为度。end参数告诉 Pillow 结束角度是多少,也是以度为单位。另外两个参数已经介绍过了。

    要查看如何绘制弧线,请创建一个名为draw_arc.py的新文件,并将以下代码添加到其中:

    # draw_arc.py
    from PIL import Image, ImageDraw
    def arc(output_path):
        image = Image.new("RGB", (400, 400), "white")
        draw = ImageDraw.Draw(image)
        draw.arc((25, 50, 175, 200), start=30, end=250, fill="green")
        draw.arc((100, 150, 275, 300), start=20, end=100, width=5, 
                 fill="yellow")
        image.save(output_path)
    if __name__ == "__main__":
        arc("arc.jpg")
    

    在这段代码中,您创建了一个白色背景的新图像。然后你创建你的Draw对象。接下来,创建两条不同的弧。第一条弧线将填充绿色。第二条弧线将被填充为黄色,但其线宽将为 5。绘制弧线时,填充是指弧线的线条颜色。你没有填充弧线本身。

    当您运行此代码时,您的输出图像将如下所示:

    尝试更改一些参数并重新运行代码,看看如何自己更改弧线。

    现在让我们继续学习如何画和弦!

    枕头还支持和弦的概念。弦与弧相同,只是端点用直线连接。

    下面是chord()的方法定义:

    def chord(self, xy, start, end, fill=None, outline=None, width=1):
        """Draw a chord."""
    

    这里唯一的区别是你还可以添加一个outline颜色。可以用指定fill颜色的任何方式来指定该颜色。

    创建一个新文件,命名为draw_chord.py。然后添加以下代码,这样您就可以看到自己是如何制作和弦的了:

    # draw_chard.py
    from PIL import Image, ImageDraw
    def chord(output_path):
        image = Image.new("RGB", (400, 400), "green")
        draw = ImageDraw.Draw(image)
        draw.chord((25, 50, 175, 200), start=30, end=250, fill="red")
        draw.chord((100, 150, 275, 300), start=20, end=100, width=5, fill="yellow",
                    outline="blue")
        image.save(output_path)
    if __name__ == "__main__":
        chord("chord.jpg")
    

    此示例将在绿色图像上绘制两条弦。第一个和弦用红色填充。第二个和弦用黄色填充,但轮廓是蓝色的。蓝色轮廓的宽度为 5。

    运行此代码时,您将创建以下图像:

    看起来不错。继续玩这个例子。稍加练习,你很快就会掌握用枕头制作和弦。

    现在让我们继续学习画椭圆!

    通过给 Pillow 一个边界框(xy ),在 Pillow 中绘制一个椭圆。在前面的章节中,您已经多次看到过这种情况。

    下面是ellipse()方法的定义:

    def ellipse(self, xy, fill=None, outline=None, width=1):
        """Draw an ellipse."""
    

    ellipse()让你用一种颜色填充它,添加一个彩色边框(outline)并改变那个outlinewidth

    要了解如何创建ellipse(),创建一个名为draw_ellipse.py的新文件,并将该代码添加到其中:

    # draw_ellipse.py
    from PIL import Image, ImageDraw
    def ellipse(output_path):
        image = Image.new("RGB", (400, 400), "white")
        draw = ImageDraw.Draw(image)
        draw.ellipse((25, 50, 175, 200), fill="red")
        draw.ellipse((100, 150, 275, 300), outline="black", width=5,
                     fill="yellow")
        image.save(output_path)
    if __name__ == "__main__":
        ellipse("ellipse.jpg")
    

    在这段代码中,您通过new()方法创建了一个漂亮的白色图像。然后你在它上面画一个红色的椭圆。最后,绘制第二个椭圆,用黄色填充并用黑色勾勒,轮廓宽度设置为 5。

    当您运行此代码时,它创建的图像将如下所示:

    您可以使用ellipse()创建椭圆形和圆形。试一试,看看你能用它做什么。

    现在让我们来看看如何创建饼图切片!

    绘制饼图切片

    饼图切片与arc())相同,但也在边界框的端点和中心之间绘制直线。

    下面是如何定义pieslice()方法的:

    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):
        """Draw a pieslice."""
    

    您已经在其他图形中使用了所有这些参数。回顾一下,fillpieslice()的内部添加颜色,而outline给图形添加彩色边框。

    要开始练习这个形状,创建一个名为draw_pieslice.py的新文件,并将以下代码添加到您的文件中:

    # draw_pieslice.py
    from PIL import Image, ImageDraw
    def pieslice(output_path):
        image = Image.new("RGB", (400, 400), "grey")
        draw = ImageDraw.Draw(image)
        draw.pieslice((25, 50, 175, 200), start=30, end=250, fill="green")
        draw.pieslice((100, 150, 275, 300), start=20, end=100, width=5, 
                      outline="yellow")
        image.save(output_path)
    if __name__ == "__main__":
        pieslice("pieslice.jpg")
    

    在这段代码中,您生成了一个灰色的图像来绘制。然后创建两个饼图切片。第一个pieslice()用绿色填充。第二个没填,但是确实有黄色的outline。注意,每个pieslice()都有不同的开始和结束程度。

    当您运行此代码时,您将获得以下图像:

    绘制饼图切片

    只需做一点工作,您就可以使用 Pillow 创建一个饼图!您应该稍微修改一下代码,并更改一些值。你将很快学会如何自己制作一些美味的馅饼。

    现在让我们来看看如何用枕头画多边形!

    绘制多边形

    多边形是一种几何形状,它有许多点(顶点)和相等数量的线段或边。正方形、三角形和六边形都是多边形。枕头可以让你创建自己的多边形。Pillow 的文档是这样定义多边形的:多边形轮廓由给定坐标之间的直线,加上最后一个和第一个坐标之间的直线组成。

    下面是polygon()方法的代码定义:

    def polygon(self, xy, fill=None, outline=None):
        """Draw a polygon."""
    

    现在,您应该对所有这些参数都很熟悉了。继续创建一个新的 Python 文件,并将其命名为draw_polygon.py。然后添加以下代码:

    # draw_polygon.py
    from PIL import Image, ImageDraw
    def polygon(output_path):
        image = Image.new("RGB", (400, 400), "grey")
        draw = ImageDraw.Draw(image)
        draw.polygon(((100, 100), (200, 50), (125, 25)), fill="green")
        draw.polygon(((175, 100), (225, 50), (200, 25)),
                      outline="yellow")
        image.save(output_path)
    if __name__ == "__main__":
        polygon("polygons.jpg")
    

    这段代码将创建一个类似于上一节中最后一个例子的灰色图像。然后它将创建一个多边形,用绿色填充。然后它将创建第二个多边形,用黄色勾勒出它的轮廓,不填充它。

    在这两幅图中,您提供了三个点。这将创建两个三角形。

    当您运行这段代码时,您将得到以下输出:

    绘制多边形

    尝试通过向上述代码中的一个或多个多边形添加额外的点来更改代码。只要稍加练习,你就能使用 Pillow 快速创建复杂的多边形。

    rectangle()方法允许你用枕头画一个矩形或正方形。下面是rectangle()的定义:

    def rectangle(self, xy, fill=None, outline=None, width=1):
        """Draw a rectangle."""
    

    您可以传入定义开始和结束坐标的两个元组来绘制矩形。或者,您可以将四个坐标作为一个盒元组(4 项元组)来提供。然后你可以添加一个outlinefill给它加上颜色,并改变轮廓的width

    创建一个新文件,命名为draw_rectangle.py。然后用下面的代码填充它,这样你就可以开始画矩形了:

    # draw_rectangle.py
    from PIL import Image, ImageDraw
    def rectangle(output_path):
        image = Image.new("RGB", (400, 400), "blue")
        draw = ImageDraw.Draw(image)
        draw.rectangle((200, 100, 300, 200), fill="red")
        draw.rectangle((50, 50, 150, 150), fill="green", outline="yellow",
                       width=3)
        image.save(output_path)
    if __name__ == "__main__":
        rectangle("rectangle.jpg")
    

    这段代码将创建一个 400x400 像素的蓝色图像。然后它会画两个矩形。第一个矩形将用红色填充。第二个将用绿色填充,用黄色勾勒。

    当您运行此代码时,您将得到以下图像作为输出:

    那些可爱的长方形不是吗?您可以修改矩形的点来创建更薄或更宽的矩形。您还可以修改添加到矩形的轮廓宽度。

    您可以使用 Pillow 为图像添加形状。这有助于为图像添加轮廓,突出显示图像的一个或多个部分,等等。

    在本文中,您了解了以下主题:

  • 绘制饼图切片
  • 绘制多边形
  • 您可以利用 Pillow 提供的形状做很多事情。你应该拿这些例子,并修改它们,用你自己的照片来测试它们。试一试,看看你能想出什么!

  • 用 Python 和 Pillow 在图像上绘制文本
  • PySimpleGUI: 用 Python GUI 在图像上绘制文本
  • Pillow: image processing with Python

    now on Lean Pub t3 |

    使用 Pillow 和 Python 在图像上绘制文本

    原文:https://www.blog.pythonlibrary.org/2021/02/02/drawing-text-on-images-with-pillow-and-python/

    除了形状之外,Pillow 还支持在图像上绘制文本。Pillow 使用自己的字体文件格式存储位图字体,限制为 256 个字符。Pillow 还支持 TrueType 和 OpenType 字体,以及 FreeType 库支持的其他字体格式。

    在本章中,您将了解以下内容:

  • 加载 TrueType 字体
  • 更改文本颜色
  • 绘制多行文本
  • 更改文本不透明度
  • 了解文本锚点
  • 虽然这篇文章并没有完全覆盖使用 Pillow 绘制文本,但是当您阅读完这篇文章后,您将会对文本绘制的工作原理有一个很好的理解,并且能够自己绘制文本。

    让我们从学习如何绘制文本开始。

    用枕头绘制文本类似于绘制形状。然而,绘制文本增加了复杂性,需要能够处理字体、间距、对齐等。您可以通过查看text()函数的签名来了解绘制文本的复杂性:

    def text(xy, text, fill=None, font=None, anchor=None, spacing=4, align='left', direction=None, 
    	     features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)
    

    这个函数接受的参数比你用 Pillow 绘制的任何形状都多!让我们依次检查一下这些参数:

  • xy -文本的锚点坐标(即开始绘制文本的位置)。
  • text -您希望绘制的文本字符串。
  • fill -文本的颜色(可以是一个元组,一个整数(0-255)或一个支持的颜色名称)。
  • font -一个ImageFont实例。
  • anchor -文本锚点对齐。确定锚点相对于文本的位置。默认对齐方式是左上方。
  • spacing -如果文本被传递到multiline_text(),这将控制行间的像素数。
  • align -如果文本被传递到multiline_text()"left""center""right"。确定线条的相对对齐方式。使用锚定参数指定与xy的对齐。
  • direction -文字的方向。可以是"rtl"(从右到左)"ltr"(从左到右)或"ttb"(从上到下)。需要 libraqm。
  • features -文本布局期间使用的 OpenType 字体特性列表。需要 libraqm。
  • language -文本的语言。不同的语言可能使用不同的字形或连字。此参数告诉字体文本使用哪种语言,并根据需要应用正确的替换(如果可用)。这应该是 BCP 47 语言代码。需要 libraqm。
  • stroke_width -文本笔画的宽度
  • stroke_fill -文字笔画的颜色。如果没有设置,它默认为fill参数的值。
  • embedded_color -是否使用字体嵌入颜色字形(COLR 或 CBDT)。
  • 除非您的工作需要使用外语或晦涩难懂的字体功能,否则您可能不会经常使用这些参数。

    当谈到学习新事物时,从一个好的例子开始总是好的。打开 Python 编辑器,创建一个名为draw_text.py的新文件。然后向其中添加以下代码:

    # draw_text.py
    from PIL import Image, ImageDraw, ImageFont
    def text(output_path):
        image = Image.new("RGB", (200, 200), "green")
        draw = ImageDraw.Draw(image)
        draw.text((10, 10), "Hello from")
        draw.text((10, 25), "Pillow",)
        image.save(output_path)
    if __name__ == "__main__":
        text("text.jpg")
    

    这里你使用 Pillow 的Image.new()方法创建一个小图像。它有一个漂亮的绿色背景。然后创建一个绘图对象。接下来,您告诉 Pillow 在哪里绘制文本。在这种情况下,您绘制两行文本。

    当您运行此代码时,您将获得以下图像:

    看起来不错。通常,当您在图像上绘制文本时,您会指定一种字体。如果手头没有字体,可以使用上面的方法,也可以使用 Pillow 的默认字体。

    下面的示例更新了上一个示例,使用 Pillow 的默认字体:

    # draw_text_default_font.py
    from PIL import Image, ImageDraw, ImageFont
    def text(output_path):
        image = Image.new("RGB", (200, 200), "green")
        draw = ImageDraw.Draw(image)
        font = ImageFont.load_default()
        draw.text((10, 10), "Hello from", font=font)
        draw.text((10, 25), "Pillow", font=font)
        image.save(output_path)
    if __name__ == "__main__":
        text("text.jpg")
    

    在这个版本的代码中,您使用ImageFont.load_default()来加载 Pillow 的默认字体。然后将字体应用于文本,用font参数传递它。

    这段代码的输出将与第一个示例相同。

    现在让我们来看看如何使用枕头 TrueType 字体!

    加载 TrueType 字体

    Pillow 支持加载 TrueType 和 OpenType 字体。因此,如果你有一个最喜欢的字体或公司规定的字体,Pillow 可能会加载它。您可以下载许多开源 TrueType 字体。一个流行的选择是 Gidole ,你可以在这里得到:

  • https://github.com/larsenwork/Gidole
  • Pillow 包的测试文件夹中也有几种字体。你可以在这里下载 Pillow 的源代码:

  • https://github.com/python-pillow/Pillow
  • 本书在 Github 上的代码库包括 Gidole 字体以及 Pillow tests 文件夹中的一些字体,您可以在本章的示例中使用这些字体:

  • https://github.com/driscollis/image_processing_with_python
  • 要查看如何加载 TrueType 字体,创建一个新文件并命名为draw_truetype.py。然后输入以下内容:

    # draw_truetype.py
    from PIL import Image, ImageDraw, ImageFont
    def text(input_image_path, output_path):
        image = Image.open(input_image_path)
        draw = ImageDraw.Draw(image)
        y = 10
        for font_size in range(12, 75, 10):
            font = ImageFont.truetype("Gidole-Regular.ttf", size=font_size)
            draw.text((10, y), f"Chihuly Exhibit ({font_size=}", font=font)
            y += 35
        image.save(output_path)
    if __name__ == "__main__":
        text("chihuly_exhibit.jpg", "truetype.jpg")
    

    对于这个例子,您使用 Gidole 字体并加载一张在德克萨斯州达拉斯植物园拍摄的图像:

    然后循环几种不同的字体大小,在图像的不同位置写出一个字符串。当您运行这段代码时,您将创建一个如下所示的图像:

    这段代码演示了如何使用 TrueType 字体改变字体大小。现在,您已经准备好学习如何在不同的 TrueType 字体之间切换。

    创建另一个新文件,并将其命名为draw_multiple_truetype.py。然后把这段代码放进去:

    # draw_multiple_truetype.py
    import glob
    from PIL import Image, ImageDraw, ImageFont
    def truetype(input_image_path, output_path):
        image = Image.open(input_image_path)
        draw = ImageDraw.Draw(image)
        y = 10
        ttf_files = glob.glob("*.ttf")
        for ttf_file in ttf_files:
            font = ImageFont.truetype(ttf_file, size=44)
            draw.text((10, y), f"{ttf_file} (font_size=44)", font=font)
            y += 55
        image.save(output_path)
    if __name__ == "__main__":
        truetype("chihuly_exhibit.jpg", "truetype_fonts.jpg")
    

    这里您使用 Python 的glob模块来搜索扩展名为.ttf的文件。然后你遍历这些文件,用glob找到的每种字体写出图片上的字体名称。

    当您运行这段代码时,您的新图像将如下所示:

    这演示了在一个代码示例中编写多种格式的文本。您始终需要提供要加载的 TrueType 或 OpenType 字体文件的相对或绝对路径。如果您不提供有效的路径,将会引发一个FileNotFoundError异常。

    现在让我们继续学习如何改变你的文本颜色!

    更改文本颜色

    Pillow 允许您通过使用fill参数来改变文本的颜色。您可以使用 RGB 元组、整数或支持的颜色名称来设置此颜色。

    继续创建一个新文件,命名为text_colors.py。然后在其中输入以下代码:

    # text_colors.py
    from PIL import Image, ImageDraw, ImageFont
    def text_color(output_path):
        image = Image.new("RGB", (200, 200), "white")
        draw = ImageDraw.Draw(image)
        colors = ["green", "blue", "red", "yellow", "purple"]
        font = ImageFont.truetype("Gidole-Regular.ttf", size=12)
        y = 10
        for color in colors:
            draw.text((10, y), f"Hello from Pillow", font=font, fill=color)
            y += 35
        image.save(output_path)
    if __name__ == "__main__":
        text_color("colored_text.jpg")
    

    在本例中,您创建了一个新的白色图像。然后创建一个颜色列表。接下来,循环列表中的每种颜色,并使用fill参数应用颜色。

    当您运行这段代码时,您将得到这个漂亮的输出:

    这个输出演示了如何改变文本的颜色。

    现在让我们学习如何一次绘制多行文本!

    绘制多行文本

    Pillow 还支持一次绘制多行文本。在本节中,您将学习绘制多条线的两种不同方法。第一种是通过使用 Python 的换行符:\n

    要了解其工作原理,创建一个文件并将其命名为draw_multiline_text.py。然后添加以下代码:

    # draw_multiline_text.py
    from PIL import Image, ImageDraw, ImageFont
    def text(input_image_path, output_path):
        image = Image.open(input_image_path)
        draw = ImageDraw.Draw(image)
        font = ImageFont.truetype("Gidole-Regular.ttf", size=42)
        text = "Chihuly Exhibit\nDallas, Texas"
        draw.text((10, 25), text, font=font)
        image.save(output_path)
    if __name__ == "__main__":
        text("chihuly_exhibit.jpg", "multiline_text.jpg")
    

    对于本例,您创建一个中间插入换行符的字符串。当您运行此示例时,您的结果应该如下所示:

    Pillow 也有一个用于绘制多行文本的内置方法。把你在上例中写的代码复制并粘贴到一个新文件中。保存新文件,并将其命名为draw_multiline_text_2.py

    现在修改代码,使其使用multiline_text()函数:

    # draw_multiline_text_2.py
    from PIL import Image, ImageDraw, ImageFont
    def text(input_image_path, output_path):
        image = Image.open(input_image_path)
        draw = ImageDraw.Draw(image)
        font = ImageFont.truetype("Gidole-Regular.ttf", size=42)
        text = """
        Chihuly Exhibit
        Dallas, Texas"""
        draw.multiline_text((10, 25), text, font=font)
        image.save(output_path)
    if __name__ == "__main__":
        text("chihuly_exhibit.jpg", "multiline_text_2.jpg")
    

    在本例中,您使用 Python 的三重引号创建了一个多行字符串。然后通过调用multiline_text()将该字符串绘制到图像上。

    当您运行这段代码时,您的图像会略有不同:

    文本位于上一示例的右下方。原因是您使用了 Python 的三重引号来创建字符串。它保留了您给它的换行符和缩进。如果你把这个字符串放到前面的例子中,它看起来应该是一样的。

    multiline_text()并不影响最终结果。

    现在,让我们学习如何在绘制文本时对齐文本。

    枕头让你对齐文本。但是,对齐是相对于锚点的,并且仅适用于多行文字。在本节中,您将看到一种不使用align参数来对齐文本的替代方法。

    要开始使用align,创建一个新文件并将其命名为text_alignment.py。然后添加以下代码:

    # text_alignment.py
    from PIL import Image, ImageDraw, ImageFont
    def alignment(output_path):
        image = Image.new("RGB", (200, 200), "white")
        draw = ImageDraw.Draw(image)
        alignments = ["left", "center", "right"]
        y = 10
        font = ImageFont.truetype("Gidole-Regular.ttf", size=12)
        for alignment in alignments:
            draw.text((10, y), f"Hello from\n Pillow", font=font,
                    align=alignment, fill="black")
            y += 35
        image.save(output_path)
    if __name__ == "__main__":
        alignment("aligned_text.jpg")
    

    这里你创建了一个小的,白色的图像。然后创建所有有效对齐选项的列表:“左”、“居中”和“右”。接下来,循环遍历这些对齐值,并将它们应用于同一个多行字符串。

    运行此代码后,您将得到以下结果:

    通过查看输出,您可以对 Pillow 中的对齐方式有所了解。这是否适合您的用例取决于您自己。除了设置参数align之外,您可能还需要调整开始绘图的位置,以获得您真正想要的结果。

    你可以用 Pillow 来得到你的绳子的尺寸,然后做一些简单的数学运算来试着把它放在中间。为此,您可以使用绘图对象的textsize()方法或字体对象的getsize()方法。

    要了解其工作原理,您可以创建一个名为center_text.py的新文件,并将以下代码放入其中:

    # center_text.py
    from PIL import Image, ImageDraw, ImageFont
    def center(output_path):
        width, height = (400, 400)
        image = Image.new("RGB", (width, height), "grey")
        draw = ImageDraw.Draw(image)
        font = ImageFont.truetype("Gidole-Regular.ttf", size=12)
        text = "Pillow Rocks!"
        font_width, font_height = font.getsize(text)
        new_width = (width - font_width) / 2
        new_height = (height - font_height) / 2
        draw.text((new_width, new_height), text, fill="black")
        image.save(output_path)
    if __name__ == "__main__":
        center("centered_text.jpg")
    

    在这种情况下,您跟踪图像的大小以及字符串的大小。对于这个例子,您使用了getsize()来获得基于字体和字体大小的字符串的宽度和高度。

    然后你把图像的宽度和高度减去字符串的宽度和高度,再除以 2。这将为您提供在图像中心书写文本所需的坐标。

    当您运行这段代码时,您可以看到文本很好地居中:

    然而,当你增加字体大小时,这个值开始下降。你增加得越多,它就离中心越远。在 StackOverflow 上有几个备选解决方案:

  • https://stack overflow . com/questions/1970 807/center-middle-align-text-with-pil
  • 主要的收获是,你可能最终需要为你正在使用的字体计算你自己的偏移量。毕竟排版是一件复杂的事情。

    现在让我们来看看如何改变你的文字的不透明度!

    更改文本不透明度

    Pillow 也支持改变文本的不透明度。这意味着你可以让文本透明、不透明或介于两者之间。这只适用于具有 alpha 通道的图像。

    对于这个例子,您将使用这个花图像:

    现在创建一个新文件,命名为text_opacity.py。然后将以下代码添加到新文件中:

    # text_opacity.py
    from PIL import Image, ImageDraw, ImageFont
    def change_opacity(input_path, output_path):
        base_image = Image.open(input_path).convert("RGBA")
        txt_img = Image.new("RGBA", base_image.size, (255,255,255,0))
        font = ImageFont.truetype("Gidole-Regular.ttf", 40)
        draw = ImageDraw.Draw(txt_img)
        # draw text at half opacity
        draw.text((10,10), "Pillow", font=font, fill=(255,255,255,128))
        # draw text at full opacity
        draw.text((10,60), "Rocks!", font=font, fill=(255,255,255,255))
        composite = Image.alpha_composite(base_image, txt_img)
        composite.save(output_path)
    if __name__ == "__main__":
        change_opacity("flowers_dallas.png", "flowers_opacity.png")
    

    在这个例子中,你打开花的形象,并将其转换为 RGBA。然后,创建一个与花图像大小相同的新图像。接下来,加载 Gidole 字体,并使用刚刚创建的自定义图像创建一个绘图上下文对象。

    现在有趣的部分来了!你画一个字符串,设置 alpha 值为 128,这相当于大约一半的不透明度。然后你在下面的线上画第二条线,告诉 Pillow 使用完全不透明。请注意,在这两个实例中,您使用的是 RGBA 值,而不是颜色名称,就像您在前面的代码示例中所做的那样。这使您在设定 alpha 值时更加灵活。

    最后一步是调用alpha_composite()并将txt_img合成到base_image上。

    当您运行这段代码时,您的输出将如下所示:

    这演示了如何用 Pillow 改变文本的不透明度。你应该为你的txt_img尝试一些不同的值,看看它如何改变文本的不透明度。

    现在,让我们了解什么是文本锚点,以及它们如何影响文本位置。

    了解文本锚点

    您可以使用anchor参数来确定您的文本相对于您给定的xy坐标的对齐方式。默认是左上角,这是la(左上)锚。根据文档,la表示左上对齐的文本。

    锚点中的第一个字母指定其水平对齐,而第二个字母指定其垂直对齐。在接下来的两个小节中,您将了解每个锚点名称的含义。

    水平锚定对齐

    有四个水平锚。以下内容改编自关于水平锚的文件:

  • l(左)-锚点位于文本的左侧。说到横文,这就是第一个字形的由来。
  • m(中间)-锚点与文本水平居中。在垂直文本的情况下,你应该使用s(基线)对齐,因为它不会根据文本中使用的特定字形而改变。
  • r(右)-锚点在文本的右边。对于横排文本,这是最后一个字形的高级原点。
  • s -基线(仅垂直文本)。对于垂直文本这是推荐的对齐方式,因为它不会根据给定文本的特定字形而改变
  • 垂直锚定对齐

    有六个垂直锚。以下内容改编自关于垂直锚的文件:

  • a(上升/顶部)-(仅横向文本)。锚点位于文本第一行的上行(顶部),由字体定义。
  • t(顶部)——(仅限单行文本)。锚点在文本的顶部。对于垂直文本,这是第一个字形的原点。对于水平文本,建议使用(上升)对齐,因为它不会基于给定文本的特定字形而改变。
  • m(中间)-锚点与文本垂直居中。对于水平文本,这是第一个上行线和最后一个下行线的中点。
  • s —基线(仅限水平文本)。锚点位于文本第一行的基线(底部),只有下行线延伸到锚点下方。
  • b(底部)-(仅单行文本)。锚点在文本的底部。对于竖排文本这是最后一个字形的高级原点。对于水平文本,建议使用d(下行)对齐,因为它不会根据给定文本的特定字形而改变。
  • d(下行/底部)-(仅横向文本)。锚点位于文本最后一行的下行线(底部),由字体定义。
  • 如果你所做的只是谈论锚,锚是很难想象的。如果你能创造一些例子来看看到底发生了什么,那会很有帮助。Pillow 在他们关于 anchors 的文档中提供了一个例子,还有一些非常有用的图片:

  • https://pillow . readthe docs . io/en/stable/handbook/text-anchors . html
  • 你可以以他们为例,稍加修改,使之更有用。要了解如何操作,请创建一个新文件并将其命名为create_anchor.py。然后向其中添加以下代码:

    # create_anchor.py
    from PIL import Image, ImageDraw, ImageFont
    def anchor(xy=(100, 100), anchor="la"):
        font = ImageFont.truetype("Gidole-Regular.ttf", 32)
        image = Image.new("RGB", (200, 200), "white")
        draw = ImageDraw.Draw(image)
        draw.line(((0, 100), (200, 100)), "gray")
        draw.line(((100, 0), (100, 200)), "gray")
        draw.text((100, 100), "Python", fill="black", anchor=anchor, font=font)
        image.save(f"anchor_{anchor}.jpg")
    if __name__ == "__main__":
        anchor(anchor)
    

    您可以按原样运行这段代码。默认锚点是“la ”,但是您在这里明确地调用了它。你也可以画一个十字线来标记xy的位置。如果你用其他设置运行它,你可以看到锚是如何影响它的。

    下面是使用六个不同主播的六次不同跑步的截图:Pillow text anchors examples

    您可以尝试使用这里没有显示的其他锚来运行这段代码。也可以调整位置元组,用不同的锚点重新运行一遍。如果你想的话,你甚至可以创建一个循环来遍历锚点并创建一组例子。

    至此,您已经很好地理解了如何使用 Pillow 绘制文本。事实上,您已经学会了如何做以下所有事情:

  • 加载 TrueType 字体
  • 更改文本颜色
  • 绘制多行文本
  • 更改文本不透明度
  • 了解文本锚点
  • 创建文本绘图 GUI
  • 你现在可以把你学到的东西付诸实践。本文中有很多例子,您可以用它们作为创建新应用程序的起点!

    电子书竞赛:赢得免费的《掌握面向对象的 Python》副本

    原文:https://www.blog.pythonlibrary.org/2014/05/12/ebook-contest-win-a-free-copy-of-mastering-object-oriented-python/

    这场比赛结束了!

    Packt Publishing 与我的博客合作,赠送了两本 Steven Lott 的电子书版本的《掌握面向对象的 Python》。你可以在这里阅读我的完整书评,但是坦率地说,我认为这是我很久以来读过的最好的高级 Python 书籍之一。它也是基于 Python 3 的,尽管大多数概念都适用于 Python 2。

    你如何能赢

    要赢得这本书,你需要做的就是在下面提出评论,强调“你为什么想赢得这本书”的原因。

    竞赛持续时间和获胜者的选择

    比赛有效期为两周,对所有人开放。获胜者将根据他们发表的评论选出。比赛将于 2014 年 5 月 26 日下午 1 点(美国中部时间)结束。

    电子书赠品- Tkinter GUI 应用程序开发

    原文:https://www.blog.pythonlibrary.org/2014/03/10/ebook-giveaway-tkinter-gui-application-development/

    小型 Python 技巧博客上正在进行一场 Python 书籍竞赛。你可以得到 3 本由巴斯卡尔·乔德里写的书 Tkinter GUI 应用程序开发中的一本。去年年底,我评论了这本书,发现它确实是一本有趣的书。我认为它会给你很多好的想法来尝试开发你自己的 GUI 应用程序。现在你有机会得到这本整洁的书了!

    电子书评论:在 Kivy 中创建应用程序

    原文:https://www.blog.pythonlibrary.org/2014/05/01/ebook-review-creating-apps-in-kivy/

    Kivy 是一个简洁的包,允许 Python 开发者在移动设备上创建用户界面。您也可以将应用程序部署到桌面上。这是我看到的关于这个主题的第二本书。Roberto Ulloa 的第一本书《Python 中的 Kivy-Interactive Applications》于去年由 Packt 出版社出版。今年,我们有达斯丁·菲利普斯的作品,在奥莱利用基维语创作应用程序。我将评论这本书的 PDF 版本。

  • 为什么拿起这本书:因为喜欢作者之前的作品 Python 3 面向对象编程所以拿起这本书
  • 我为什么要读完它:这本书很短,而且很有趣
  • 我会把它给:一个已经了解 Python 的人
  • 你可以得到这本书的平装本、epub、mobi 或 PDF。

    这本书实际上只是关于创建一个应用程序。共 9 章,132 页。

    第一章是对基维语和基维语的介绍。KV 语言有点像 GUI 的强大 CSS 版本。在这一章中,你将学习如何创建基本的小部件,并对 KV 进行深入研究,同时开始这本书的总体项目。第二章介绍了 Kivy 的事件系统是如何工作的,以及如何在 KV 定义的小部件中访问属性。

    第 3 章深入探讨了如何操作小部件。这意味着您将学习如何交换小部件和整个表单。第四章讨论了“迭代开发”的概念,并通过一个例子说明了作者是如何从不同的角度解决问题的。您还将学习如何使用 Kivy 从互联网上检索数据。在第五章中,我们学习了 Kivy 的图形(如绘画/动画)来使用户界面更有吸引力。它还讨论了向应用程序添加图标。

    第六章是关于 Kivy 世界的坚持。你如何保存你的设置?你将在本章中找到答案。您还将了解所有 Kivy 应用程序的默认设置以及如何修改它们。在第七章,我们学习手势。如何记录手势、触摸事件、基于手势的击发事件等。

    第八章是关于 Kivy 的高级部件。您将了解 Carousel 小部件(允许在多个小部件之间滑动)、ModalView 和 Popup 小部件(用于在其他小部件上显示小部件)以及 ActionBar。本章还有一个重构代码的例子。第九章讲述了如何使用定制部署工具 buildozer 将你的应用发布到 Android 和 iOS。

    我发现这本书比我读的上一本 Kivy 的书好了一步。虽然标题有点误导,但您仍然会学到很多关于 Kivy 及其内部的知识。我在这里和那里看到一些错别字,但我也有这本书的早期版本,所以我猜我的版本还没有完全编辑好。我要说的是,我在图形章节中遇到了一点麻烦,最终只是阅读了示例,而没有尝试。我喜欢学习许多关于如何使用 Kivy 以及如何适当地将 KV 代码与 Python 混合的简洁的小提示。

    虽然我很想在书中看到其他应用示例,但本文涵盖了开始使用 Kivy 所需了解的所有要点。我认为如果你将这本书与 Kivy 文档和示例片段结合起来,你将很快掌握 Kivy。

    在 Kivy 中创建应用程序

    达斯丁·菲利普斯[亚马逊](http://www.amazon.com/gp/product/B00JKZSYS6/ref=as_li_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B00JKZSYS6&linkCode=as2&tag=thmovsthpy-20&linkId=KFVINA3S7TDFWMKF target=)奥莱利 |

  • Python 中的交互式应用
  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • Python 3 面向对象编程
  • 关于 Kivy 的附加信息

  • 在 Kivy 中创建应用程序
  • The Kivy API
  • 电子书评论:烧瓶框架食谱

    原文:https://www.blog.pythonlibrary.org/2014/12/19/ebook-review-flask-framework-cookbook/

    Packt Publishing 最近发给我一本电子书版本的 Shalabh Aggarwal 的《Flask Framework Cookbook》。我没有读完整本书,因为烹饪书通常不是非常有趣的线性读物。我只是通过它和樱桃挑选了各种食谱。但是在我进入太多细节之前,让我们快速回顾一下!

  • 拿起它的原因:出版社让我看这本书。
  • 我完成它的原因:正如已经提到的,我实际上只是浏览了一下这本书,看了一些随意的食谱
  • 我会把它给:一个初涉 Flask 或可能是中级 Flask 开发人员的人
  • 你可以得到这本书的平装本、epub、mobi 或 PDF。

    这本书分为 12 章,258 页,80 多个食谱。

    Packt 总是推出小众 Python 书籍。Flask 是比较流行的 Python 微型 web 框架之一,所以它可能有相当多的受众。让我们花点时间看看这些章节涵盖了什么。在第一章中,我们找到了许多配置 Flask 的方法。它包含了关于使用基于类的设置,静态文件,蓝图和更多的信息。第二章用一组关于模板语言 Jinja 的食谱稍微改变了一些事情。在第三章中,我们使用 SQLAlchemy 进行数据建模。还有 Redis,Alembic,MongoDB 的配方。第四章是关于使用视图。它包含关于 XHR 请求、基于类的视图、自定义 404 处理程序和其他几个配方的信息。

    在第五章中,作者重点讨论了带有 WTForms 的 webforms。在这里,我们将了解字段验证、上传文件和跨站伪造。对于第 6 章,我们将讨论认证方案。有 Flask-Login 扩展、OpenID、脸书、Google 和 Twitter 的配方。第 7 章讨论 RESTful API 构建。本章只有四种方法,其中两种是关于创建不同类型的 REST 接口的。最后一个方法是一个完整的 REST API 示例。第八章是关于 Flask 中的管理界面。在这里你将学习 Flask-Admin 扩展,自定义表单,用户角色等等!

    第九章带我们进入国际化和本地化。它的食谱最少,只有 3 种。您将学习如何添加新语言、语言切换和 gettext/ngettext。继续第十章,我们将学习调试、错误处理和测试。在这里,我们涵盖了从发送错误邮件到使用 pdb 调试器到 nose、mock 和覆盖率测试的所有内容。第 11 章是关于部署的。它涵盖了关于 apach,Gunicornm 龙卷风,织物,Heroku,AWS 弹性豆茎,应用程序监控和其他一些项目的食谱。第 12 章用其他技巧和诀窍来充实这本书,比如全文搜索、使用信号、缓存、芹菜等等。

    总的来说,我觉得这本书写得相当好。有一些地方有点起伏,因为我不相信作者是以英语为母语的人,但散文并没有因此受到很大影响。大多数食谱作为独立的片段运行良好。有时候代码片段看起来并不完全可以运行,但是您应该能够从 Packt 下载完整的代码。我并不总是发现食谱的分组是完全一致的,但在大多数情况下,它们在一起是有意义的。我推荐这本书给那些想把自己的技能提升到一个新水平的 Flask 初学者,以及那些需要更完整地理解你可以用 Flask 做的事情的人。

    烧瓶框架食谱

    作者:沙拉布·阿格沃尔[亚马逊](http://www.amazon.com/gp/product/178398340X/ref=as_li_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=178398340X&linkCode=as2&tag=thmovsthpy-20&linkId=2QSNQXU6EGH5P7KH target=)打包发布 |

  • L. Felipe Martins 著
  • 达斯丁·菲利普斯用 Kivy 语言创建应用程序
  • Roberto Ulloa 的 Python 交互式应用
  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 达斯丁·菲利普斯的 Python 3 面向对象编程
  • 电子书评论-指南:学习 Python 中的迭代和生成器

    原文:https://www.blog.pythonlibrary.org/2012/04/28/ebook-review-guide-to-learning-iteration-and-generators-in-python/

    上个月大约在 2012 年美国 PyCon 的时候,Matt Harrison 给我发了一本他的新书,Guide to:Learning Iteration and Generators in Python。我一直想学习更多关于发电机的知识,所以我认为这是非常偶然的。可悲的是,我花了一个月才抽出时间来读它。mobi(即 Kindle)版本的电子书重量为 460 kb,epub 版本为 460 kb。在跳跃之后,我们将快速地看一下好的和坏的。

    这是一本技术性很强的书。我想如果它被印刷出来,它会有 50 页左右。所以是速读。另外,它在亚马逊上的零售价仅为 3.99 美元。我想说,这本书是为中高级 Python 程序员而写的,因为作者使用了许多高度技术性的术语,并深入挖掘了 Python 本身的本质,尤其是在最初几章。他也不会花太多时间来解释琐碎的事情,所以我认为这可以作为如今 PyCon 上自吹自擂的“极端”谈话的一个很好的模板。对我来说最重要的是,这本书向我展示了我可以在当天创建的代码中实现生成器的地方。我只是觉得那很酷!您还了解了迭代器和可迭代对象之间的区别,这有点令人难以置信。

    作者并没有说他在给我发一个草稿,但我想这就是我收到的。我的意思是,有很多小句子问题,你会看到像“the”而不是“than”这样的东西,或者一个句子缺少“the”、“an”或“a”,这可能使句子读起来很别扭。我发现前几个例子有点令人困惑,因为作者使用了一个 while 循环来描述一个循环的。最令人困惑的一点是,他指的是一个循环,因为它是前面的循环的例子。更有趣的错误之一是这句话:****

    像 Stack Overfull 这样的网站充斥着声称 xrange 是一个生成器的答案。(Kindle 位置 403)

    我找不到这本书的勘误表,所以我不能说这些吹毛求疵的小问题已经解决了。因为这本书非常专业,所以这也不是初学者学习发电机的最佳方式。另一方面,有时先学习困难的方法是好的。如果你正在努力理解发电机,或者想知道它们为什么存在,那么我想这本书会帮助你。否则,您可以随时查看文档。

    指南:学习 Python 中的迭代和生成器

    作者马特·哈里森从亚马逊购买****作者网站 |

    电子书评论-指南:学习 Python 装饰者

    原文:https://www.blog.pythonlibrary.org/2012/05/02/ebook-review-guide-to-learning-python-decorators/

    本周,我买了马特·哈里森的书学习 Python 装饰者指南,想看看我是否能最终理解装饰者到底有什么了不起。我已经决定尝试用道格·海尔曼的方法来回顾这本书,先做一个快速回顾,然后再做一个更正式的深度回顾,给那些足够想多读点的人。

  • 为什么我拿起它:因为我想了解装修工,我也想看看这本书与哈里森的其他书相比如何。
  • 我为什么要读完它:简单地说,这本书很短,我可以在做其他事情的间隙读它。此外,哈里森关于函数的一些见解非常有趣。
  • 我会把它给:一个需要做元编程或者必须理解函数和函数生成器的中级到高级 Python 开发人员
  • 我能找到的唯一购买这本书的地方是亚马逊的 Kindle,甚至是作者的 T2 网站。所以我猜 mobi 是目前唯一支持的格式,除非你能从作者那里骗到别的东西。

    这本电子书没有真正的章节。对我来说,它们更像是命名的部分。

    函数 -关于函数及其工作原理的各种信息
    函数参数 -这一章讲述了如何args、**kwargs 以及它们的用处。它还讨论了使用“”操作符的“拼合”或展平。闭包, -快速而肮脏的一章,讲述了什么是闭包,以及它们如何引导装饰者。
    装修工——这本书的最后一部分当然是关于装修工的。它涵盖了简单装饰器、装饰器模板、参数化装饰器、多个装饰器和一个类装饰器。

    我觉得这本书相当直接有趣。大多数时候,作者以坦率、平易近人的方式写作。这听起来像一本初学者的书,但我认为它更适合有经验的初学者到中级程序员,因为 Harrison 先生在进入函数生成器、闭包和装饰器时会进入一些令人兴奋的主题。我在这里和那里看到了一个错别字,但总的来说,我认为这篇散文相当不错。偶尔会有一些重复的片段,有时音符部分会叠在一起。堆叠笔记的问题是它们有点像迷你的边角料,会打断文本的流动。

    如果你不理解函数的具体细节,并且你想最终学习那些新的装饰者,我会推荐这本书作为一个处理这些主题的好方法。

    电子书评论:即时烧瓶网络开发

    原文:https://www.blog.pythonlibrary.org/2013/11/08/ebook-review-instant-flask-web-development/

    Packt Publishing 最近联系我,讨论他们的新书《即时烧瓶网络开发》,作者是 Ron DuPlain。他们给了我一本电子书,我刚刚读完。我总是努力对我阅读的 Python 书籍给出诚实的意见,因为我希望我的读者知道一本书是否值得他们辛苦赚来的钱。如果你没有太多时间复习,那么你可以看看我下面的短文。如果你有几分钟的时间,你可以读完剩下的!

  • 为什么选择它:我对学习 Flask(以及一般的 web 开发)感兴趣已经有一段时间了,这本书正好落在我的腿上。
  • 为什么我看完了:它很短,有很多有趣的小食谱和小技巧。
  • 我会把这本书送给:我会把这本书送给已经了解 Python 并且可能也对 web 编程略知一二的人。
  • Packt 出版公司最近开始发行其即时系列图书。这些书都很短。在Instant Flask Web Development的案例中,这本书长达 78 页,包括所有加在开头和结尾的样板文件。这不是给程序员初学者看的书。作者假设读者了解 Python,绝对不会花时间解释 Python 是如何工作的。这并不是一件坏事,因为许多书浪费了大约三分之一的内容来解释初学者的概念,而不是专注于他们的核心主题。它也是一种烹饪书,因为每一部分都是一个食谱,被标为简单,中级或高级。

    另一方面,书中有些观点需要反复阅读才能理解作者在说什么。书中还有一些不完整的代码示例(如第 15 页),还有一些示例中有缺口,读者应该知道如何填补。我在第 46 页找到一个例子,其中两个 return 语句缩进到相同的级别,这样第二个语句就永远不会到达。我知道这些都是吹毛求疵的问题,但是如果一些读者试图直接使用书中的代码,他们会感到困惑。说到代码,Packt 提供的源代码只有代码的最终版本。事实上,我喜欢看到每一章或每一个食谱的代码,看看它是如何发展的,但这是个人的喜好。

    我们来简单谈谈这本书的内容。本书的前提是在 Flask 中创建一个功能齐全的日程安排应用程序。DuPlain 先生谈到了处理请求/响应、静态文件、表单、使用数据库(通过 Flask-SQLAlchemy)、用 Jinja 制作模板、错误响应、认证用户、会话和部署。作者花了本书的大部分时间解释请求/响应处理和使用数据库(如何添加、编辑、删除和查询)。有很多有趣的插件,比如 Flask-WTForms,以及它们是如何工作的。你会发现自己想要点击作者提供的所有各种资源链接,这样你就可以学习到书以外的各种其他东西。我认为这是这本书最擅长的:激起你的食欲,让你越来越想学习。

    虽然这本书有些地方有些粗糙,但我觉得值得一读。当我读完它的时候,我发现自己想了解更多关于 Flask 和它的插件。因此,如果你有兴趣了解 Python 的一个微观网络框架,我认为这本书将帮助你入门。

    注意:我正在为这本书举办一场竞赛,竞赛将于 2013 年 11 月 15 日结束。如果你想有机会赢得一份免费拷贝,就去看看那篇文章

    快速烧瓶网显影

    罗恩·杜普兰亚马逊打包发布 |

  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 马特·哈里森著《踩 Python 第二卷:中级 Python》
  • 约翰·罗兰的《快速学习 Python》
  • 电子书评论:中级 Python

    原文:https://www.blog.pythonlibrary.org/2015/09/02/ebook-review-intermediate-python/

    最近,免费电子书《中级 Python》的作者 Muhammad Yasoob Ullah Khalid 找到我,评论他的作品。Yasoob 是 Python 技巧博客的幕后推手。这本书已经在 Github 上开源发布,但是可以从 ReadTheDocs 下载 PDF 格式。但是在我详细介绍这本书之前,我先简单回顾一下:

  • 为什么拿起:作者让我看这本书。
  • 为什么我读完了这本书:实际上,我通读了这本书的大部分内容,并浏览了剩下的部分
  • 我想把它给:一个想要学习更多 Python 语言的初学者
  • 你可以得到这本书的 PDF,ePub,Mobi,HTML 或者它的源代码,在 RestructuredText 中。你可以在这里购买电子书。

    在写这篇评论的时候,这本书被分成 24 章,共 75 页,但由于它是开源的,这可能会改变。

    这本书涵盖了很多材料,但没有深入任何主题。实际上,这让我想起了我自己的书。没有一堆介绍性的材料,每一章都给出了掌握主题所需的最少量的信息。有些话题确实比其他话题得到了更多的报道。每章长度在 2 至 8 页之间。我应该提一下,这本书相当粗糙,读起来像初稿。例如,目录是空的。英语似乎不是作者的第一语言,所以有些句子可能会有点尴尬。开源的好处之一是任何人都可以来解决这些小问题。

    让我们花点时间讨论一下这本书涵盖的内容。

    前几章介绍了args / **kwargs、调试、生成器和映射/过滤器。在这一点上,我相信我的一些读者会质疑这本书是否真的涵盖了中级水平的材料,因为有些人会认为args / **kwargs 或内置地图更适合初学者。坦率地说,在初级和中级之间有一条细微的界限,所以我真的不打算去那里。这本书是免费的,所以你可以自己做决定。此外,这里还有很多中级材料。

    接下来的几章将介绍 decorators、mutation、slots 和 virtualenv 等。您还会发现关于集合模块、对象自省、协同程序、lambdas、函数缓存和上下文管理器的章节。还有一大堆其他的章节,涵盖了异常处理、全局、枚举、理解、虚拟、三元运算符等等。

    我觉得这本书很有趣,它确实涵盖了各种各样的信息。不过,这些主题似乎没有按照逻辑顺序进行分组。总的来说,我认为普通的 Python 程序员会从这本书里发现一些有价值的信息,而且入门价格是免费的,我认为这本书值得一读。如果你确实喜欢这本书,你应该通过购买这本书来支持作者。

    中级 Python

    穆罕默德·亚索布·乌拉·哈立德橡胶路 T3 |

  • L. Felipe Martins 著
  • 达斯丁·菲利普斯用 Kivy 语言创建应用程序
  • Roberto Ulloa 的 Python 交互式应用
  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 达斯丁·菲利普斯的 Python 3 面向对象编程
  • 电子书评论:IPython 笔记本必备

    原文:https://www.blog.pythonlibrary.org/2014/12/04/ebook-review-ipython-notebook-essentials/

    本周,Packt Publishing 让我评论 L. Felipe Martins 的《IPython 笔记本精要》。他们给我发了一本电子书来评论。我一直对学习 IPython 笔记本很感兴趣,但从来没有抽出时间来,所以这似乎是一个了解更多的好方法。

  • 拿起它的原因:出版社让我看这本书。
  • 为什么看完:我只看了书的笔记本部分。其余的我只是浏览了一下。
  • 我会把它给:一个已经了解 Python 并且是数据科学家的人
  • 你可以得到这本书的平装本、epub、mobi 或 PDF。

    这本书分为五章和三个附录。

    这本书首先在第一章向读者展示了 IPython 笔记本。作者建议您使用 Python 的 Anaconda 发行版,并注册 Wakari 以使共享笔记本更容易。然后,您将学习如何运行笔记本,作者将使用咖啡冷却算法进行示例。这听起来可能有点奇怪,但了解如何计算咖啡随着时间的推移冷却了多少确实很有趣。我还认为这是展示笔记本电脑功能的好方法。这一章以几个简短的练习结束。

    在第二章中,我们学习了更多关于笔记本界面的知识。在这里,我们学习如何编辑和导航笔记本和 IPython magics。您还将学习如何运行脚本以及加载和保存数据。本章最后用几个例子展示了如何在你的笔记本中嵌入图片、Youtube 视频和 HTML。我很喜欢这一章。

    对于第三章,我们戏剧性地改变齿轮。从这一点直到我们到达附录,这本书基本上是给科学家的。这一章是关于在笔记本里用 Matplotlib 创建情节和动画。笔记本本身很少讨论。

    第四章是关于熊猫项目,这是一个强大的数据处理和分析库。这超出了我的专业范围,所以我不能评论它的准确性,更不用说理解作者在这一章中所写的一切。简单地说,我只浏览了第四章。

    第五章是关于 SciPy,Numba 和 NumbaPro。再次强调,重点是科学计算(SciPy)和如何加速这些计算(Numba/NumbaPro)。我也跳过了这一章。

    附录包括以下内容:

  • IPython 笔记本参考卡
  • Python 语言的简要概述
  • NumPy 数组
  • 进入这本书,我认为这将是一个 IPython 笔记本的指南。这个标题无疑给人一种这样的印象。然而,这本书的大部分内容根本不是关于 IPython 笔记本,而是专注于使用 Python 进行科学计算。有许多其他的书涉及这个主题,也许 IPython 笔记本主要是被科学家使用的。前言指出,这本书应该也在学习笔记本以及其他一些库。我只是觉得科学图书馆得到了大部分的散文,而笔记本受到了冷落。

    如果你正在寻找一本 IPython 笔记本的指南,我不确定我能为你推荐这本书。它只有两章专门讨论这个主题,在附录中还有一张参考卡片。另一方面,如果您正在寻找一些可以在 Python 中使用的科学库的简要概述,并学习如何使用 IPython 笔记本,那么这本书可能适合您。

    IPython 笔记本必备

    菲利普·马丁斯[亚马逊](http://www.amazon.com/gp/product/B00Q2N0CL6/ref=as_li_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B00Q2N0CL6&linkCode=as2&tag=thmovsthpy-20&linkId=H4S6DVUH5TTRXJA2 target=)打包发布 |

  • 达斯丁·菲利普斯用 Kivy 语言创建应用程序
  • Roberto Ulloa 的 Python 交互式应用
  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 达斯丁·菲利普斯的 Python 3 面向对象编程
  • 电子书评论:Python 中的交互式应用

    原文:https://www.blog.pythonlibrary.org/2013/12/17/ebook-review-kivy-interactive-applications-python/

    我最近收到了一本 Roberto Ulloa 写的《Kivy:Python 中的交互式应用》。这是目前唯一一本关于 Kivy 的书。Kivy 是一个跨平台的 GUI 工具包,可以在 Linux、Windows 和 OS X 以及 Android 和 iOS 上运行。事实上,Kivy 背后的人强调这主要是针对移动编程的。Kivy 支持多点触控,有一群非常活跃的程序员。你可以在他们项目的主页上读到更多关于 Kivy 的信息。我将评论这本书的 PDF 版本。

    这里是我给你们的快速回顾:

  • 我买这本书的原因:我收到了这本书,作为帮助我复习另一本 Packt 书的报酬,但我自己也会买,因为我对学习 Android/iOS 版 Python 很感兴趣,而且我喜欢学习 Python GUI 工具包。
  • 我为什么完成它:这本书很短,我乐观地认为它会变得更好。
  • 我会把它给:一个已经了解 Python 和 Kivy 基础的人,尽管我不认为我会推荐它。
  • 你可以得到这本书的平装本、epub、mobi 或 PDF。

    这本书分为五章。前四章涵盖了漫画创作者项目,这是关于创建形状和与 Kivy 绘图。读者应该学习 GUI 基础知识(第 1 章),布局(第 1 章),如何使用画布对象(第 2 章),小部件事件(第 3 章),改善用户体验(第 4 章),最后一章涵盖了第二个也是最后一个项目,这是一个太空入侵者的克隆。

    Kivy 工具包支持两种语言。你可以完全用 Python 写你的程序,也可以混合使用 Python 和 Kv 语言。Kv 语言看起来有点像 CSS+Python,它有类似于 Python 的缩进要求(即每个块必须缩进 4 个空格)。使用 Kv 语言的第一个例子在书中没有适当缩进。作者从来没有提到需要将 Kv 代码缩进四个空格,所以我花了一段时间才弄明白为什么代码不起作用。你会发现,书上几乎每一个 Kv 代码的例子,如果照搬都不行。一些 Python 代码也有缩进问题。Packt 雇佣了很多母语不是英语的作者。这本书有许多难以阅读或没有意义的句子的例子。让我们看看每一章。

    第一章介绍了如何启动一个 Kivy 应用程序,如何添加一两个小部件,小部件的属性/变量,Kivy 和布局的各种坐标系。前几节非常简单。坐标部分很混乱,需要反复阅读才能理解。我只理解了版面部分的内容。Kivy 中的布局类似于 wxPython 中的 sizers。当用户改变窗口大小时,它们帮助控制部件如何动态定位。

    第二章深入探讨了基维的画布物体。它涵盖了如何绘制形状,插入图像,如何使用颜色,缩放和翻译。本章中还有关于存储/检索当前坐标空间上下文的信息。图像和颜色部分是我的亮点。其余的,就没那么多了。

    在第三章中,我们学习了 Kivy 中的事件绑定。您将学习如何覆盖、绑定、解除绑定和创建 Kivy 事件。您还将了解如何使用属性来保持 UI 最新。这一章旨在解释其他几个主题。我不确定我是否理解了作者不断绑定事件然后解除绑定的推理,但至少现在我知道怎么做了。有一节是关于小部件、小部件的父部件和窗口本身之间的相对和绝对坐标的转换。这一部分令人困惑,但也很有趣。

    对于第四章,我们学习屏幕管理器。这个概念使得切换屏幕变得很容易,这有点像在 wxPython 中交换面板,只是它内置在 Kivy 中。它还谈到了一个颜色控制小部件,创建和保存手势,以及用于拖动、旋转和缩放的多点触摸。这一章的手势部分很吸引人,尽管我认为它解释得不够详细。Kivy 实际上内置了专门用于保存和检索自定义手势的类。我希望这一节提到 Kivy 在识别手势方面有多准确,但它没有。

    第五章是关于太空入侵者的克隆。这一章只有 20 页,所以我认为它没有给出足够的细节来说明每件事情是如何工作的。我觉得太匆忙了。另一方面,我喜欢学习如何创建游戏,所以我会给作者一些支持。这一章有很多很酷的信息。不过,你只需要花大部分时间来破译密码。

    最后,我想知道更多关于 Kivy 的事情。我发现 Kivy 的文档比这本书更有帮助,但这本书至少有一些有趣的想法。我认为这是它最有价值的地方。它让你想要学习 Kivy,这样你就可以改进书中的两个项目,并制作自己的项目。我认为非常缺少的一个关键话题是项目在一个或两个移动平台上的实际分配,以及如何在这些平台上进行测试。Kivy 在 Android 或 iOS 模拟器中工作吗?Kivy 有 7 个或 8 个以上的 widgets 吗?这些问题没有答案。如果你能便宜买到这本书,我会说去买吧。否则,坚持使用 Kivy 文档和演示程序。

    kivy:Python 中的交互式应用

    罗伯特·乌洛亚亚马逊打包发布 |

  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 马特·哈里森著《踩 Python 第二卷:中级 Python》
  • 约翰·罗兰的《快速学习 Python》
  • 关于 Kivy 的附加信息

  • 在 Kivy 中创建应用程序
  • The Kivy API
  • 电子书评论:快速学习 Python

    原文:https://www.blog.pythonlibrary.org/2013/04/01/ebook-review-learn-python-quickly/

    几个月前,约翰·罗兰联系了我。他是全新电子书快速学习 Python的作者,他联系我,想用我的一篇博客文章作为他书中一个例子的基础。这个确切的说是一个。无论如何,我告诉他当他的书出版的时候我会评论它。总之,这本书几周前出版了,这是我的评论。注:我设法在它免费的时候弄到了一本,我想那是它发售的第二天。

  • 我选择它的原因:我选择这本书,首先是因为有人想在他们的书中使用我的一篇文章,这让我很感兴趣,其次,我偷偷看了几章,很喜欢作者的写作风格。此外,免费拿起它帮助!
  • 为什么写完:因为想复习这本书。不过,我只阅读了正文,而且只浏览了相当广泛的术语表/附录。
  • 我会把它给:新程序员,特别是如果他们已经有一点编程经验,比如 101 课程。
  • 跳完可以看我的全评!

    在撰写本文时,这本书在亚马逊上仅作为 Kindle 图书出售。

    快速学习 Python教 Python 3。它涵盖了你能想到的所有话题和一些你想不到的话题。没想到只是涵盖了安装 Python,尤其是只在 Windows 上。我也很惊讶,像这本书这么短的一本书会在最后 3 章试图跳到用 Tkinter 进行 GUI 编程,但是它做到了。正常的东西当然也包括在内(不一定按这个顺序):数字、字符串、循环和 if 语句、列表和字典(尽管没有太多关于元组的内容)、函数和类、文件 I/O、异常处理、日期操作以及关于电子表格和数据库的一章。

    电子表格和数据库章节(第 8 章)关注电子表格的 csv 模块,提到了 xlwt 包,但没有提到 xlrd 。我想这一章可能会谈到 PyWin32 以及如何使用 PyWin32 的 COM 模块访问 Microsoft Excel,但它没有。数据库部分是对 pyodbc 的快速展示和讲述。他不教 SQL,这没问题,但是要注意。

    这本书在书的最后涵盖了几个应用程序的开发。Rowland 先生让读者在课程章节中创建一个简单的银行应用程序的几种变体。然后,他继续让读者创建一些小的 Tkinter 应用程序。

    这本书最独特的地方在于它使用了大量的超链接。事实上,如果没有术语表和附录,这本书将只有一半长。作者链接到他的词汇表中的各种术语以及一些外部资源。写作风格吸引人,有时很有趣,尤其是当作者放弃一些英国术语时。我觉得这篇课文直截了当,易于理解。不过,我不得不指出几个缺点。代码示例并不多,他经常在书的配套网站上提到代码:http://www.learnpythonquickly.com。大多数情况下,这工作得很好,但是当我将 Tkinter 的代码复制到我的 Python IDE 中时,我的行号与作者的不太匹配。此外,如果你试图使用亚马逊云阅读器阅读这本书,那么代码大多数时候都不会正确缩进,尽管如果你在 Kindle 软件中打开这本书,它似乎会适当缩进代码。

    除此之外,这本书非常好,我会推荐给那些刚接触这门语言,想快速入门的人。当然,如果你是新手,那么你会花很多时间阅读 Python 文档,而且这本书不可能涵盖整个 Python 语言的全部内容。无论如何,我认为这本书将让读者快速掌握 Python 的基础知识,并且当他们需要学习更多知识时,这些链接将帮助他们知道以后要搜索什么。

    快速学习 Python

    约翰·道兰德亚马逊 |

    电子书评论:艰难地学习 Python

    原文:https://www.blog.pythonlibrary.org/2014/01/28/ebook-review-learn-python-the-hard-way/

    几年前,一个叫 Zed Shaw 的家伙创建了一个名为艰难地学 Python的网站,受到了很多人的称赞。该网站由许多简短的练习组成,帮助初级程序员学习 Python 的各种细微差别,但都是以小块的形式。他不时地更新这本书,最终艾迪森-韦斯利把它写成了同名的书。最近有人给了我一份该书的 PDF 版本供我审阅。下面是快速版本:

  • 为什么选择这本书:我收到这本书是为了对它进行评论,尽管我对阅读这本书很感兴趣,只是因为我听说过这个网站
  • 我完成它的原因:这本书的章节很短...严格来说,我浏览了很多
  • 我会把它给:想学习 Python 并且以前没有任何其他语言经验的人
  • 平装本、EPUB、MOBI 和 PDF

    如果你愿意,这本书被分成 52 个练习或章节。大多数章节的长度都不到四页。事实上,有很多章节在它和下一章之间有一个空白页,所以这里有一些填充符。每一章都有一些练习和一些常见的学生问题。正如在介绍性文本中所预期的,您将了解作为 Python 程序员所需的所有数据结构。从字符串、字典和列表等简单的东西,到条件、循环、函数和类。这里都有。这本书还介绍了布尔值、Is-a / has-a、继承、组合、测试和 lpthw.web 框架。

    在导言中,肖先生大谈如果你,读者,觉得他在侮辱你的智慧,那么你就不是这本书的预期读者。无论你是否是初学者,单单这一部分就相当具有侮辱性。当他说“程序员经常谎称自己是数学天才,而实际上他们并不是”时,我并不十分欣赏。我想他是想搞笑,但他给人的印象最多是刻薄。

    这本书很好地涵盖了 Python 的基础知识。通常每个新题目都有几个练习。例如,像文件 I/O 一样,学习打印到标准输出在 3 个练习中涉及。我认为包括学习练习和问答部分绝对是一个好主意,因为它们增强了每章中涉及的材料。我确实认为最后几个练习不太合适。它们相互之间并不适合,看起来像是独立的主题(游戏、骨骼、测试、网站等)。另一方面,这最后几个练习也比前几个长得多,所以也许没关系。

    不管你是否喜欢刻薄/傲慢的部分,核心内容还是很不错的。我喜欢每一部分是如何组合在一起的,以及章节是如何相互构建的,一步一步地提高读者的能力。我认为初学者会受益于这本书,但我建议在你购买这本书之前,先查看一下网站。

    艰难地学习 Python

    作者:泽德·肖亚马逊培生/ InformIT |

  • Roberto Ulloa 的 Python 交互式应用
  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 马特·哈里森著《踩 Python 第二卷:中级 Python》
  • 约翰·罗兰的《快速学习 Python》
  • 电子书评论:学习 scikit-learn:Python 中的机器学习

    原文:https://www.blog.pythonlibrary.org/2014/02/14/ebook-review-learning-scikit-learn-machine-learning-in-python/

    Packt Publishing 的人最近给我发了一本 ral Garreta 和 Guillermo Moncecchi 的书《学习 sci kit-learn:Python 中的机器学习》,请我阅读。机器学习不是我非常熟悉的话题,但我尝试了这本书,因为它听起来很有趣。对于时间不多的人,我先快速回顾一下:

  • 为什么我选择了它:这本书是一本回顾版,但实际上我对任何 Python 编程书籍都感兴趣
  • 我为什么要读完它:这本书写得很好,虽然我不太懂其中的很多内容,但它的主旨很有趣...我浏览了很多。
  • 我会把它给:出于科学目的或机器学习而使用 Python 的人
  • 如果你觉得有趣,那么请随意阅读完整的评论!

    这本书可以买到平装本、PDF、epub 和 Kindle 格式

    Packt Publishing 有一个概念,他们称之为“即时”书籍。这些书往往有 100 页左右长。虽然这本书没有被贴上“即时”的标签,但我认为它符合这一类别,因为它只有 4 章 118 页。这本书是为高级用户准备的。事实上,我会说它是为拥有高等数学或其他科学学位的人准备的。坦率地说,虽然内容很有趣,但我几乎没有领会其中的概念。因此,这将是一个相当轻松的审查。

    首先,你需要 scikit-learnNumPy 。我不确定是否也需要 SciPy。第一章是关于安装 scikit-learn,也是对机器学习的“温和介绍”。第 2 章涵盖了一个名为的监督学习的主题。在这一章中,你将学习图像识别、朴素贝叶斯、泰坦尼克号假说、决策树、随机森林和向量机。我喜欢贝叶斯的解释,学习图像识别也很酷。

    第三章进入了无监督学习的世界,这是一个我觉得相当困惑的话题。作者写了关于主成分分析、k 均值聚类和各种其他聚类方法。我没有真正理解这一章。第 4 章是关于 scikit-learn 的高级特性。它涵盖了诸如特征提取和选择、模型选择和网格搜索等项目。

    作者似乎在他们的领域很有知识,这本书写得很好。我真的没有注意到他们的散文有什么大问题。代码示例看起来很干净,但是我没有测试它们。我当然会向需要学习如何使用 Python 进行机器学习的程序员推荐这本书。。

    学习 scikit-learn:Python 中的机器学习

    作者:ral Garreta 和 Guillermo Moncecchi亚马逊打包发布 |

  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 马特·哈里森著《踩 Python 第二卷:中级 Python》
  • 约翰·罗兰的《快速学习 Python》
  • 电子书评论:忙碌的 Python 开发者的现代 Tkinter

    原文:https://www.blog.pythonlibrary.org/2012/05/12/ebook-review-modern-tkinter-for-busy-python-developers/

    我最近从亚马逊购买了马克·罗斯曼为忙碌的 Python 开发者编写的 Modern Tkinter,昨天刚刚完成。我认为它很新,但我现在找不到它的发布日期。不管怎样,我们继续复习吧!

  • 为什么我买了这本书:我买这本书是因为我一直打算深入研究其他 Python GUI 工具包,而且自从约翰·格雷森的 Python 和 Tkinter 编程之后,我就再也没有看过新的 Tkinter 书了
  • 我完成它的原因:它有一个非常好的写作风格,尽管部件章节开始变得拖沓
  • 我想把它给:任何想让他们的 Tkinter 应用程序看起来更本地或者想了解一点 Tkinter 新主题系统的人。
  • 据我所知,这是另一个亚马逊 Kindle 或其他任何接受 mobi 的 mobi 书。根据亚马逊的说法,它可以打印出大约 147 页,大小不到一兆。

    第 1 章和第 2 章是介绍性的,给出了项目的一些背景信息。第 3 章只是关于安装 Tkinter,我不是很懂。然而,这本书对 Tkinter 的新 ttk 部分以及它如何只在 Python 2.7 和 3.x 中可用进行了大做文章,需要注意的是,在提到 2.7 一次后,作者的行为就像 ttk 只在 3.x 中可用一样,这是混乱和错误的。对于 2.7 之前的版本,你实际上可以下载它,但默认情况下它是 2.7 的(反正在 Windows 上)。

    不管怎样,第 4 章和第 5 章介绍了 Tkinter 的概念。第 6 章和第 8 章是与第 7 章相关的小部件,讨论网格几何管理器。第 9 章介绍菜单;10 浏览窗口和对话框;11 是组织性的(笔记本、窗格式窗户等);12 是关于字体、颜色和图像。第 13-15 章涵盖了大部件:分别是画布、文本和树部件。最后一章,也就是第 16 章,讲述了应用程序的主题化。

    正如我已经提到的,这本书是以一种引人入胜的方式写的。我听说你可以让 Tkinter 看起来更好,但是 Tk 8.5+中的新东西(包含在 Python 2.7+中)让让你的应用程序看起来更好变得容易了。ttk 小部件的主题化方式使它们看起来是本地的或接近本地的,由于新的主题化功能,听起来你实际上可以很容易地对其进行主题化。

    我注意到的不好的地方是在文本中有几个 PYTHONTODO 语句的例子。我想作者是想在这些地方多写些东西,只是忘记删除了。第 6 章中有一部分是关于组合框的,听起来你可以将数据和列表中的项目联系起来。作者声明他将在后面的 Listbox 部分中讨论它,但结果是 Tkinter 根本没有提供这样做的方法。你必须想出自己的方法,尽管作者描述了一些想法,但他并没有展示它们。我认为它可能是类似 wxPython 内置的做这种事情的方式,我在这里写了,但事实并非如此。哦好吧。

    你应该设置 Tkinter 设置的一些方法不清楚,写得很奇怪,通常是这样的: "step?额?”。我不太确定问号是不是必须的,但我猜不是。通常当提到设置时,没有例子来说明它们是如何工作的。在阅读了所有这些内容并看到了一些配置 Tkinter 小部件或实例化它们的奇怪方式后,我仍然认为这非常不直观和不一致。

    另一方面,我认为这本书在很短的时间内包含了很多有用的信息。我感到很受鼓舞,再次尝试 Tkinter,看看它能做什么,也因为我想写一些关于它的文章。我的裁决?如果你想学习关于 ttk 的新东西,这本书很有意义。据我所知,除了官方文档之外,市场上没有任何东西包含这方面的信息。请注意,很少有完整的例子,主题一章实际上从来没有展示如何创建自己的主题,它只是给你足够的信息来做这件事。因此,如果你是一名新的 Python GUI 开发人员,并且想使用 Tkinter,那么这本书可能适合你。

    更新(2012 年 5 月 31 日):这篇文章被重新格式化并转载于I-Programmer

    电子书评论:使用 Python 和 Ming 的 MongoDB

    原文:https://www.blog.pythonlibrary.org/2012/08/08/ebook-review-mongodb-with-python-and-ming/

    本周,我从亚马逊上买了里克·科普兰的《MongoDB with Python》和明的《T1》电子书。它刚刚在 2012 年 7 月发布,所以我想我应该检查一下,看看 MongoDB 和整个 NoSQL 时尚有什么大惊小怪的。

  • 我选择它的原因:主要是因为我对 MongoDB 感兴趣有一段时间了,这本书价格合理,我还读过一点他的 SQLAlchemy 的书。我想我可能几年前也在 PyCon 见过这个人。
  • 我为什么要读完一本书:我几乎总是试图读完一本书,尤其是如果我要复习的话。不过这个很难。
  • 我会把它给:需要一个快速文本来让他们快速了解 MongoDB 和 Ming 的人
  • 据我所知,这本书只有 Lulu 的 epub 版本或 Kindle 版本。

    这本书大约有 84 页长。它包含 6 个章节。第 1 章和第 2 章本质上是介绍性的。第一章是典型的一次性章节,简单描述了将会涉及的内容以及读者应该是谁。简单地说,如果你还不知道 Python,这本书不会帮助你。它也不会帮助您设置 MongoDB。实际上,我很惊讶第一章不是前言。第 2 章告诉你去设置 MongoDB 或者使用一个在线服务,比如 MongoLab 或者 MongoHQ。您还将学习如何安装 pyMongo 并使用它连接 MongoDB、插入数据、运行查询、创建索引、删除数据、更新数据,学习使用 GridFS,以及 MongoDB 中的聚合(mapreduce、分片、聚合框架)。是的,第二章很重。当你读完它的时候,这本书你差不多已经读了一半了。

    第 3 章是关于如何获得 MongoDB 的最佳性能,并讨论了硬件升级和分片。第 4 章介绍 Ming(不要与 Windows 的 MingW 混淆)。Ming 基本上是 MongoDB 的一个 ORM(或 ODM - Object Document Mapper ),由 SourceForge 的人编写,并且是开源的。第 4 章非常全面地介绍了 Ming,包括强制性地和声明性地定义模式。它还涵盖了许多与第 2 章相同的内容(即 CRUD ),但都是从阿明/会议的角度出发。第五章建立在第四章的基础上,它谈到了明灿提供的另一个抽象层,它给了开发者自动持久化的能力,一个身份映射,一次刷新多个更新的方法和一些其他的东西。最后,第 6 章是一个零零碎碎的章节,包含了本书其他地方不适合的东西(这是作者的话,不是我的)。它讨论了在模式改变时支持数据库迁移的各种方法(比如使用 flyaway 模块)以及如何扩展 ODM 的 mapper。

    这本书开头写得很好,作者写得很吸引人。然而,在第 2 章结束时,我发现自己陷入了一个又一个代码示例的泥潭。通常这不会困扰我,但有时感觉有点重复,我觉得没有足够的解释来解释来源。我自己只尝试了几个例子,但它们似乎在大多数时候都有效。就在 2.3 节之前,代码中有一个错别字,作者使用了一个不存在的 findOne()方法。而应该是 find_one()。我试图用谷歌查找 pyMongo 的 API 最近是否有变化,但什么也找不到。希望这是一个孤立的案例,但是正如我所说的,我没有测试很多代码。

    这本书的另一个问题是有许多奇怪的小错别字。通常只是拼写错误,尽管偶尔会有一些语法问题。这是次要的东西,但是我用过的大多数拼写检查器都可以发现其中的大部分。有几处作者有点漫无边际,或者代码会话有点难以理解,但除此之外,我认为这本书相当不错。是的,到最后会变得很枯燥,但大多数编程教科书都是如此。如果你想加入 MongoDB 程序员的大军,并且想坚持使用 Python,那么这本书应该可以让你开始。如果你需要更多的信息,那么 Niall O'Higgins 的《MongoDB 和 Python:流行的面向文档的数据库的模式和过程 》可能会有所帮助(注意:我还没有读过那本书)。

    使用 Python 和 Ming 的 MongoDB

    里克·科普兰亚马逊 |

    电子书评论:Python 高性能编程

    原文:https://www.blog.pythonlibrary.org/2014/02/18/ebook-review-python-high-performance-programming/

    去年,Packt Publishing 邀请我担任 Gabriele Lanaro 的《Python 高性能编程》一书的技术评审。它于 2013 年 12 月出版。对于那些注意力持续时间短的人,我给你们一个简短的回顾:

  • 我拿起它的原因:我是免费得到它的,但我会拿起它,因为它的主题让我感兴趣
  • 我为什么要读完它:这本书有很多有趣的提示,让我想继续读下去
  • 我想把它给:想学习优化代码的人
  • 如果这激起了你的兴趣,一定要点击查看完整的评论!

    这本书可以买到平装本,PDF,epub 和 Kindle 格式。

    这本书的编排方式让我想起了 Packt Publishing 的 Instant 系列,这是他们较短的书籍之一,只有 4 章 108 页。第一章是关于基准和剖析。它讲述了如何使用 Python 的 cProfile、dis 模块和 memory_profiler。我发现这一章非常有趣。虽然我知道这一章提到的几个项目,但它包含了足够多的新信息,让我的大脑充满了分析的想法。

    在第二章中,我们学习了使用 NumPy 的快速数组。这有点奇怪,因为我通常不会想到通过向我的系统添加一个科学的 Python 包来提高性能。然而,如果您使用数组做大量工作,这是有意义的。它还讨论了一个粒子模拟器(整洁!)并使用 numexpr ,NumPy 的快速数值表达式求值器。我个人现在不怎么使用数组,但是对于那些使用数组的人来说,这一章可能会很有意思。

    第三章深入研究了 Cython 的世界。这里的想法是通过使用静态类型、使用 C 数组/指针、内存视图等,使用 Cython 来加速常规 Python 代码。我认为仅仅通过几个调整就可以提高for循环的速度,从而将它变成 C for 循环,这真的很酷。它有大量的例子。就我个人而言,我想看一本以 Cython 为主题的书。

    在第四章中,作者深入探讨了并行处理。本章的重点是使用 Python 自带的多重处理模块。还有一节是关于使用 IPython 并行的。你可以在这里阅读一些关于这个话题的内容。本章的最后一节将讨论如何使用 Cython 和 OpenMP 来实现 Cython 中的并行处理。

    我觉得这本书唯一的问题是它有点太短了。我本想读一读关于这个主题的完整文本。无论如何,对于那些需要加速代码的人来说,我认为这本书可以帮助你开始。

    Python 高性能编程

    加布里埃尔·拉纳罗亚马逊打包发布 |

  • 学习 scikit-learn:Python 中的机器学习
  • 艰难地学习 Python
  • Ron DuPlain 开发的
  • 弗莱彻·海斯勒的《真正的蟒蛇》
  • 马特·哈里森著《踩 Python 第二卷:中级 Python》
  • 约翰·罗兰的《快速学习 Python》
  • http://www.packtpub.com/python-high-performance-programming

    电子书评论:高质量的 Python 开发

    原文:https://www.blog.pythonlibrary.org/2012/05/07/ebook-review-quality-python-development/

    上周看了几本电子书后,我被要求为其他几位作者写评论。我甚至得到了为另一个网站写 Python 书评的机会!疯狂。无论如何,弗雷德里克·莱皮德今天联系我,评论他的电子书,这本书在亚马逊上有售。他以 mobi(即 Kindle)文件的形式发给我。我最终使用了 calibre 来阅读它,因为我使用的机器上没有 Kindle 软件。它非常短,大约有 42 页,所以我一口气读完了。不管怎样,我们继续复习吧!

  • 我拿起它的原因:主要是因为这本书的作者要求我这么做。是的,作者给了我一本书来评论。
  • 我为什么要读完它:这本书短小精悍,涉及的话题令人耳目一新
  • 我想把它给:这本书是为想要扩展自己的技能并成长为中级 Python 编程的初学者而写的
  • 据我所知,这本书只在 Kindle 的亚马逊上有售,所以完全是 mobi。如果你有一台设备或者喜欢 PC/Mac 版的 Kindle 软件,那么这很好。它的重量约为。600 KB 或 42 页。

    这本书有 7 章:

    第 1 章 -编码风格(主要讨论 PEP8 和 pyLint)
    第 2 章 -构建你的开发树(组织你的文件结构/目录层次结构)
    第 3 章 -文档(讲述 reST 和 Sphinx)
    第 4 章 -打包(如何用 distutils 创建一个包并放在 PyPI 上)
    第 5 章 -单元测试
    第 6 章 -打包 教一些 unittest 的东西,提到 Foord 的模拟库,并给出一小段关于 Nose 测试框架和覆盖率的内容。py)
    第 7 章——持续集成(从第 5 章和第 6 章中提取内容,并与 Jenkins 结合)

    让我们先解决这个问题。我怀疑这本书的作者不是以英语为母语的人。因此,作者太频繁地写“代码”而不是“代码”就有点粗糙了。另一方面,我没有发现很多拼写错误的单词。这本书没有深入探讨任何东西,这有点遗憾。不过,这确实会让你想学得更多。作者提到了许多不同的包和它们的用途,我觉得这很有趣。他没有花很多时间解释 Python 的基础知识。相反,他专注于让读者作为程序员开始提升自己。

    我应该提一下,第 6 章与其说是一章,不如说只有一页长。第 7 章可能是最长和最详细的,因为它有很多关于让图形在 Jenkins 中工作的说明,所以你可以看到你的代码有多好。我发现这很有趣,因为我一直听到持续集成。我还发现文档和打包章节非常有趣。

    你可以在亚马逊上花 4.99 美元购买这本书,如果你有真正的 Kindle 和亚马逊 Prime,也可以免费获得。我肯定会免费试用,或者在亚马逊上查看几个样本页面。如果你正在寻找构建你的程序、测试和文档的概述,那么这本书可能正合你的胃口。

    电子书评论:真正的 Python

    原文:https://www.blog.pythonlibrary.org/2013/04/19/ebook-review-real-python/

    我最近收到了弗莱彻·海斯勒的《真正的 Python》,刚刚读完。我从最近的 KickStarter 活动中得到它作为这本书的续集Web 开发的真正 Python的奖金,这本书实际上是别人写的。你可以去这本书的网站购买这本书,并获得这本书谈到的文件。我将审查修订版 2.2,因为这是我几周前下载时得到的。似乎从那以后有了更新。这是我读过的第一本关于 Python 2.7.3 的书,尽管它提到了 Python 3 的一些不同之处。

  • 我买这本书的原因:我买这本书是因为它的续集 Kickstarter 活动给了我额外的奖励。
  • 我为什么要完成它:这本书有一种吸引人的写作风格
  • 我想给:刚接触 Python 语言的程序员
  • 如果你对那个介绍感兴趣,请在跳转之后和我一起阅读完整的评论!

    这本书有 PDF 版、MOBI 版(即 Kindles 版)和 EPUB 版。我不相信在这个审查的时候有一个死树版本。

    Heisler 先生很好地向我们介绍了 Python。起初,听起来好像你将通过编写大量代码来学习 Python(这让我想到了 Zed Shaw 的网站),但作者最终做了大多数 Python 作者做的事情,并经历了一堆基础知识。总之,这本书被分成 13 章(如果算上第 0 章的话是 14 章!)和一些“插曲”部分扔在这里和那里。以下是承保范围的细分:

    第零章只是一个介绍。第一章介绍了下载 Python 和使用 IDLE 的基础知识。然后我们遇到了一个包含代码中注释的插曲。第二章和第三章涵盖了字符串和字符串方法(查找字符串、切片等)。第 4 章讨论函数和循环。然后是另一个插曲,这一次涵盖了 Python 调试器:pdb。第五章讨论条件句(如 if/elif/else ),并讨论如何在循环中中断和继续。第六章是关于列表和字典的。在第七节中,我们学习文件 I/O 以及如何读写 CSV 文件。然后我们进入了另一个插曲,作者谈到了如何安装第三方 Python 模块。出于某种原因,他推荐 easy_install,我认为它在 Python 社区中已经失宠了。但是没有提到替代品,比如 pip。总之,在第八章中,我们学习了如何用 pyPDF 来读、写和操作 PDF。有提到 reportlab 和 PDFMiner,但是没有例子。第 9 章讨论了使用 Python 的 SQL,主要集中在 SQLite 上,尽管它提到了 pyodbc、pyscopg 和 MySQLdb。

    第 10 章介绍了使用 Python 正则表达式的 web 抓取,beautifulsoup 和 mechanize。第 11 章是关于 Python 和图形的科学编程。它涵盖了一点 NumPy 和一点 matplotlib。第 12 章用 EasyGUI 和 Tkinter 探讨 Python GUI 工作。我认为 EasyGUI 是一个奇怪的选择,因为它基本上只是一个对话框生成器,但无论如何。最后一章介绍了使用谷歌应用引擎的网络应用。

    每一章都有多个部分,这些部分通常以一两个练习结束,供读者尝试。文本是以一种非常非正式的方式写的,有一些有趣的例子,比如写一个 L33T 的翻译脚本。因为这是 KickStarter 上的一本书,最后几页列出了所有帮助这本书出版的支持者。我认为这本书涵盖了足够多的语言,足以让一个新的程序员入门。这不是一本深入的 Python 书籍,但也不应该是。它是为了让读者开始他们的 Python 之旅,它在这方面做得很好!

    真正的 Python

    弗莱彻·海斯勒RealPython.com |

    电子书评论:探索 Python 第 2 卷:中级 Python

    原文:https://www.blog.pythonlibrary.org/2013/04/03/ebook-review-treading-on-python-volume-2-intermediate-python/

    上周, Matt Harrison 给我发了一本他最新的 Python 电子书,名为 踏上 Python Vol 2:中级 Python 。我很感兴趣,因为我很少阅读中级 Python 书籍。事实上,我想说作者谈到的一些东西进入了高级水平。无论如何,我认为这是一本非常好的小书,如果你有时间,我会告诉你为什么。

  • 为什么选择它:正如我提到的,这是一本中级水平的书,这是我的必读书目。
  • 为什么我读完了它:因为这本书被证明非常有趣。
  • 我会把它给: Python 程序员,他们对基础知识有很好的理解,但希望提高他们的 Python 技能。
  • 现在如果你有几分钟的时间,你可以在跳转后阅读我的完整评论!

    据我所知,这本书只有在我写作的时候才能在亚马逊上买到。我收到的副本是 epub 格式的,所以可能还有其他版本...

    马特·哈里森的新书是他迄今为止最好的作品。我发现写作几乎没有错误,只有一些错别字,大部分在书的后半部分。这本书分成三个部分(不包括导言)。哈里森没有花时间向我们介绍 Python 相反,他假设您已经知道了,并开始深入研究函数构造。第一部分就这样开始了,他涵盖了 lambda、map、reduce、filter、recursion、list、set 和 dict comprehensions,最后是操作符模块。他使用了 lambda 后面的许多主题来说明 lambda 结构的高级用法。我认为这很有趣,并最终学到了一些新的技巧,我希望很快在自己的代码中实现。

    第二部分致力于迭代和生成器。在这本书里,你将学习 iterables 和 iterators 之间的区别,如何构造一个普通的生成器和一个对象生成器,作者也给出了关于什么时候使用生成器和列表的提示。他还展示了 Python 内核中生成器和迭代器的一些真实例子。他在第一部分也做了一点。

    第三部分是关于函数、闭包和装饰器的,重点是后者。我认为这部分是他关于装饰者的书的更新版本,因为一些例子看起来有点熟悉。不管怎样,这很有启发性。我承认,在书的最后的“替代装饰器实现”部分是相当混乱的。

    最后,我认为这本书非常值得拥有它的成本。你几乎肯定会在第一部分学到一些新东西。如果你不太了解 Python 中的生成器、迭代器或装饰器,那么这本书将帮助你搞清楚,并希望给你一些如何在你的代码中使用它们的想法。我知道我学到了一些东西(可能还重新学到了其他一些东西!).

    行走在 Python 之上第二卷:中级 Python

    马特·哈里森亚马逊 |

    电子书评论:踩在 Python 上

    原文:https://www.blog.pythonlibrary.org/2011/11/26/ebook-review-treading-on-python/

    本周,我发现了一本关于 Python 的新书,书名是 《践踏 Python》第一卷 ,作者是马特·哈里森。这本书只有草稿形式,所以还很粗糙,但是作者好心地给了我一份 epub 和 mobi 格式的免费拷贝。我用 Firefox 的插件 EPUBReader 阅读了其中的一部分,这样我就可以在我的浏览器上阅读了。然后我就切换到 PC Kindle 软件来完成这本书。

    这本书是典型的 Python 入门文本。我觉得它比我读过的一些介绍书要短一点,但这可能是因为它是一本电子书。他涵盖了你所期望的内容,但这里有一个简短的主题列表:

  • Python 的安装
  • 数字和字符串
  • 指导和帮助(自省,尽管他从未使用过这个词)
  • 序列(列表、元组和字典)
  • 函数、类和方法
  • 文件输入输出
  • 例外——非常简短,没有展示如何创建自己的例外
  • 他使用了一些我从未听说过的奇怪术语,比如将 Python 的双下划线方法称为“dunder 方法”(比如 initseq)。我只听说过“魔法方法”这个名字。他还说了下面的话:在 Python 中经常听到关于布尔和布尔类对象的“真”或“假” (Kindle 位置 700)。我读过很多关于 Python 的书,以前也从未遇到过。没什么大不了的,他们只是突然出现在我面前,让我挠头。

    无论如何,我不能对它太苛刻,因为它仍然只是一个草稿。我确实注意到,这本书的前几节似乎在后来有所重复。我不确定那是不是故意的。也许这是强调材料的一种方式。不管怎样,书中的信息对于刚开始学习这门语言的人来说是相当不错的。我应该提到,这是一本概述性的书。每个主题平均只有 1-4 页的信息,所以这本书会给你足够的信息,但是如果你遇到困难,你仍然需要阅读文档。例如,他提到理解,但从来没有说它们是什么。当你编程的时候,你不需要这些,但是它们确实很好。另一方面,他确实说了很多“with”语句。

    总的来说,我认为这是一本非常好的 Python 入门书。读者将会对这种语言有一个很好的了解,而不会对第三方包或者甚至是包含的模块感到困惑。他们对 Python 自省工具有一点了解,这很好。当这本书完成的时候,你可能会想把这本书记在心里,留给你的萌芽期的皮托尼斯塔。你现在可以从他的网站上以 4.99 美元的价格购买这本书,我想你会在完成后得到最终版本,有点像曼宁的早期访问计划(MEAP)。

    出售教学 Python 101 / 201 课程

    原文:https://www.blog.pythonlibrary.org/2017/10/30/educative-python-101-201-courses-on-sale/

    又到了一年中的这个时候,假期就要来了,所以我正在出售我的一些作品。可以免费获得 Python 101 ,五折获得 Python 201:中级 Python 。以下是您可以使用的优惠券代码:

  • 对于Python 101-au-py 101-free
  • 对于python 201-au-py 201-50
  • 注意 Python 101 是完全免费的,第二门课是 50%的折扣。你也可以在 Leanpub 上免费获得 Python 101 的电子书。你也可以用这个链接打五折买到 Python 201 的电子书:【http://leanpub.com/python201/c/py201free

    所有这些优惠券在一周内有效。感谢您的支持!

    PyCon 出售教育 Python 课程!

    原文:https://www.blog.pythonlibrary.org/2017/05/17/educative-python-courses-on-sale-for-pycon/

    本周,我将在 PyCon 上出售我的交互式教育 Python 课程。可以五折获得 Python 101Python 201:中级 Python 。以下是您可以使用的优惠券代码:

  • 对于python 101-au-pycon-py 101
  • 对于python 201-au-pycon-py 201
  • Educative 也在半价出售他们的 Python 3:一门互动深度潜水课程,你可以用这张优惠券获得: au-pycon-deepdive

    现在,为了完全不同的东西,Educative 正在提供 17%的折扣销售他们的 Coderust 2.0:使用交互式可视化更快地编写面试准备,所以如果你有兴趣学习一些稍微不同的东西,现在是你的机会!这是代码: au-pycon-coderust

    使用 Python 启用屏幕锁定

    原文:https://www.blog.pythonlibrary.org/2010/02/09/enabling-screen-locking-with-python/

    几个月前,我的雇主需要锁定我们的一些工作站,以兼容我们从另一个政府机构安装的一些新软件。我们需要在这么多分钟过去后强制这些机器锁定,并且我们需要让用户无法更改这些设置。在本文中,您将了解如何做到这一点,另外,我还将向您展示如何使用 Python 按需锁定您的 Windows 机器。

    黑进注册表锁定机器

    首先,我们来看看我的原始脚本,然后我们将对它进行一点重构,以使代码更好:

    from _winreg import CreateKey, SetValueEx from _winreg import HKEY_CURRENT_USER, HKEY_USERS from _winreg import REG_DWORD, REG_SZ i = 0 while True: subkey = EnumKey(HKEY_USERS, i) if len(subkey) > 30: break i += 1 except WindowsError: # WindowsError: [Errno 259] No more data is available # looped through all the subkeys without finding the right one raise WindowsError("Could not apply workstation lock settings!") keyOne = CreateKey(HKEY_USERS, r'%s\Control Panel\Desktop' % subkey) keyTwo = CreateKey(HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Policies\System') # enable screen saver security SetValueEx(keyOne, 'ScreenSaverIsSecure', 0, REG_DWORD, 1) # set screen saver timeout SetValueEx(keyOne, 'ScreenSaveTimeOut', 0, REG_SZ, '420') # set screen saver SetValueEx(keyOne, 'SCRNSAVE.EXE', 0, REG_SZ, 'logon.scr') # disable screen saver tab SetValueEx(keyTwo, 'NoDispScrSavPage', 0, REG_DWORD, 1) CloseKey(keyOne) CloseKey(keyTwo)

    发现这一点花了一些时间,但是要设置正确的键,我们需要在 HKEY _ 用户配置单元下找到第一个长度大于 30 个字符的子键。我确信可能有更好的方法来做这件事,但是我还没有找到。无论如何,一旦我们找到了长键,我们就跳出循环,打开我们需要的键,或者创建它们,如果它们不存在的话。这就是我们使用 CreateKey 的原因,因为它将做到这一点。接下来,我们设置四个值,然后关闭按键以应用新的设置。您可以阅读注释来了解每个键的作用。现在,让我们稍微改进一下代码,使其成为一个函数:

    from _winreg import * def modifyRegistry(key, sub_key, valueName, valueType, value): A simple function used to change values in the Windows Registry. key_handle = OpenKey(key, sub_key, 0, KEY_ALL_ACCESS) except WindowsError: key_handle = CreateKey(key, sub_key) SetValueEx(key_handle, valueName, 0, valueType, value) CloseKey(key_handle) i = 0 while True: subkey = EnumKey(HKEY_USERS, i) if len(subkey) > 30: break i += 1 except WindowsError: # WindowsError: [Errno 259] No more data is available # looped through all the subkeys without finding the right one raise WindowsError("Could not apply workstation lock settings!") subkey = r'%s\Control Panel\Desktop' % subkey data= [('ScreenSaverIsSecure', REG_DWORD, 1), ('ScreenSaveTimeOut', REG_SZ, '420'), ('SCRNSAVE.EXE', REG_SZ, 'logon.scr')] for valueName, valueType, value in data: modifyRegistry(HKEY_USERS, subkey, valueName, valueType, value) modifyRegistry(HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Policies\System', 'NoDispScrSavPage', REG_DWORD, 1)

    如您所见,首先我们导入 _winreg 模块中的所有内容。不建议这样做,因为您可能会意外地覆盖您已经导入的函数,这就是为什么这有时被称为“毒害名称空间”。然而,我见过的几乎所有使用 _winreg 模块的例子都是这样做的。请参见第一个示例,了解从中导入的正确方法。

    接下来,我们创建一个可以打开密钥的通用函数,或者创建密钥(如果它不存在的话)。该函数还将为我们设置值和关闭键。之后,我们基本上做了与上一个例子相同的事情:我们遍历 HKEY _ 用户配置单元并适当地中断。为了稍微混合一下,我们创建了一个保存元组列表的数据变量。我们对其进行循环,并使用适当的参数调用我们的函数,为了更好地测量,我们演示了如何在循环之外调用它。

    以编程方式锁定机器

    现在您可能会想,我们已经介绍了如何以编程方式锁定机器。从某种意义上来说,我们做到了。但我们真正做的是设置一个计时器,在将来机器空闲时锁定机器。如果我们现在想锁定机器呢?你们中的一些人可能会想,我们应该只按 Windows 键加“L ”,这是一个好主意。然而,我创建这个脚本的原因是因为我必须不时地用 VNC 远程连接到我的机器,当使用 VNC 时,我需要通过多个步骤来锁定机器,而如果你正确设置了 Python,你只需双击一个脚本文件,让它为你锁定。这就是这个小脚本的作用:

    import os winpath = os.environ["windir"] os.system(winpath + r'\system32\rundll32 user32.dll, LockWorkStation')

    这三行脚本导入 os 模块,使用其 environ 方法获取 Windows 目录,然后调用 os.system 来锁定机器。如果您在计算机上打开一个 DOS 窗口,并在其中键入以下内容,您会得到完全相同的效果:

    C:\windows\system32\rundll32 user32.dll, LockWorkStation

    现在你知道如何用 Python 锁定你的机器了。如果您将第一个示例放在登录脚本中,那么您可以使用它锁定网络上的一些或所有机器。如果您的用户喜欢闲逛或参加许多会议,但让他们的机器保持登录状态,这将非常方便。这可以防止他们窥探,也可以保护你的公司免受间谍活动的侵扰。

    使用 Python 增强照片

    原文:https://www.blog.pythonlibrary.org/2017/10/24/enhancing-photos-with-python/

    有时当你拍照时,你会发现它并不是你想要的。这幅画看起来很棒,但就是有点太暗了。或者有点模糊,需要增加锐度。锐度问题现在已经不那么糟糕了,因为很多相机在拍照后会自动为你增加锐度。

    无论如何,在这篇文章中,我们将学习如何做到以下几点:

  • 如何调整照片的亮度
  • 如何改变图像的对比度
  • 如何锐化照片
  • 您首先需要的是可以使用 pip 安装的枕头包:

    pip install Pillow

    现在我们已经安装了枕头,我们可以开始了!

    我个人认为这张照片看起来很好,但出于演示的目的,让我们试着让这张照片变亮。增强照片的关键是使用 Pillow 的 ImageEnhance 模块。让我们来看看:

    from PIL import Image from PIL import ImageEnhance def adjust_brightness(input_image, output_image, factor): image = Image.open(input_image) enhancer_object = ImageEnhance.Brightness(image) out = enhancer_object.enhance(factor) out.save(output_image) if __name__ == '__main__': adjust_brightness('lighthouse.jpg', 'output/lighthouse_darkened.jpg',

    这里我们从 Pillow 导入我们需要的图片,然后在函数中打开输入的图片。接下来我们需要创建一个“增强器”对象。在这种情况下,我们使用 ImageEnhance 的 Brightness 类,并将我们的 image 对象传递给它。接下来我们调用 enhance() 方法,并赋予它增强因子。根据枕头文档,你需要一个大于 1.0 的系数来增加照片的亮度。如果你只是给它一个 1.0 的因子,那么它将返回原始图像不变。

    如果您运行这段代码,您将得到类似这样的结果:

    您也可以将低于 1.0 的增强因子向下传递到 0.0。根据文档,如果一直降到 0.0,您将收到一个完全黑色的图像。只是为了好玩,试着将上面代码中的增强因子改为 0.7。如果你这样做了,那么你会得到以下结果:

    现在让我们试着给图片增加一些对比度!

    调整图像的对比度

    我以前拍过一些非常暗的照片,并且能够通过给照片增加亮度和对比度来保存它们。在这个例子中,我们将只增加这张可爱的毛毛虫照片的对比。但是,您也可以通过将下面的代码与前面的示例相结合来轻松增加亮度:

    from PIL import Image from PIL import ImageEnhance def adjust_contrast(input_image, output_image, factor): image = Image.open(input_image) enhancer_object = ImageEnhance.Contrast(image) out = enhancer_object.enhance(factor) out.save(output_image) if __name__ == '__main__': adjust_contrast('caterpillar.jpg', 'output/caterpillar_more_contrast.jpg',

    这段代码非常类似于增亮函数。唯一的区别是,这里我们使用的是 ImageEnhance 模块中的对比度类,而不是亮度类。当我运行这段代码时,我得到了以下增强:

    ImageEnhance 模块中的所有类都以相同的方式运行。如果您碰巧尝试将增强值 1.0 传递给它,您只是得到原始图像,没有添加任何调整。但是如果你从 0.0 到 1.0,你会降低对比度。您可以自己尝试增强因子,看看可以对自己的图像进行什么样的更改。我试着把它改成 0.7,结果是这样的:

    现在我们准备学习锐化照片!

    更改照片的清晰度

    我很少锐化模糊的照片,因为我很少发现它有帮助。然而,你可以锐化照片,使它看起来不同,在一个愉快的方式。让我们看看如何使用 Python 和 Pillow 来实现这一点:

    from PIL import Image from PIL import ImageEnhance def adjust_sharpness(input_image, output_image, factor): image = Image.open(input_image) enhancer_object = ImageEnhance.Sharpness(image) out = enhancer_object.enhance(factor) out.save(output_image) if __name__ == '__main__': adjust_sharpness('mantis.png', 'output/mantis_sharpened.jpg',

    同样,唯一的变化是使用 ImageEnhance 的 Sharpness 类,而不是其他选择之一。同样像以前一样,我们需要使用一个大于 1.0 的增强因子来增加清晰度。结果如下:

    实际上我有点喜欢这个的结局。你也可以通过使用小于 1.0 的增强因子来模糊图像,但我认为这只会使图像变得相当暗淡。尽管如此,你也可以随意摆弄这些值。

    Pillow 包有这么多使用 Python 编程语言编辑和增强照片的简洁功能。试用起来也超级快。您应该给这些脚本一个旋转,并尝试增强因子,看看您自己能做些什么。还有一个颜色类,我没有在这里介绍,你也可以用它来增强你的照片。开心快乐编码!

  • Kanoki - 为你的照片画铅笔素描
  • 如何用 Python 给你的照片加水印
  • 如何用 Python 调整照片大小
  • 用 Python 将一张照片转换成黑白
  • 如何用 Python 旋转/镜像照片
  • 如何用 Python 裁剪照片
  • Python 101:异常处理(视频)

    原文:https://www.blog.pythonlibrary.org/2021/06/25/exception_handling_video/

    在本视频教程中,您将了解 Python 中异常处理的工作原理。

    具体来说,您将学习以下内容:

  • 检查异常对象
  • 使用finally语句
  • 使用else语句
  • https://www.youtube.com/embed/uGIwpRF2T78?feature=oembed

    如果您喜欢阅读教程,您可能会对以下内容感兴趣:

  • Python 101 - 异常处理
  • 想了解更多,买我的 Python 101 书:

  • Gumroad(电子书)【https://gumroad.com/l/pypy101
  • 亚马逊(平装/Kindle)-【https://amzn.to/2Zo1ARG
  • 使用 Python 从 pdf 导出数据

    原文:https://www.blog.pythonlibrary.org/2018/05/03/exporting-data-from-pdfs-with-python/

    很多时候,您会希望从 PDF 中提取数据,并使用 Python 将其导出为不同的格式。不幸的是,没有很多 Python 包能很好地完成提取部分。在这一章中,我们将会看到各种不同的可以用来提取文本的包。我们还将学习如何从 pdf 中提取一些图像。虽然 Python 中没有针对这些任务的完整解决方案,但是您应该能够使用这里的信息来开始。一旦我们提取了我们想要的数据,我们还将研究如何获取这些数据并以不同的格式导出。

    让我们从学习如何提取文本开始吧!

    使用 PDFMiner 提取文本

    可能最广为人知的是一个叫做 PDFMiner 的包。PDFMiner 包从 Python 2.4 开始就存在了。它的主要目的是从 PDF 中提取文本。事实上,PDFMiner 可以告诉您文本在页面上的确切位置以及关于字体的父信息。对于 Python 2.4 - 2.7,您可以参考以下网站以获得关于 PDFMiner 的更多信息:

  • github-https://github.com/euske/pdfminer
  • PyPI-https://pypi.python.org/pypi/pdfminer/
  • 网页-https://euke . github . io/pdf miner/
  • PDFMiner 与 Python 3 不兼容。幸运的是,有一个名为 PDFMiner.six 的 PDFMiner 分支,其工作原理完全相同。你可以在这里找到:【https://github.com/pdfminer/pdfminer.sixT2

    | | 想了解更多关于使用 Python 处理 pdf 的信息吗?然后看看我的书:

    ReportLab:使用 Python 处理 PDF

    在 Leanpub 上立即购买 |

    安装 PDFMiner 的说明已经过时了。您实际上可以使用 pip 来安装它:

    python -m pip install pdfminer

    如果您想为 Python 3 安装 PDFMiner(这可能是您应该做的),那么您必须像这样进行安装:

    python -m pip install pdfminer.six

    关于 PDFMiner 的文档充其量只能算是相当差的。你很可能需要使用 Google 和 StackOverflow 来弄清楚如何有效地使用本章没有涉及的 PDFMiner。

    提取所有文本

    有时您会想要提取 PDF 中的所有文本。PDFMiner 包提供了几种不同的方法来实现这一点。我们将首先看一些编程方法。让我们试着读出国内税收服务 W9 表格中的所有文本。你可以从这里得到一份:https://www.irs.gov/pub/irs-pdf/fw9.pdf

    一旦您正确保存了 PDF,我们就可以查看代码:

    import io from pdfminer.converter import TextConverter from pdfminer.pdfinterp import PDFPageInterpreter from pdfminer.pdfinterp import PDFResourceManager from pdfminer.pdfpage import PDFPage def extract_text_from_pdf(pdf_path): resource_manager = PDFResourceManager() fake_file_handle = io.StringIO() converter = TextConverter(resource_manager, fake_file_handle) page_interpreter = PDFPageInterpreter(resource_manager, converter) with open(pdf_path, 'rb') as fh: for page in PDFPage.get_pages(fh, caching=True, check_extractable=True): page_interpreter.process_page(page) text = fake_file_handle.getvalue() # close open handles converter.close() fake_file_handle.close() if text: return text if __name__ == '__main__': print(extract_text_from_pdf('w9.pdf'))

    当您直接使用 PDFMiner 包时,它可能有点冗长。在这里,我们从 PDFMiner 的各个部分导入不同的片段。因为没有这些类的文档,也没有 docstrings,所以我不会深入解释它们是做什么的。如果你真的很好奇的话,可以自己钻研源代码。然而,我认为我们可以跟着代码走。

    我们做的第一件事是创建一个资源管理器实例。然后我们通过 Python 的 io 模块创建一个类似文件的对象。如果你使用的是 Python 2,那么你会希望使用 StringIO 模块。我们的下一步是创建一个转换器。在本例中,我们选择了 TextConverter ,但是如果你愿意,你也可以使用 HTMLConverter 或者 XMLConverter 。最后,我们创建一个 PDF 解释器对象,它将接受我们的资源管理器和转换器对象并提取文本。

    最后一步是打开 PDF 并循环浏览每一页。最后,我们获取所有文本,关闭各种处理程序,并将文本打印到 stdout。

    逐页提取文本

    坦白地说,从一个多页文档中抓取所有文本并不那么有用。通常,您会希望在文档的较小子集上工作。因此,让我们重写代码,以便它能够逐页提取文本。这将允许我们一页一页地检查文本:

    # miner_text_generator.py import io from pdfminer.converter import TextConverter from pdfminer.pdfinterp import PDFPageInterpreter from pdfminer.pdfinterp import PDFResourceManager from pdfminer.pdfpage import PDFPage def extract_text_by_page(pdf_path): with open(pdf_path, 'rb') as fh: for page in PDFPage.get_pages(fh, caching=True, check_extractable=True): resource_manager = PDFResourceManager() fake_file_handle = io.StringIO() converter = TextConverter(resource_manager, fake_file_handle) page_interpreter = PDFPageInterpreter(resource_manager, converter) page_interpreter.process_page(page) text = fake_file_handle.getvalue() yield text # close open handles converter.close() fake_file_handle.close() def extract_text(pdf_path): for page in extract_text_by_page(pdf_path): print(page) print() if __name__ == '__main__': print(extract_text('w9.pdf'))

    在这个例子中,我们创建了一个生成器函数,生成每页的文本。 extract_text 函数打印出每一页的文本。在这里我们可以添加一些解析逻辑来解析出我们想要的东西。或者我们可以将文本(或 HTML 或 XML)保存为单独的文件,以便将来解析。

    您会注意到文本可能没有按照您期望的顺序排列。所以你肯定需要找出解析出你感兴趣的文本的最佳方法。

    PDFMiner 的好处在于,您已经可以将 PDF 导出为文本、HTML 或 XML。

    如果您不想自己尝试找出 PDFMiner,也可以使用 PDFMiner 的命令行工具, pdf2txt.pydumppdf.py 来为您完成导出。根据 pdf2txt.py 的源代码,可以用来将一个 pdf 导出为纯文本、html、xml 或者“标签”。

    通过 pdf2txt.py 导出文本

    默认情况下,pdfMiner 附带的 pdf2txt.py 命令行工具将从 PDF 文件中提取文本并将其打印到 stdout。它不能识别图像文本,因为 PDFMiner 不支持光学字符识别(OCR)。让我们试试使用它的最简单的方法,就是把路径传递给 PDF 文件。我们将使用 w9.pdf 的。打开终端并导航到您保存该 PDF 的位置,或者修改下面的命令以指向该文件:

    pdf2txt.py w9.pdf

    如果运行这个命令,它会将所有文本打印到 stdout。您也可以让 pdf2txt.py 将文本以文本、HTML、XML 或“标记 pdf”的形式写入文件。XML 格式将给出关于 PDF 的大部分信息,因为它包含文档中每个字母的位置以及字体信息。不推荐使用 HTML,因为 pdf2txt 生成的标记往往很难看。以下是获得不同格式输出的方法:

    pdf2txt.py -o w9.html w9.pdf pdf2txt.py -o w9.xml w9.pdf

    第一个命令将创建一个 HTML 文档,而第二个命令将创建一个 XML 文档。以下是我在进行 HTML 转换时得到的一张照片:

    正如你所看到的,最终的结果看起来有点差,但还不算太差。它输出的 XML 非常冗长,所以我不能在这里全部复制。不过,这里有一个片段可以让你了解它的样子:

     <pages><page id="1" bbox="0.000,0.000,611.976,791.968" rotate="0"><textbox id="0" bbox="36.000,732.312,100.106,761.160"><textline bbox="36.000,732.312,100.106,761.160"><text font="JYMPLA+HelveticaNeueLTStd-Roman" bbox="36.000,736.334,40.018,744.496" size="8.162">F</text>
    <text font="JYMPLA+HelveticaNeueLTStd-Roman" bbox="40.018,736.334,44.036,744.496" size="8.162">o</text>
    <text font="JYMPLA+HelveticaNeueLTStd-Roman" bbox="44.036,736.334,46.367,744.496" size="8.162">r</text>
    <text font="JYMPLA+HelveticaNeueLTStd-Roman" bbox="46.367,736.334,52.338,744.496" size="8.162">m</text>
    <text font="ZWOHBU+HelveticaNeueLTStd-BlkCn" bbox="60.122,732.312,78.794,761.160" size="28.848">W</text>
    <text font="ZWOHBU+HelveticaNeueLTStd-BlkCn" bbox="78.794,732.312,87.626,761.160" size="28.848">-</text>
    <text font="ZWOHBU+HelveticaNeueLTStd-BlkCn" bbox="87.626,732.312,100.106,761.160" size="28.848">9</text></textline></textbox></page></pages>
    

    使用 Slate 提取文本

    Tim McNamara 不喜欢 PDFMiner 使用起来如此迟钝和困难,所以他写了一个名为 slate 的包装器,使得从 pdf 中提取文本更加容易。不幸的是,它似乎与 Python 3 不兼容。如果你想试一试,你可能需要有 easy_install 来安装 distribute 包,就像这样:

    easy_install distribute

    我无法让 pip 正确安装软件包。一旦安装完毕,您将能够使用 pip 来安装 slate:

    python -m pip install slate

    请注意,最新版本是 0.5.2,pip 可能会也可能不会获取该版本。如果没有,那么您可以直接从 Github 安装 slate:

    python -m pip install git+https://github.com/timClicks/slate

    现在我们准备编写一些代码来从 PDF 中提取文本:

    # slate_text_extraction.py import slate def extract_text_from_pdf(pdf_path): with open(pdf_path) as fh: document = slate.PDF(fh, password='', just_text=1) for page in document: print(page) if __name__ == '__main__': extract_text_from_pdf('w9.pdf')

    如您所见,要让 slate 解析 PDF,您只需导入 slate,然后创建其 PDF 类的一个实例。PDF 类实际上是 Python 的列表内置的一个子类,所以它只返回文本页面的列表/ iterable。您还会注意到,如果 PDF 设置了密码,我们可以传入一个密码参数。无论如何,一旦文档被解析,我们只需打印出每页上的文本。

    我真的很喜欢 slate 的易用性。不幸的是,几乎没有与这个包相关的文档。查看源代码后,似乎这个包只支持文本提取。

    导出您的数据

    现在我们有了一些要处理的文本,我们将花一些时间学习如何以各种不同的格式导出数据。具体来说,我们将学习如何通过以下方式导出文本:

  • 可扩展标记语言
  • 战斗支援车
  • 我们开始吧!

    导出到 XML

    可扩展标记语言(XML)格式是最广为人知的输出和输入格式之一。它在互联网上被广泛用于许多不同的事情。正如我们在本章中已经看到的,PDFMiner 也支持 XML 作为其输出之一。

    不过,让我们创建自己的 XML 创建工具。这里有一个简单的例子:

    # xml_exporter.py import os import xml.etree.ElementTree as xml from miner_text_generator import extract_text_by_page from xml.dom import minidom def export_as_xml(pdf_path, xml_path): filename = os.path.splitext(os.path.basename(pdf_path))[0] root = xml.Element('{filename}'.format(filename=filename)) pages = xml.Element('Pages') root.append(pages) counter = 1 for page in extract_text_by_page(pdf_path): text = xml.SubElement(pages, 'Page_{}'.format(counter)) text.text = page[0:100] counter += 1 tree = xml.ElementTree(root) xml_string = xml.tostring(root, 'utf-8') parsed_string = minidom.parseString(xml_string) pretty_string = parsed_string.toprettyxml(indent=' ') with open(xml_path, 'w') as fh: fh.write(pretty_string) #tree.write(xml_path) if __name__ == '__main__': pdf_path = 'w9.pdf' xml_path = 'w9.xml' export_as_xml(pdf_path, xml_path)

    这个脚本将使用 Python 的内置 XML 库, minidomElementTree 。我们还导入了 PDFMiner 生成器脚本,用于一次抓取一页文本。在这个例子中,我们创建了顶层元素,它是 PDF 的文件名。然后我们在它下面添加一个页面元素。下一步是我们的 for 循环,我们从 PDF 中提取每一页并保存我们想要的信息。您可以在这里添加一个特殊的解析器,将页面分成句子或单词,解析出更多有趣的信息。例如,您可能只想要带有特定名称或日期/时间戳的句子。您可以使用 Python 的正则表达式来查找这些内容,或者只是检查句子中是否存在子字符串。

    对于这个例子,我们只从每个页面中提取前 100 个字符,并将它们保存到一个 XML 子元素中。从技术上讲,下一段代码可以简化为只写出 XML。然而,ElementTree 并没有对 XML 做任何处理以使其易于阅读。它看起来有点像缩小的 javascript,因为它只是一个巨大的文本块。因此,我们没有将文本块写入磁盘,而是使用 minidom 在写出之前用空格“美化”XML。结果看起来像这样:

    <w9><pages><page_1>Form W-9(Rev. November 2017)Department of the Treasury Internal Revenue Service Request for Taxp</page_1> <page_2>Form W-9 (Rev. 11-2017)Page 2 By signing the filled-out form, you: 1\. Certify that the TIN you are g</page_2> <page_3>Form W-9 (Rev. 11-2017)Page 3 Criminal penalty for falsifying information. Willfully falsifying cert</page_3> <page_4>Form W-9 (Rev. 11-2017)Page 4 The following chart shows types of payments that may be exempt from ba</page_4> <page_5>Form W-9 (Rev. 11-2017)Page 5 1\. Interest, dividend, and barter exchange accounts opened before 1984</page_5> <page_6>Form W-9 (Rev. 11-2017)Page 6 The IRS does not initiate contacts with taxpayers via emails. Also, th</page_6></pages></w9>

    这是非常干净的 XML,也很容易阅读。作为奖励,您可以利用在 PyPDF2 章节中学到的知识,从 PDF 中提取元数据并添加到 XML 中。

    导出到 JSON

    JavaScript Object Notation 或 JSON 是一种易于读写的轻量级数据交换格式。Python 在其标准库中包含了一个 json 模块,允许您以编程方式读写 json。让我们利用上一节学到的知识,创建一个输出 JSON 而不是 XML 的导出器脚本:

    # json_exporter.py import json import os from miner_text_generator import extract_text_by_page def export_as_json(pdf_path, json_path): filename = os.path.splitext(os.path.basename(pdf_path))[0] data = {'Filename': filename} data['Pages'] = [] counter = 1 for page in extract_text_by_page(pdf_path): text = page[0:100] page = {'Page_{}'.format(counter): text} data['Pages'].append(page) counter += 1 with open(json_path, 'w') as fh: json.dump(data, fh) if __name__ == '__main__': pdf_path = 'w9.pdf' json_path = 'w9.json' export_as_json(pdf_path, json_path)

    在这里,我们导入我们需要的各种库,包括我们的 PDFMiner 模块。然后我们创建一个接受 PDF 输入路径和 JSON 输出路径的函数。JSON 基本上是 Python 中的一个字典,所以我们创建了几个简单的顶级键:文件名页面。第页的键映射到一个空列表。接下来,我们遍历 PDF 的每一页,提取每页的前 100 个字符。然后,我们创建一个以页码为键、以 100 个字符为值的字典,并将其添加到顶级页面的列表中。最后,我们使用 json 模块的 dump 命令来编写文件。

    文件的内容最终看起来像这样:

    {'Filename': 'w9', 'Pages': [{'Page_1': 'Form W-9(Rev. November 2017)Department of the Treasury Internal Revenue Service Request for Taxp'}, {'Page_2': 'Form W-9 (Rev. 11-2017)Page 2 By signing the filled-out form, you: 1\. Certify that the TIN you are g'}, {'Page_3': 'Form W-9 (Rev. 11-2017)Page 3 Criminal penalty for falsifying information. Willfully falsifying cert'}, {'Page_4': 'Form W-9 (Rev. 11-2017)Page 4 The following chart shows types of payments that may be exempt from ba'}, {'Page_5': 'Form W-9 (Rev. 11-2017)Page 5 1\. Interest, dividend, and barter exchange accounts opened before 1984'}, {'Page_6': 'Form W-9 (Rev. 11-2017)Page 6 The IRS does not initiate contacts with taxpayers via emails. Also, th'}]}

    同样,我们有一些易读的输出。如果您愿意,也可以用 PDF 的元数据来增强这个例子。请注意,输出会根据您希望从每个页面或文档中解析出的内容而变化。

    现在,让我们快速了解一下如何导出到 CSV。

    导出到 CSV

    CSV 代表**逗号分隔值* *。这是一种非常标准的格式,已经存在了很长时间。CSV 的好处在于 Microsoft Excel 和 LibreOffice 会自动在一个漂亮的电子表格中打开它们。如果您想查看原始值,也可以在文本编辑器中打开 CSV 文件。

    Python 有一个内置的 csv 模块,可以用来读写 csv 文件。我们将在这里使用它从 PDF 中提取的文本创建一个 CSV。让我们来看看一些代码:

    # csv_exporter.py import csv import os from miner_text_generator import extract_text_by_page def export_as_csv(pdf_path, csv_path): filename = os.path.splitext(os.path.basename(pdf_path))[0] counter = 1 with open(csv_path, 'w') as csv_file: writer = csv.writer(csv_file) for page in extract_text_by_page(pdf_path): text = page[0:100] words = text.split() writer.writerow(words) if __name__ == '__main__': pdf_path = 'w9.pdf' csv_path = 'w9.csv' export_as_csv(pdf_path, csv_path)

    对于这个例子,我们导入 Python 的 csv 库。否则,导入与前面的示例相同。在我们的函数中,我们使用 CSV 文件路径创建了一个 CSV 文件处理程序。然后,我们初始化一个 CSV writer 对象,将该文件处理程序作为唯一的参数。接下来,我们像以前一样遍历 PDF 的页面。这里唯一的不同是,我们将前 100 个字符拆分成单独的单词。这允许我们将一些实际数据添加到 CSV 中。如果我们不这样做,那么每一行中只有一个元素,这就不是一个真正的 CSV 文件。最后,我们将单词列表写入 CSV 文件。

    这是我得到的结果:

    Form,W-9(Rev.,November,2017)Department,of,the,Treasury,Internal,Revenue,Service,Request,for,Taxp Form,W-9,(Rev.,11-2017)Page,2,By,signing,the,filled-out,"form,",you:,1.,Certify,that,the,TIN,you,are,g Form,W-9,(Rev.,11-2017)Page,3,Criminal,penalty,for,falsifying,information.,Willfully,falsifying,cert Form,W-9,(Rev.,11-2017)Page,4,The,following,chart,shows,types,of,payments,that,may,be,exempt,from,ba Form,W-9,(Rev.,11-2017)Page,5,1.,"Interest,","dividend,",and,barter,exchange,accounts,opened,before,1984 Form,W-9,(Rev.,11-2017)Page,6,The,IRS,does,not,initiate,contacts,with,taxpayers,via,emails.,"Also,",th

    我认为这个例子比 JSON 或 XML 例子更难理解,但也不算太差。现在让我们继续,看看我们如何从 PDF 中提取图像。

    从 pdf 中提取图像

    不幸的是,没有 Python 包真正从 pdf 中提取图像。我找到的最接近的是一个名为 minecart 的项目,它声称可以做到,但只在 Python 2.7 上工作。我无法让它与我拥有的样本 pdf 一起工作。内德·巴奇尔德的博客上有一篇文章讲述了他是如何从 pdf 中提取 jpg 的。他的代码如下:

    # Extract jpg's from pdf's. Quick and dirty. import sys pdf = file(sys.argv[1], "rb").read() startmark = "\xff\xd8" startfix = 0 endmark = "\xff\xd9" endfix = 2 i = 0 njpg = 0 while True: istream = pdf.find("stream", i) if istream < 0: break istart = pdf.find(startmark, istream, istream+20) if istart < 0: i = istream+20 continue iend = pdf.find("endstream", istart) if iend < 0: raise Exception("Didn't find end of stream!") iend = pdf.find(endmark, iend-20) if iend < 0: raise Exception("Didn't find end of JPG!") istart += startfix iend += endfix print("JPG %d from %d to %d" % (njpg, istart, iend)) jpg = pdf[istart:iend] jpgfile = file("jpg%d.jpg" % njpg, "wb") jpgfile.write(jpg) jpgfile.close() njpg += 1 i = iend

    这也不适用于我正在使用的 pdf。有些人在评论中声称它对他们的一些 pdf 文件有效,评论中也有一些更新代码的例子。StackOverflow 上有这段代码的变体,其中一些以某种方式使用了 PyPDF2。这些对我来说都不起作用。

    我的建议是使用像 Poppler 这样的工具来提取图像。Poppler 有一个叫做 pdfimages 的工具,你可以和 Python 的子流程模块一起使用。以下是在没有 Python 的情况下如何使用它:

    pdfimages -all reportlab-sample.pdf images/prefix-jpg

    确保已经创建了图像文件夹(或您想要创建的任何输出文件夹),因为 pdfimages 不会为您创建它。

    让我们编写一个 Python 脚本来执行这个命令,并确保输出文件夹也为您存在:

    # image_exporter.py import os import subprocess def image_exporter(pdf_path, output_dir): if not os.path.exists(output_dir): os.makedirs(output_dir) cmd = ['pdfimages', '-all', pdf_path, '{}/prefix'.format(output_dir)] subprocess.call(cmd) print('Images extracted:') print(os.listdir(output_dir)) if __name__ == '__main__': pdf_path = 'reportlab-sample.pdf' image_exporter(pdf_path, output_dir='images')

    在这个例子中,我们导入了子进程操作系统模块。如果输出目录不存在,我们尝试创建它。然后我们使用子进程的调用方法来执行 pdfimages。我们使用调用,因为它将等待 pdfimages 完成运行。你可以使用 Popen 来代替,但是那将基本上在后台运行这个过程。最后,我们打印出输出目录的列表,以确认图像被提取到其中。

    互联网上还有其他一些文章引用了一个名为 Wand 的库,您可能也想试试。它是一个 ImageMagick 包装器。同样值得注意的是,有一个名为 pypoppler 的 Python 绑定到 Poppler,尽管我找不到该包进行图像提取的任何示例。

    我们在这一章中讲述了许多不同的信息。您了解了几种不同的包,我们可以使用它们从 pdf(如 PDFMiner 或 Slate)中提取文本。我们还学习了如何使用 Python 的内置库将文本导出为 XML、JSON 和 CSV。最后,我们看了从 pdf 导出图像的难题。虽然 Python 目前没有任何好的库来完成这项任务,但是您可以通过使用其他工具来解决这个问题,比如 Poppler 的 pdfimage 实用程序。

  • 使用 Wand 从 python 中的pdf 中提取图像
  • Ned Batchelder - 从 pdf 中提取 JPGs】
  • 用 Python 提取 PDF 元数据和文本
  • StackOverflow: 在 python 中使用 PDFMiner 从 PDF 文件中提取文本?**
  • 用 Python 提取 PDF 元数据和文本

    原文:https://www.blog.pythonlibrary.org/2018/04/10/extracting-pdf-metadata-and-text-with-python/

    有很多与 Python 相关的 PDF 包。我最喜欢的一个是 PyPDF2 。您可以使用它来提取元数据、旋转页面、分割或合并 pdf 等。这就像是现有 pdf 的瑞士军刀。在本文中,我们将学习如何使用 PyPDF2 提取 PDF 的基本信息

    PyPDF2 不是 Python 标准库的一部分,所以您需要自己安装它。这样做的首选方法是使用 pip

    pip install pypdf2

    现在我们已经安装了 PyPDF2,让我们学习如何从 PDF 中获取元数据!

    提取元数据

    您可以使用 PyPDF2 从任何 PDF 中提取大量有用的数据。例如,您可以了解文档的作者、标题和主题以及有多少页。让我们从位于 https://leanpub.com/reportlab 的 Leanpub 下载这本书的样本来了解一下。我下载的样本名为“reportlab-sample.pdf”。

    代码如下:

    # get_doc_info.py from PyPDF2 import PdfFileReader def get_info(path): with open(path, 'rb') as f: pdf = PdfFileReader(f) info = pdf.getDocumentInfo() number_of_pages = pdf.getNumPages() print(info) author = info.author creator = info.creator producer = info.producer subject = info.subject title = info.title if __name__ == '__main__': path = 'reportlab-sample.pdf' get_info(path)

    这里我们从 PyPDF2 导入 PdfFileReader 类。这个类让我们能够使用各种访问器方法读取 PDF 并从中提取数据。我们做的第一件事是创建我们自己的 get_info 函数,它接受 PDF 文件路径作为唯一的参数。然后,我们以只读二进制模式打开文件。接下来,我们将该文件处理程序传递给 PdfFileReader,并创建它的一个实例。

    现在我们可以通过使用 getDocumentInfo 方法从 PDF 中提取一些信息。这将返回一个pypdf 2 . pdf . document information的实例,它具有以下有用的属性:

    如果您打印出 DocumentInformation 对象,您将会看到:

    {'/Author': 'Michael Driscoll', '/CreationDate': "D:20180331023901-00'00'", '/Creator': 'LaTeX with hyperref package', '/Producer': 'XeTeX 0.99998', '/Title': 'ReportLab - PDF Processing with Python'}

    我们还可以通过调用 getNumPages 方法来获得 PDF 中的页数。

    从 pdf 中提取文本

    PyPDF2 对从 PDF 中提取文本的支持有限。不幸的是,它没有提取图像的内置支持。我在 StackOverflow 上看到过一些使用 PyPDF2 提取图像的菜谱,但是代码示例似乎很随意。

    让我们尝试从上一节下载的 PDF 的第一页中提取文本:

    # extracting_text.py from PyPDF2 import PdfFileReader def text_extractor(path): with open(path, 'rb') as f: pdf = PdfFileReader(f) # get the first page page = pdf.getPage(1) print(page) print('Page type: {}'.format(str(type(page)))) text = page.extractText() print(text) if __name__ == '__main__': path = 'reportlab-sample.pdf' text_extractor(path)

    您会注意到,这段代码的开始方式与我们之前的示例非常相似。我们仍然需要创建一个 PdfFileReader 的实例。但是这一次,我们使用 getPage 方法抓取页面。PyPDF2 是从零开始的,很像 Python 中的大多数东西,所以当你给它传递一个 1 时,它实际上抓取了第二页。在这种情况下,第一页只是一个图像,所以它不会有任何文本。

    有趣的是,如果你运行这个例子,你会发现它没有返回任何文本。相反,我得到的是一系列换行符。不幸的是,PyPDF2 对提取文本的支持非常有限。即使它能够提取文本,它也可能不会按照您期望的顺序排列,并且间距也可能不同。

    要让这个示例代码工作,您需要尝试在不同的 PDF 上运行它。我在美国国税局的网站上找到了一个:https://www.irs.gov/pub/irs-pdf/fw9.pdf

    这是为个体经营者或合同工准备的 W9 表格。它也可以用在其他场合。无论如何,我以w9.pdf的名字下载了它,并把它添加到了 Github 库。如果您使用 PDF 文件而不是示例文件,它会很高兴地从第 2 页中提取一些文本。我不会在这里复制输出,因为它有点长。

    您可能会发现 pdfminer 包比 PyPDF2 更适合提取文本。

    PyPDF2 包非常有用。使用它,我们能够从 pdf 中获得一些有用的信息。我可以在 PDF 文件夹中使用 PyPDF,并使用元数据提取技术按照创建者名称、主题等对 pdf 进行分类。试试看,看你怎么想!

  • 简单的分步报告实验室教程
  • ReportLab 101: 文本对象
  • ReportLab - 如何添加图表和图形
  • 基于 Python 和 OpenCV 的人脸检测

    原文:https://www.blog.pythonlibrary.org/2018/08/15/face-detection-using-python-and-opencv/

    机器学习、人工智能和人脸识别是眼下的热门话题。所以我想看看用 Python 来检测照片中的人脸是多么容易,这会很有趣。本文将只关注检测人脸,而不是人脸识别,人脸识别实际上是给一张脸指定一个名字。使用 Python 检测人脸最流行也可能是最简单的方法是使用 OpenCV 包。OpenCV 是一个用 C++编写的计算机视觉库,有 Python 绑定。根据您使用的操作系统,安装可能有点复杂,但在大多数情况下,您可以使用 pip:

    pip install opencv-python
    

    我在旧版本的 Linux 上使用 OpenCV 时遇到了问题,我无法正确安装最新版本。但是这在 Windows 上工作得很好,并且现在似乎在最新版本的 Linux 上也工作得很好。对于本文,我使用的是 OpenCV 的 Python 绑定的 3.4.2 版本。

    使用 OpenCV 查找人脸主要有两种方法:

  • 哈尔分类器
  • LBP 级联分类器
  • 大部分教程都用 Haar,因为它更准确,但也比 LBP 慢很多。在本教程中,我将继续使用 Haar。OpenCV 包实际上包含了有效使用 Harr 所需的所有数据。基本上,您只需要一个 XML 文件,其中包含正确的面部数据。如果你知道你在做什么,你可以创建你自己的,或者你可以使用 OpenCV 自带的。我不是数据科学家,所以我将使用内置的分类器。在这种情况下,您可以在您安装的 OpenCV 库中找到它。只需转到 Python 安装中的/Lib/site-packages/cv2/data文件夹,并查找Haar cascade _ frontal face _ alt . XML。我把那个文件复制出来,放在我写人脸检测代码的那个文件夹里。

    哈尔通过观察一系列正面和负面的图像来工作。基本上,有人会将一堆照片中的特征标记为相关或不相关,然后通过机器学习算法或神经网络进行运行。哈尔着眼于边缘,线条和四矩形特征。OpenCV 网站上有一个很好的解释。一旦你有了数据,你就不需要做任何进一步的训练,除非你需要完善你的检测算法。

    现在我们已经做好了准备,让我们写一些代码:

    import cv2
    import os
    def find_faces(image_path):
        image = cv2.imread(image_path)
        # Make a copy to prevent us from modifying the original
        color_img = image.copy()
        filename = os.path.basename(image_path)
        # OpenCV works best with gray images
        gray_img = cv2.cvtColor(color_img, cv2.COLOR_BGR2GRAY)
        # Use OpenCV's built-in Haar classifier
        haar_classifier = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
        faces = haar_classifier.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=5)
        print('Number of faces found: {faces}'.format(faces=len(faces)))
        for (x, y, width, height) in faces:
            cv2.rectangle(color_img, (x, y), (x+width, y+height), (0, 255, 0), 2)
        # Show the faces found
        cv2.imshow(filename, color_img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    if __name__ == '__main__':
        find_faces('headshot.jpg')
    

    我们在这里做的第一件事是进口。OpenCV 绑定在 Python 中被称为 cv2 。然后,我们创建一个接受图像文件路径的函数。我们使用 OpenCV 的 imread 方法来读取图像文件,然后创建一个副本来防止我们意外修改原始图像。接下来,我们将图像转换为灰度。你会发现计算机视觉几乎总是用灰色比用彩色效果更好,至少 OpenCV 是这样。

    下一步是使用 OpenCV 的 XML 文件加载 Haar 分类器。现在,我们可以尝试使用分类器对象的检测多尺度方法在我们的图像中找到人脸。我打印出我们找到的面孔的数量,如果有的话。分类器对象实际上返回元组的迭代器。每个元组包含它找到的面的 x/y 坐标以及面的宽度和高度。我们使用这些信息在使用 OpenCV 的矩形方法找到的脸部周围画一个矩形。最后我们展示了结果:

    我直视镜头的照片效果很好。只是为了好玩,让我们试着运行我通过代码找到的这张免版税图片:

    当我在代码中运行这个图像时,我得到了如下结果:

    正如你所看到的,OpenCV 只找到了四个人脸中的两个,所以这个特定的层叠文件不足以找到照片中的所有人脸。

    在照片中寻找眼睛

    OpenCV 还有一个 Haar Cascade eye XML 文件,用于查找照片中的眼睛。如果你做过很多摄影,你可能知道当你做肖像的时候,你想试着聚焦在眼睛上。事实上,一些相机甚至有眼睛自动对焦功能。例如,我知道索尼已经吹嘘他们的眼睛对焦功能好几年了,在我对他们的一款相机的测试中,它实际上工作得很好。它很可能使用类似于 Haars 本身的东西来实时发现眼睛。

    无论如何,我们需要稍微修改一下代码来创建一个眼睛探测器脚本:

    import cv2
    import os
    def find_faces(image_path):
        image = cv2.imread(image_path)
        # Make a copy to prevent us from modifying the original
        color_img = image.copy()
        filename = os.path.basename(image_path)
        # OpenCV works best with gray images
        gray_img = cv2.cvtColor(color_img, cv2.COLOR_BGR2GRAY)
        # Use OpenCV's built-in Haar classifier
        haar_classifier = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
        eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
        faces = haar_classifier.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=5)
        print('Number of faces found: {faces}'.format(faces=len(faces)))
        for (x, y, width, height) in faces:
            cv2.rectangle(color_img, (x, y), (x+width, y+height), (0, 255, 0), 2)
            roi_gray = gray_img[y:y+height, x:x+width]
            roi_color = color_img[y:y+height, x:x+width]
            eyes = eye_cascade.detectMultiScale(roi_gray)
            for (ex,ey,ew,eh) in eyes:
                cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
        # Show the faces / eyes found
        cv2.imshow(filename, color_img)
        cv2.waitKey(0) 
        cv2.destroyAllWindows()
    if __name__ == '__main__':
        find_faces('headshot.jpg')
    

    这里我们添加第二个级联分类器对象。这一次,我们使用 OpenCV 内置的 haarcascade_eye.xml 文件。另一个变化是在我们的循环中,我们对找到的人脸进行循环。在这里,我们也试图找到眼睛,并在眼睛周围画矩形。我试着在这个新例子中运行我的原始头像,得到了以下结果:

    这做得相当好,虽然它没有在右边的眼睛周围画出那么好的矩形。

    OpenCV 有很多强大的功能让你开始用 Python 做计算机视觉。你不需要写很多行代码来创建有用的东西。当然,您可能需要做比本教程中显示的更多的工作,训练您的数据并优化您的数据集,以使这种代码正常工作。我的理解是,培训部分是真正耗时的部分。无论如何,我强烈推荐去看看 OpenCV,试一试。这是一个非常整洁的图书馆,有很好的文档。

  • OpenCV - 使用哈尔级联的人脸检测
  • 用 Python 进行人脸识别
  • DataScienceGo - OpenCV 人脸检测
  • 用 Faker 软件包伪造数据

    原文:https://www.blog.pythonlibrary.org/2021/09/09/faking-data/

    如果您是一名软件开发人员或工程师,那么您知道拥有样本数据会非常有帮助。数据也不一定是真实的数据。相反,数据可能是假的。例如,如果您正在编写一个处理 HIPAA 数据的程序,那么您将不会使用实际数据进行测试,因为这将违反隐私法。

    优秀的程序员知道他们应该测试他们的代码,但是当数据受到保护或不可用时,如何测试呢?这就是虚假数据的来源。你可以用假数据填充你的数据库,创建 XML 或 JSON,或者用它来匿名化真实数据。有一个叫做 Faker 的 Python 包,可以用来生成假数据。

    Faker 的灵感主要来自于 PHP FakerPerl FakerRuby Faker

    使用 Faker 的第一步是安装它!

    如果你知道如何使用 pip ,Faker 很容易安装。以下是您可以运行的命令:

    python3 -m pip install Faker
    

    现在 Faker 已经安装好了,您可以开始创建假数据了!

    用 Faker 创建假数据

    Faker 让伪造数据变得异常容易。打开您的终端(或 cmd.exe/Powershell)并运行 Python。然后,您可以在您的 REPL 中尝试以下代码:

    >>> from faker import Faker
    >>> fake = Faker()
    >>> fake.name()
    'Paul Lynn'
    >>> fake.name()
    'Keith Soto'
    >>> fake.address()
    'Unit 6944 Box 5854\nDPO AA 14829'
    >>> fake.address()
    '44817 Wallace Way Apt. 376\nSouth Ashleymouth, GA 03737'
    

    这里你从 faker 模块导入 Faker 类。接下来,调用几次名称()地址()函数。每次调用这些函数时,都会返回一个新的假名字或假地址。

    您可以通过创建一个循环并调用 name() 十次来看到这一点:

    >>> for _ in range(10):
    ...     print(fake.name())
    Tiffany Mueller
    Zachary Burgess
    Clinton Castillo
    Yvonne Scott
    Randy Gilbert
    Christina Frazier
    Samantha Rodriguez
    Billy May
    Joel Ross
    Lee Morales
    

    这段代码演示了每次调用函数时,名字都是不同的!

    创建假的国际数据

    Faker 支持在实例化 Faker() 类时设置区域设置。这意味着你可以用其他语言伪造数据。

    例如,尝试将地区设置为意大利语,然后打印出一些名字:

    >>> fake_italian = Faker(locale="it_IT")
    >>> for _ in range(10):
    ...     print(fake_italian.name())
    Virgilio Cignaroli
    Annibale Tutino
    Alessandra Iannucci
    Flavio Bianchi
    Pier Peruzzi
    Marcello Mancini-Saragat
    Marina Sismondi
    Rolando Comolli
    Dott. Benvenuto Luria
    Giancarlo Folliero-Dallapé
    

    这些名字现在都是意大利语。如果您想要更多的变化,您可以将一个地区列表传递给 Faker() 来代替:

    注意:这个例子是一个图像而不是文本,因为语法荧光笔工具不能正确显示亚洲字符。

    创建假的 Python 数据

    Faker 包甚至可以伪造 Python 数据。如果你不想拿出你的 Python 列表、整数、字典等等,你可以让 Faker 帮你做。

    这里有几个例子:

    >>> fake.pylist()
    ['http://www.torres.com/category/', -956214947820.653, 'bPpdDhlEBEbhbQETwXOZ', Decimal('256.347612040523'), '
    dPypmKDRlQqxpdkhOfmP', 5848, 'PGyduoxaLewOUdTEdeBs', Decimal('-43.8777257283172'), 'oxqvWiDyWaOErUBrkhIa', 
    'hkJbiRnTaPqZpEnuJoFF', 8471, '[email protected]', 'rXQBeNIKEiGcQpLZKBvR']
    >>> fake.pydict()
    {'eight': 'http://nielsen.com/posts/about/', 'walk': Decimal('-2945142151233.25'), 'wide': '[email protected]', 
    'sell': 5165, 'information': 2947, 'fire': 'http://www.mitchell.com/author.html', 'sea': 4662, 
    'claim': '[email protected]'}
    >>> fake.pyint()
    >>> fake.pyint()
    

    这不是很好吗?

    Faker 允许您设置自定义种子或创建自己的假数据提供者。要了解全部细节,请阅读 Faker 的文档。您应该今天就看看这个包,看看它对您自己的代码有多大用处。

    其他简洁的 Python 包

    想了解其他整洁的 Python 包吗?查看以下教程:

  • arrow—Python 的新日期/时间包
  • PySimpleGUI 简介
  • OpenPyXL–使用 Python 使用 Microsoft Excel】
  • 2018 年秋季电子书销售

    原文:https://www.blog.pythonlibrary.org/2018/08/26/fall-ebook-sale-2018/

    这是一个新学年的开始,所以今年秋天我要进行一次新的销售。请随意查看我目前的销售情况:

  • ReportLab:Python 中的 PDF 处理
  • Python 201: 中级 Python
  • Python 101
  • Jupyter notebook 101(预购/提前获取)-预计。2018 年 11 月交付
  • 这些销售将持续到 9 月 1 日。我所有的电子书都有 PDF、mobi (Kindle)和 epub 格式。

    2 月 5 日- 2009 年平壤会议总结

    原文:https://www.blog.pythonlibrary.org/2009/02/06/feb-5th-2009-pyowa-meeting-wrap-up/

    在我们昨晚的聚会上,除了我之外,我们还有 7 个新成员。考虑到过去几天有 5 个人退出,我认为这是一个很好的出席率。我们谈了一点关于我们自己的 Python 日,但是我们并没有提出太多。因此,我在征求意见,并希望为我们的下一次会议收集这些意见,这样我们就可以确定一个日期。

    会议的其余时间都花在解决我遇到的前几个愚蠢的电脑问题上。我们有三个团队在研究它们,我们有相当多的种类。我用函数,另一个用类接口完全面向对象。我们只是把摄氏温度转换成华氏温度,反之亦然。第二个程序是将一系列数字转换成文本,例如:

    如果用户输入:123,那么输出应该是“一二三”。为了让事情变得更困难,我们还需要一种处理负数的方法。有一种方法可以做到:

    numberDict = {0:"zero", 1:"one", 2:"two", 3:"three", 4:"four", 5:"five", 6:"six", 7:"seven", 8:"eight", 9:"nine"}

    value = raw_input("请输入要转换为文本的一个数字或一系列数字: ")

    对于 val in value:
    if is instance(val,str) and val == "-":
    打印" minus ",
    else:

    只打印可以转换为整数类型的字符

    打印 numberDict[int(val)],

    当然,这种实现方式存在很多问题。例如,异常处理的方式不多,如果不重新运行脚本,就没有办法再次运行它。作为一个函数或一个类会更好,但是我将把那些任务留给读者作为练习。

    我们的下一次会议将于 2009 年 3 月 2 日在马歇尔郡治安官办公室举行。我希望在那里见到你!

    用 Python 填充 PDF 表单

    原文:https://www.blog.pythonlibrary.org/2018/05/22/filling-pdf-forms-with-python/

    多年来,可填写表格一直是 Adobe PDF 格式的一部分。在美国,可填写表单最著名的例子之一是来自国内税收署的文档。有许多政府表格使用可填写的表格。以编程方式填写这些表单有许多不同的方法。我听说过的最耗时的方法是在 ReportLab 中手工重新创建表单,然后填写。坦白地说,我认为这可能是最糟糕的主意,除非你的公司自己负责创建 pdf。那么这可能是一个可行的选择,因为这样你就可以完全控制 PDF 的创建和输入。

    创建简单的表单

    我们需要一个简单的表单用于我们的第一个例子。ReportLab 内置了对创建交互式窗体的支持,所以让我们使用 ReportLab 来创建一个简单的窗体。下面是代码:

    # simple_form.py from reportlab.pdfgen import canvas from reportlab.pdfbase import pdfform from reportlab.lib.colors import magenta, pink, blue, green def create_simple_form(): c = canvas.Canvas('simple_form.pdf') c.setFont("Courier", 20) c.drawCentredString(300, 700, 'Employment Form') c.setFont("Courier", 14) form = c.acroForm c.drawString(10, 650, 'First Name:') form.textfield(name='fname', tooltip='First Name', x=110, y=635, borderStyle='inset', borderColor=magenta, fillColor=pink, width=300, textColor=blue, forceBorder=True) c.drawString(10, 600, 'Last Name:') form.textfield(name='lname', tooltip='Last Name', x=110, y=585, borderStyle='inset', borderColor=green, fillColor=magenta, width=300, textColor=blue, forceBorder=True) c.drawString(10, 550, 'Address:') form.textfield(name='address', tooltip='Address', x=110, y=535, borderStyle='inset', width=400, forceBorder=True) c.drawString(10, 500, 'City:') form.textfield(name='city', tooltip='City', x=110, y=485, borderStyle='inset', forceBorder=True) c.drawString(250, 500, 'State:') form.textfield(name='state', tooltip='State', x=350, y=485, borderStyle='inset', forceBorder=True) c.drawString(10, 450, 'Zip Code:') form.textfield(name='zip_code', tooltip='Zip Code', x=110, y=435, borderStyle='inset', forceBorder=True) c.save() if __name__ == '__main__': create_simple_form()

    运行此示例时,交互式 PDF 表单如下所示:

    现在,我们准备学习填写此表格的方法之一!

    Jan Ch 撰写了一篇关于 Medium 的文章,其中包含了几种不同的方法来解决在 pdf 中填写表单的问题。提出的第一个解决方案是在 PDF 中获取一个未填充的表单,并使用 ReportLab 创建一个单独的 PDF,其中包含我们希望“填充”该表单的数据。然后作者使用 pdfrw 将两个 pdf 合并在一起。理论上,您也可以将 PyPDF2 用于合并过程。让我们来看看这个方法是如何使用 pdfrw 包工作的。

    让我们从安装 pdfrw 开始:

    python -m pip install pdfrw

    现在我们已经安装了这些,让我们创建一个名为 fill_by_overlay.py 的文件。我们将向该文件添加两个函数。第一个函数将创建我们的覆盖。让我们来看看:

    # fill_by_overlay.py import pdfrw from reportlab.pdfgen import canvas def create_overlay(): Create the data that will be overlayed on top of the form that we want to fill c = canvas.Canvas('simple_form_overlay.pdf') c.drawString(115, 650, 'Mike') c.drawString(115, 600, 'Driscoll') c.drawString(115, 550, '123 Greenway Road') c.drawString(115, 500, 'Everytown') c.drawString(355, 500, 'IA') c.drawString(115, 450, '55555') c.save()

    在这里,我们导入了 pdfrw 包,还从 ReportLab 导入了画布子模块。然后我们创建一个名为 create_overlay 的函数,它使用 ReportLab 的 Canvas 类创建一个简单的 PDF。我们只是用拉带画布的方法。这需要反复试验。幸运的是,在 Linux 和 Mac 上,有不错的 PDF 预览应用程序,你可以用它来保持 PDF 打开,它们会随着每次更改自动刷新。这对于计算出绘制字符串所需的精确坐标非常有帮助。因为我们创建了原始表单,所以计算覆盖图的偏移量实际上非常容易。我们已经知道表单元素在页面上的位置,所以我们可以很好地猜测将字符串绘制到哪里。

    这个难题的下一部分实际上是将我们在上面创建的覆盖图与我们在前一部分创建的表单合并。接下来让我们编写这个函数:

    def merge_pdfs(form_pdf, overlay_pdf, output): Merge the specified fillable form PDF with the overlay PDF and save the output form = pdfrw.PdfReader(form_pdf) olay = pdfrw.PdfReader(overlay_pdf) for form_page, overlay_page in zip(form.pages, olay.pages): merge_obj = pdfrw.PageMerge() overlay = merge_obj.add(overlay_page)[0] pdfrw.PageMerge(form_page).add(overlay).render() writer = pdfrw.PdfWriter() writer.write(output, form) if __name__ == '__main__': create_overlay() merge_pdfs('simple_form.pdf', 'simple_form_overlay.pdf', 'merged_form.pdf')

    这里我们使用 pdfrw 的 PdfReader 类打开表单和覆盖 pdf。然后我们遍历两个 pdf 的页面,并使用页面合并将它们合并在一起。在代码的最后,我们创建了一个 PdfWriter 的实例,我们用它来写出新合并的 PDF。最终结果应该是这样的:

    注意:当我运行这段代码时,我确实在 stdout 上收到了一些错误。这里有一个例子:

    [ERROR] tokens.py:226 stream /Length attribute (171) appears to be too small (size 470) -- adjusting (line=192, col=1)

    正如我提到的,这实际上并不妨碍合并 PDF 的创建。但是你可能要留意这些,因为如果你有任何问题,它们可能暗示着一个问题。

    填写表单的其他方式

    我读过一些其他的方法来“填充”这些类型的 pdf 中的字段。其中一个是获取一个 PDF 文件,并将页面保存为一系列图像。然后在您想要添加文本的位置绘制矩形,然后使用您的新图像作为配置文件来填写 PDF。似乎有点古怪,坦白说,我不想去做那些工作。

    更好的方法是在 PDF 编辑器中打开 PDF,您可以在其中添加不可见的只读字段。您可以用唯一的名称标记字段,然后通过 PDF 的元数据访问它们。在元数据上循环,并使用 ReportLab 的 canvas 方法再次创建一个覆盖图,然后以与之前大致相同的方式将其合并。

    我也看到很多人在谈论使用表单数据格式或 FDF。这是 PDF 应该用来保存要在 PDF 中填充的数据的格式。您可以使用 PyPDFtkPdfJinja 来完成表单填写。有趣的是, PyPDFtk 不能处理图像字段,比如你可能想要粘贴签名图像的地方。为此,您可以使用 PdfJinja 。然而 PdfJinja 在使用复选框和单选按钮时似乎有一些限制。

    您可以通过以下链接了解有关这些主题的更多信息:

  • https://yoongkang.com/blog/pdf-forms-with-python/
  • https://medium . com/@ zwin ny/filling-pdf-forms-in-python-the-right-way-EB 9592 e 03 DBA
  • 使用 pdf 表单包

    我认为在易用性方面最有希望的包是新的 pdfforms 包。不过它要求你安装一个名为 pdftk 的跨平台应用程序。幸运的是 pdftk 是免费的,所以这不是一个真正的问题。

    您可以使用 pip 安装 pdfforms,如下所示:

    python -m pip install pdfforms

    要使用 pdfforms,您必须首先让它检查包含表单的 PDF,以便它知道如何填写。你可以这样做检查:

    pdfforms inspect simple_form.pdf

    如果 pdfforms 工作正常,它会在“test”子文件夹中创建一个“filled”PDF。该子文件夹出现在 pdfforms 本身所在位置的旁边,而不是您运行它的位置。它将按顺序用数字填充表单。这些是字段编号

    接下来您要做的是创建一个 CSV 文件,其中第一列和第一行包含 PDF 的名称。第一列中的其他行对应于字段编号。您在此输入要填写的字段的编号。然后,在 CSV 文件的第三列中输入要在表单中填写的数据。第二列被忽略,所以您可以在这里放置一个描述。第三列之后的所有列也将被忽略,因此这些列可以用于您想要的任何用途。

    对于本例,您的 CSV 文件可能如下所示:

    simple_form.pdf,,, 1,first name,Mike 2,last name,Driscoll

    填写完 CSV 后,您可以运行以下命令,用您的自定义数据实际填写表单:

    pdfforms fill data.csv

    默认情况下,填充的 PDF 会出现在名为 filled 的子文件夹中。

    现在说说坏消息。我无法让它在 Windows 或 Mac 上正常工作。我让 inspect 步骤在 Windows 上运行,但在 Mac 上它只是挂起。在 Windows 上,当我运行 fill 命令时,它失败了,并显示一个错误,说找不到要填充的 PDF。

    我想当这个包变得不那么容易出错的时候,真的会很神奇。除了运行有问题之外,唯一主要的缺点是你需要安装一个根本不是用 Python 写的第三方工具。

    在查看了 Python 开发人员可用于填充 PDF 表单的许多不同选项后,我认为最直接的方法是创建覆盖图,然后使用 pdfrw 之类的工具将其合并到可填充的表单 PDF 中。虽然这感觉有点像黑客,但我见过的其他方法看起来也一样的黑客和耗时。一旦您知道了表单中一个单元格的位置,您就可以合理地计算出页面上大多数其他单元格的位置。

  • PyPI 上的 pdfforms 包
  • Github 上的 pdfrw 包
  • Github 上的 PdfJinja 包
  • 使用 Python 的 PDF 表单博客文章
  • 使用 Python 查找已安装的软件

    原文:https://www.blog.pythonlibrary.org/2010/03/03/finding-installed-software-using-python/

    你有没有想过你的电脑上安装了什么软件?大多数使用 Windows 的人可能会通过添加/删除程序来找到这些信息,但他们不是程序员。不,程序员必须编写脚本,因为这样做是我们的天性。实际上,我这么做还有另一个原因:我的老板希望我记录用户电脑上安装了什么,这样我们就能知道用户是否安装了未经授权的软件。因此,尝试这样做还有一个实际的原因。

    经过一些研究,我发现大多数行为良好的软件会在 Windows 注册表中存储关于它们自己的各种信息。具体来说,它们通常将这些信息存储在以下位置:HKEY _ LOCAL _ MACHINE \ Software \ Microsoft \ Windows \ current version \ Uninstall

    应该注意的是,并非所有您安装的程序都会将该信息放入注册表中。例如,有些供应商根本不使用注册中心。此外,恶意软件之类的恶意程序可能也不会把任何东西放在那里。然而,超过 90%的人会这样做,这是获取信息的好方法。要获得更多信息,您可能需要使用 Python 的操作系统模块的“walk”方法进行一些目录遍历,并通过与注册表中的内容进行比较来查找不匹配的内容,或者从您从原始基础机器保存的一些存储映像中查找不匹配的内容。

    总之,说够了。让我们来看看代码!注:如果你想跟着做,那么你需要下载并安装蒂姆·戈登的 WMI 模块

    import StringIO import traceback import wmi from _winreg import (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, OpenKey, EnumValue, QueryValueEx) softFile = open('softLog.log', 'w') errorLog = open('errors.log', 'w') r = wmi.Registry () result, names = r.EnumKey (hDefKey=HKEY_LOCAL_MACHINE, sSubKeyName=r"Software\Microsoft\Windows\CurrentVersion\Uninstall") softFile.write('These subkeys are found under "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall"\n\n') errorLog.write("Errors\n\n") separator = "*" * 80 keyPath = r"Software\Microsoft\Windows\CurrentVersion\Uninstall" for subkey in names: softFile.write(separator + '\n\n') path = keyPath + "\\" + subkey key = OpenKey(HKEY_LOCAL_MACHINE, path, 0, KEY_ALL_ACCESS) temp = QueryValueEx(key, 'DisplayName') display = str(temp[0]) softFile.write('Display Name: ' + display + '\nRegkey: ' + subkey + '\n') except: softFile.write('Regkey: ' + subkey + '\n') except: fp = StringIO.StringIO() traceback.print_exc(file=fp) errorMessage = fp.getvalue() error = 'Error for ' + key + '. Message follows:\n' + errorMessage errorLog.write(error) errorLog.write("\n\n") softFile.close() errorLog.close()

    这是一个很短的片段,但这里有很多东西。让我们打开它。首先,我们导入我们需要的模块,然后打开几个文件: softFile 将把我们的脚本找到的所有软件存储在“softLog.log”中,而我们的 errorLog 变量将把我们遇到的任何错误存储在“errors.log”中。接下来,我们使用 WMI 来枚举“Uninstall”键中的子项。之后,我们给每个日志文件写一些标题信息,使它们更容易阅读。

    最后一个重要部分出现在循环结构中。在这里,我们循环从我们的 WMI 调用返回的结果。在我们的循环中,我们试图提取两条信息:软件的显示名称和与之相关的键。还有很多其他信息,但似乎没有任何标准可以遵循,所以我没有抓住任何一个。您将需要更复杂的错误处理来很好地提取它(或者使用生成器)。无论如何,如果我们试图取出的任何一部分失败了,我们会发现错误并继续下去。嵌套异常处理捕捉与获取显示名称相关的错误,而外部异常处理程序捕捉与访问注册表相关的错误。我们或许应该将这些异常显式化(比如,后者应该是 WindowsError,我认为),但这只是一个快速而肮脏的脚本。你认为有必要的话,可以随意延长。

    如果我们在任一位置遇到错误,我们会记录一些内容。在嵌套的情况下,我们只是将 Regkey 的名称记录到“softLog.log”中,而在外部的情况下,我们只是将一个错误记录到“errors.log”中。最后,我们通过关闭文件进行清理。

    下面是我在 Windows XP 机器上运行这个脚本时得到的部分示例:

    These subkeys are found under "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall"

    显示名称:Windows 驱动程序包-Garmin(grmnusb)Garmin Devices(03/08/2007 2 . 2 . 1 . 0)
    Regkey:45a 7283175 c 62 fac 673 f 913 C1 f 532 c 5361 f 97841

    Regkey: AddressBook

    显示名称:Adobe Flash Player 10 ActiveX
    Regkey:Adobe Flash Player ActiveX

    显示名称:Adobe Flash Player 10 插件
    Regkey: Adobe Flash Player 插件

    显示名称:Python 2.4 ado db-2.00
    Regkey:ado db-py 2.4

    显示名称:代理搜掠
    Regkey:代理搜掠

    显示名称:亚马逊游戏&软件下载器
    Regkey:亚马逊游戏&软件下载器 _ is1

    显示名称:亚马逊 MP3 下载器 1.0.3
    Regkey:亚马逊 MP3 下载器

    显示名称:ZoneAlarm Spy Blocker Toolbar
    Regkey:Ask Toolbar _ is1

    显示名称:Aspell 英语词典-0.50-2
    Regkey: Aspell 英语词典 _ is1

    现在你知道如何提取安装在你的 Windows 系统上的大部分软件了。我主要在使用 Python 2.5 的 Windows XP 上测试了这一点,但它应该也能在 Windows Vista 和 7 上运行。Windows 7 和 Vista 通常会强制默认用户以比 XP 更低的权限运行,因此您可能需要以管理员身份或模拟管理员身份运行此脚本。玩得开心!

    烧瓶 101:添加数据库

    原文:https://www.blog.pythonlibrary.org/2017/12/12/flask-101-adding-a-database/

    上次我们学习了如何安装烧瓶。在这篇文章中,我们将学习如何添加一个数据库到我们的音乐数据网站。您可能还记得,Flask 是一个微型网络框架。这意味着它不像 Django 那样带有对象关系映射器(ORM)。如果您想要添加数据库交互性,那么您需要自己添加或者安装一个扩展。我个人喜欢 SQLAlchemy ,所以我认为有一个现成的扩展可以将 SQLAlchemy 添加到 Flask 中,这个扩展叫做 Flask-SQLAlchemy ,这很好。

    要安装 Flask-SQLAlchemy,只需要使用 pip。在运行以下内容之前,请确保您处于我们在本系列第一部分中创建的激活的虚拟环境中,否则您将最终将扩展安装到您的基本 Python 而不是您的虚拟环境中:

    pip install flask-sqlalchemy

    现在我们已经安装了 Flask-SQLAlchemy 及其依赖项,我们可以开始创建数据库了!

    创建数据库

    用 SQLAlchemy 创建数据库实际上非常容易。SQLAlchemy 支持几种不同的数据库操作方式。我最喜欢的是使用它的声明性语法,允许您创建模拟数据库本身的类。所以在这个例子中我会用到它。我们也将使用 SQLite 作为我们的后端,但是如果我们想的话,我们可以很容易地将后端更改为其他东西,如 MySQL 或 Postgres。

    首先,我们将看看如何使用普通的 SQLAlchemy 创建数据库文件。然后我们将创建一个单独的脚本,它使用稍微不同的 Flask-SQLAlchemy 语法。将以下代码放入名为 db_creator.py 的文件中

    # db_creator.py from sqlalchemy import create_engine, ForeignKey from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, backref engine = create_engine('sqlite:///mymusic.db', echo=True) Base = declarative_base() class Artist(Base): __tablename__ = "artists" id = Column(Integer, primary_key=True) name = Column(String) def __repr__(self): return "{}".format(self.name) class Album(Base): """""" __tablename__ = "albums" id = Column(Integer, primary_key=True) title = Column(String) release_date = Column(String) publisher = Column(String) media_type = Column(String) artist_id = Column(Integer, ForeignKey("artists.id")) artist = relationship("Artist", backref=backref( "albums", order_by=id)) # create tables Base.metadata.create_all(engine)

    对于使用 Python 的人来说,这段代码的第一部分应该非常熟悉,因为我们在这里所做的只是从 SQLAlchemy 导入一些我们需要的片段,以使代码的其余部分工作。然后我们创建 SQLAlchemy 的引擎对象,它基本上将 Python 连接到选择的数据库。在本例中,我们连接到 SQLite 并创建一个文件,而不是在内存中创建数据库。我们还创建了一个“基类”,我们可以用它来创建实际定义数据库表的声明类定义。

    接下来的两个类定义了我们关心的表,即艺术家专辑。你会注意到我们通过 tablename 类属性来命名表格。我们还创建表的列,并根据需要设置它们的数据类型。Album 类有点复杂,因为我们设置了与 Artist 表的外键关系。你可以在我以前的 SQLAlchemy 教程中阅读更多关于这是如何工作的,或者如果你想要更深入的细节,那么查看写得很好的文档

    当您运行上面的代码时,您应该在终端中看到类似这样的内容:

    2017-12-08 18:36:43,290 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 2017-12-08 18:36:43,291 INFO sqlalchemy.engine.base.Engine () 2017-12-08 18:36:43,292 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 2017-12-08 18:36:43,292 INFO sqlalchemy.engine.base.Engine () 2017-12-08 18:36:43,294 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("artists") 2017-12-08 18:36:43,294 INFO sqlalchemy.engine.base.Engine () 2017-12-08 18:36:43,295 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("albums") 2017-12-08 18:36:43,295 INFO sqlalchemy.engine.base.Engine () 2017-12-08 18:36:43,296 INFO sqlalchemy.engine.base.Engine CREATE TABLE artists ( id INTEGER NOT NULL, name VARCHAR, PRIMARY KEY (id) 2017-12-08 18:36:43,296 INFO sqlalchemy.engine.base.Engine () 2017-12-08 18:36:43,315 INFO sqlalchemy.engine.base.Engine COMMIT 2017-12-08 18:36:43,316 INFO sqlalchemy.engine.base.Engine CREATE TABLE albums ( id INTEGER NOT NULL, title VARCHAR, release_date DATE, publisher VARCHAR, media_type VARCHAR, artist_id INTEGER, PRIMARY KEY (id), FOREIGN KEY(artist_id) REFERENCES artists (id) 2017-12-08 18:36:43,316 INFO sqlalchemy.engine.base.Engine () 2017-12-08 18:36:43,327 INFO sqlalchemy.engine.base.Engine COMMIT

    现在让我们在烧瓶中完成所有这些工作!

    使用烧瓶-SQLAlchemy

    当我们使用 Flask-SQLAlchemy 时,我们需要做的第一件事是创建一个简单的应用程序脚本。我们就叫它 app.py 。将下面的代码放到这个文件中,并保存到 musicdb 文件夹中。

    # app.py from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mymusic.db' app.secret_key = "flask rocks!" db = SQLAlchemy(app)

    在这里,我们创建 Flask 应用程序对象,并告诉它 SQLAlchemy 数据库文件应该放在哪里。我们还设置了一个简单的密钥,并创建了一个 db 对象,允许我们将 SQLAlchemy 集成到 Flask 中。接下来,我们需要创建一个 models.py 文件,并将其保存到 musicdb 文件夹中。完成后,向其中添加以下代码:

    # models.py from app import db class Artist(db.Model): __tablename__ = "artists" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String) def __repr__(self): return "".format(self.name) class Album(db.Model): """""" __tablename__ = "albums" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) release_date = db.Column(db.String) publisher = db.Column(db.String) media_type = db.Column(db.String) artist_id = db.Column(db.Integer, db.ForeignKey("artists.id")) artist = db.relationship("Artist", backref=db.backref( "albums", order_by=id), lazy=True)

    您会注意到 Flask-SQLAlchemy 并不需要所有的导入,就像普通的 SQLAlchemy 所需要的那样。我们所需要的是我们在应用程序脚本中创建的 db 对象。然后,我们只需在原始 SQLAlchemy 代码中使用的所有类前加上“db”。您还会注意到,它已经被预定义为 db,而不是创建一个基类。型号

    最后,我们需要创建一种初始化数据库的方法。您可以将它放在几个不同的地方,但我最终创建了一个名为 db_setup.py 的文件,并添加了以下内容:

    # db_setup.py from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base engine = create_engine('sqlite:///mymusic.db', convert_unicode=True) db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() Base.query = db_session.query_property() def init_db(): import models Base.metadata.create_all(bind=engine)

    这段代码将用您在模型脚本中创建的表初始化数据库。为了进行初始化,让我们编辑掉上一篇文章中的 test.py 脚本:

    # test.py from app import app from db_setup import init_db init_db() @app.route('/') def test(): return "Welcome to Flask!" if __name__ == '__main__': app.run()

    这里我们只是导入了我们的 app 对象和 init_db 函数。然后我们立即调用 init_db 函数。要运行这段代码,您只需在终端的 musicdb 文件夹中运行以下命令:

    FLASK_APP=test.py flask run

    当您运行这个命令时,您不会看到我们前面看到的 SQLAlchemy 输出。相反,您将只看到一些打印出来的信息,说明您的 Flask 应用程序正在运行。您还会发现在您的 musicdb 文件夹中已经创建了一个 mymusic.db 文件。

    注意, init_db() 调用似乎并不总是有效,所以如果您的 SQLite 数据库文件没有正确生成,您可能需要运行我在上一篇文章中编写的 db_creator 脚本。

    此时,您现在有了一个带有空数据库的 web 应用程序。您不能使用 web 应用程序向数据库添加任何内容,也不能查看数据库中的任何内容。是的,你刚刚创造了一些非常酷的东西,但它对你的用户来说也是完全无用的。在下一篇文章中,我们将学习如何添加一个搜索表单来搜索空数据库中的数据!是的,我的疯狂是有方法的,但是你必须继续阅读这个系列才能弄明白。

    从本文下载一个代码包:flask-music db-part _ ii . tar

    本系列的其他文章

  • 第一部分-101 号烧瓶:入门
  • Flask-SQLAlchemy 网站
  • SQLAlchemy 网站
  • 一个简单的 SQLAlchemy 教程
  • 烧瓶 101:添加、编辑和显示数据

    原文:https://www.blog.pythonlibrary.org/2017/12/14/flask-101-adding-editing-and-displaying-data/

    上次我们学习了如何在我们的音乐数据库应用程序中添加一个搜索表单。当然,我们还没有向数据库中添加任何数据,所以搜索表单实际上并没有做什么,只是告诉我们它没有找到任何东西。在本教程中,我们将学习如何实际添加数据,显示搜索结果和编辑数据库中的条目。

    我们开始吧!

    向数据库添加数据

    让我们从编写新专辑开始吧。打开我们在上一个教程中创建的“forms.py”文件,并添加以下类:

    class AlbumForm(Form): media_types = [('Digital', 'Digital'), ('CD', 'CD'), ('Cassette Tape', 'Cassette Tape') artist = StringField('Artist') title = StringField('Title') release_date = StringField('Release Date') publisher = StringField('Publisher') media_type = SelectField('Media', choices=media_types)

    这定义了创建新相册所需的所有字段。现在我们需要打开“main.py”并添加一个函数来处理当我们想要创建新相册时发生的事情。

    # main.py from app import app from db_setup import init_db, db_session from forms import MusicSearchForm, AlbumForm from flask import flash, render_template, request, redirect from models import Album init_db() @app.route('/', methods=['GET', 'POST']) def index(): search = MusicSearchForm(request.form) if request.method == 'POST': return search_results(search) return render_template('index.html', form=search) @app.route('/results') def search_results(search): results = [] search_string = search.data['search'] if search.data['search'] == '': qry = db_session.query(Album) results = qry.all() if not results: flash('No results found!') return redirect('/') else: # display results return render_template('results.html', table=table) @app.route('/new_album', methods=['GET', 'POST']) def new_album(): Add a new album form = AlbumForm(request.form) return render_template('new_album.html', form=form) if __name__ == '__main__': app.run()

    在这里,我们添加了一个导入来导入顶部的新表单,然后我们创建了一个名为 new_album() 的新函数。然后,我们创建新表单的一个实例,并将其传递给我们的 render_template() 函数,该函数将呈现一个名为“new_album.html”的文件。当然,这个 HTML 文件还不存在,所以这将是我们需要创建的下一个东西。当您保存这个新的 HTML 文件时,请确保将其保存到“musicdb”文件夹内的“templates”文件夹中。

    创建“new_album.html”后,向其中添加以下 html:

    <title>New Album - Flask Music Database</title> ## 新相册 {% from "_formhelpers.html" import render_field %} <form method="post"> {{ render_field(form.artist) }} {{ render_field(form.title) }} {{ render_field(form.release_date) }} {{ render_field(form.publisher) }} {{ render_field(form.media_type) }} </form>

    这段代码将呈现表单中的每个字段,它还创建了一个提交按钮,这样我们就可以保存我们的更改。我们需要做的最后一件事是更新我们的“index.html”代码,这样它就有一个链接可以加载我们的新相册页面。基本上,我们需要做的就是添加以下内容:

    New Album

    所以完整的变化看起来是这样的:

    <title>Flask Music Database</title> ## 烧瓶音乐数据库 [新专辑]({{ url_for('.new_album') }}) { % with messages = get _ flash _ messages()% } { % if messages % } * {{消息}} {% endif %} {% endwith %} {% from "_formhelpers.html" import render_field %} <form method="post"> {{ render_field(form.select) }} {{ render_field(form.search) }} </form>

    现在,如果您加载 web 应用程序的主页,它应该是这样的:

    如果你点击“新相册”链接,你应该会在你的浏览器中看到这样的内容:

    现在我们有了一个丑陋但功能强大的新相册表单,但我们实际上并没有让提交按钮工作。这是我们的下一个任务。

    当按下提交按钮时,我们需要新的相册表单来保存数据。但是当你按下提交按钮时会发生什么呢?如果您返回到“new_album.html”文件,您会注意到我们将表单方法设置为 POST。所以我们需要更新 main.py 中的代码,这样它就可以在 POST 上做一些事情。

    为了进行保存,我们需要更新 main.py 中的 new_album() 函数,因此结果如下:

    @app.route('/new_album', methods=['GET', 'POST']) def new_album(): Add a new album form = AlbumForm(request.form) if request.method == 'POST' and form.validate(): # save the album album = Album() save_changes(album, form, new=True) flash('Album created successfully!') return redirect('/') return render_template('new_album.html', form=form)

    现在,当我们发布时,我们创建一个相册实例,并将其与表单对象一起传递给一个 save_changes() 函数。我们还传递一个标志,表明该项目是否是新的。我们将在文章的后面讨论我为什么添加最后一个。不过现在,我们需要创建 save_changes() 函数。将下面的代码保存在 main.py 脚本中。

    def save_changes(album, form, new=False): Save the changes to the database # Get data from form and assign it to the correct attributes # of the SQLAlchemy table object artist = Artist() artist.name = form.artist.data album.artist = artist album.title = form.title.data album.release_date = form.release_date.data album.publisher = form.publisher.data album.media_type = form.media_type.data if new: # Add the new album to the database db_session.add(album) # commit the data to the database db_session.commit()

    这里,我们从表单中提取数据,并相应地将其分配给相册对象的属性。您还会注意到,我们需要创建一个艺术家实例来将艺术家正确地添加到相册中。如果不这样做,将会得到一个与 SQLAlchemy 相关的错误。这里使用新参数向数据库添加新记录。

    下面是我做的一个测试:

    一旦项目保存,它应该带你回到网站的主页。需要注意的一点是,我没有在数据库中做任何检查来防止用户多次保存一个条目。如果你想接受挑战,这是你可以自己添加的。无论如何,当我测试这个的时候,我提交了相同的条目几次,所以当我搜索的时候,我应该会得到相同条目的多个条目。如果您现在尝试进行搜索,您将会看到一个错误,因为我们还没有创建结果页面。

    让我们接着做吧!

    显示搜索结果

    我更喜欢表格化的结果,这需要使用表格。您可以下载另一个名为烧瓶表的烧瓶扩展,而不是摆弄 HTML 表元素。要安装它,只需像这样使用 pip:

    pip install flask_table

    现在我们已经安装了 Flask 表,我们需要创建一个表定义。让我们创建一个名为“tables.py”的文件,并将其保存在 musicdb 文件夹中。在编辑器中打开它,并添加以下代码:

    from flask_table import Table, Col class Results(Table): id = Col('Id', show=False) artist = Col('Artist') title = Col('Title') release_date = Col('Release Date') publisher = Col('Publisher') media_type = Col('Media')

    当您定义表类时,您会希望使类属性与将传递给它的对象中的属性具有相同的名称。在本例中,我使用了 Album 类中的属性。现在我们只需要创建一个results.html文件,并将其保存到模板文件夹中。该文件中应该包含以下内容:

    <title>Search Results - Flask Music Database</title> {{ table }}

    正如您所看到的,我们需要做的只是添加一个 title 元素,这实际上是可选的,并在 Jinja 中添加一个 table 对象。

    最后,我们需要更新我们的 main.py 中的搜索功能,以使用一个表:

    @app.route('/results') def search_results(search): results = [] search_string = search.data['search'] if search.data['search'] == '': qry = db_session.query(Album) results = qry.all() if not results: flash('No results found!') return redirect('/') else: # display results table = Results(results) table.border = True return render_template('results.html', table=table)

    现在,当您使用空字符串运行搜索时,您应该会看到类似这样的内容:

    是的,它很简单,但是它很有效,你现在可以看到你数据库中的所有东西。

    编辑数据库中的数据

    我们需要涉及的最后一项是如何编辑数据库中的数据。最简单的方法之一是搜索一个条目,并为用户添加一种方法来编辑找到的条目。打开 tables.py 文件并添加一个 LinkCol :

    from flask_table import Table, Col, LinkCol class Results(Table): id = Col('Id', show=False) artist = Col('Artist') title = Col('Title') release_date = Col('Release Date') publisher = Col('Publisher') media_type = Col('Media') edit = LinkCol('Edit', 'edit', url_kwargs=dict(id='id'))

    LinkCol 将列名作为一个字符串以及端点应该是什么。端点是单击链接时将调用的函数。我们还传递条目的 id,以便在数据库中查找它(即 url_kwargs 参数)。现在我们需要用一个名为 edit() 的函数来更新我们的 main.py 文件:

    @app.route('/item/', methods=['GET', 'POST']) def edit(id): qry = db_session.query(Album).filter( Album.id==id) album = qry.first() if album: form = AlbumForm(formdata=request.form, obj=album) if request.method == 'POST' and form.validate(): # save edits save_changes(album, form) flash('Album updated successfully!') return redirect('/') return render_template('edit_album.html', form=form) else: return 'Error loading #{id}'.format(id=id)

    这里要注意的第一点是,我们为 URL 设置了一个自定义路由,它使用我们传递给它的 id 来创建一个惟一的 URL。接下来,我们在数据库中搜索有问题的 id。如果我们找到了 id,那么我们就可以使用之前创建的表单来创建表单。但是这次我们传递给它的是相册对象,所以表单已经预先填充了数据,这样我们就有东西可以编辑了。如果用户按下这个页面上的 Submit 按钮,那么它会将条目保存到数据库中,并向用户显示一条消息。如果我们传入一个错误的 id,那么将向用户显示一条消息。

    我们还需要在我们的模板文件夹中创建一个 edit_album.html 文件。下面是您需要放入该文件的 HTML:

    <title>Edit Album - Flask Music Database</title> ## 编辑相册 {% from "_formhelpers.html" import render_field %} <form method="post"> {{ render_field(form.artist) }} {{ render_field(form.title) }} {{ render_field(form.release_date) }} {{ render_field(form.publisher) }} {{ render_field(form.media_type) }} </form>

    现在,当我们运行之前的空搜索时,您应该会看到:

    让我们点击第一行的编辑链接:

    在这里,我编辑页面上的大多数字段。然后我点击提交,得到这个:

    据推测,该条目已根据我的更改进行了更新。要进行验证,请尝试运行另一个空搜索:

    看起来没错,所以现在我们已经完成了编辑功能!

    此时,您应该能够向数据库添加条目,显示所有条目并编辑这些条目。缺少的主要项目是如何过滤搜索结果,以便它实际上寻找您想要的搜索词,而不是总是返回数据库中的所有内容。我们可能还应该添加从数据库中删除项目的功能。这些是我们将在下一篇文章中探讨的主题。现在,享受快乐的编码吧!

    从本文下载一个代码包:flask _ musicdb _ part _ iv . tar或者在 Github 上克隆它

    本系列的其他文章

  • 第一部分-101 号烧瓶:入门
  • 第二部分 -烧瓶 101: 添加数据库
  • 第三部分 -烧瓶 101: 如何添加搜索表单
  • Flask 101:过滤搜索和删除数据

    原文:https://www.blog.pythonlibrary.org/2017/12/15/flask-101-filtering-searches-and-deleting-data/

    上次我们让基于 Flask 的音乐数据库应用程序部分运行。它现在可以向数据库中添加数据,编辑所述数据,还可以显示数据库中的所有内容。但是我们没有介绍如何使用用户的过滤器选择(艺术家、专辑名称或出版商名称)和搜索字符串来过滤数据。我们也没有讨论如何从数据库中删除条目。这是本文的双重目标。

    过滤搜索结果

    使用 SQLAlchemy(通过 Flask-SQLAlchemy)过滤搜索结果实际上非常容易。您需要做的就是创建一些非常简单的查询对象。打开我们上次编辑的 main.py 文件,用下面的代码版本替换 search_results() 函数:

    @app.route('/results') def search_results(search): results = [] search_string = search.data['search'] if search_string: if search.data['select'] == 'Artist': qry = db_session.query(Album, Artist).filter( Artist.id==Album.artist_id).filter( Artist.name.contains(search_string)) results = [item[0] for item in qry.all()] elif search.data['select'] == 'Album': qry = db_session.query(Album).filter( Album.title.contains(search_string)) results = qry.all() elif search.data['select'] == 'Publisher': qry = db_session.query(Album).filter( Album.publisher.contains(search_string)) results = qry.all() else: qry = db_session.query(Album) results = qry.all() else: qry = db_session.query(Album) results = qry.all() if not results: flash('No results found!') return redirect('/') else: # display results table = Results(results) table.border = True return render_template('results.html', table=table)

    这里我们添加了一个有点长的条件 if 语句。我们首先检查用户是否在搜索文本框中输入了搜索字符串。如果是,那么我们检查用户从组合框中选择了哪个过滤器:艺术家、专辑或出版商。根据用户的选择,我们创建一个定制的 SQLAlchemy 查询。如果用户没有输入搜索词,或者如果我们的 web 应用程序搞混了,不能识别用户的过滤器选择,那么我们对整个数据库进行查询。如果数据库变得非常大,那么在生产中可能不应该这样做,然后对数据库进行查询会导致您的 web 应用程序没有响应。您可以简单地向表单的输入添加一些验证来防止这种情况发生(即不要使用空的搜索字符串查询数据库)。然而,我们不会在这里涵盖这一点。

    无论如何,继续尝试这段代码,看看它是如何工作的。我尝试了几个不同的搜索词,它似乎对我的用例很有效。您会注意到,我只是使用了 contains 方法,这对于在表的列中查找字符串非常有用。你可以随时索引你的数据库,并对其进行其他各种优化,包括让这些查询更加集中,如果你愿意的话。请随意使用这段代码,看看如何改进它。

    现在我们将继续学习如何从数据库中删除项目!

    有时候,当你在数据库中输入一些东西,你只是想删除。从技术上讲,你可以使用我们的编辑功能来编辑条目,但有时你只需要永久清除数据。因此,我们需要做的第一件事是在结果表中添加一个 Delete 列。您将希望打开 tables.py 并将一个新的 LinkCol 实例添加到 Results 类中:

    from flask_table import Table, Col, LinkCol class Results(Table): id = Col('Id', show=False) artist = Col('Artist') title = Col('Title') release_date = Col('Release Date') publisher = Col('Publisher') media_type = Col('Media') edit = LinkCol('Edit', 'edit', url_kwargs=dict(id='id')) delete = LinkCol('Delete', 'delete', url_kwargs=dict(id='id'))

    正如我们在创建用于编辑数据的链接时所做的那样,我们添加了一个用于删除数据的新链接。您会注意到第二个参数,也就是端点,指向一个删除函数。所以下一步是打开我们的 main.py 文件并添加所说的 delete() 函数:

    @app.route('/delete/', methods=['GET', 'POST']) def delete(id): Delete the item in the database that matches the specified id in the URL qry = db_session.query(Album).filter( Album.id==id) album = qry.first() if album: form = AlbumForm(formdata=request.form, obj=album) if request.method == 'POST' and form.validate(): # delete the item from the database db_session.delete(album) db_session.commit() flash('Album deleted successfully!') return redirect('/') return render_template('delete_album.html', form=form) else: return 'Error deleting #{id}'.format(id=id)

    这段代码实际上非常类似于上一篇文章中的 edit()函数。你会注意到我们更新了路线。所以没有指定'/item/<id>',而是做成'/delete/<id>'。这使得两个函数之间的 URL 不同,所以当链接被点击时,它们实际上执行正确的函数。另一个区别是,我们不需要在这里创建一个特殊的保存函数。我们只是直接引用 db_session 对象,并告诉它如果在数据库中找到相册就删除它,然后提交我们的更改。

    如果您运行该代码,在执行空字符串搜索时,您应该会看到如下内容:

    我们需要做的最后一件事是创建上面提到的 delete_album.html 。让我们创建该文件,并将其保存到我们的模板文件夹中。一旦创建了该文件,只需添加以下内容:

    <title>Delete Album - Flask Music Database</title> ## 删除相册 {% from "_formhelpers.html" import render_field %} <form method="post"> {{ render_field(form.artist) }} {{ render_field(form.title) }} {{ render_field(form.release_date) }} {{ render_field(form.publisher) }} {{ render_field(form.media_type) }} </form>

    这段代码将呈现我们的表单,向用户显示他们正在删除的内容。让我们尝试单击表中一个副本的删除链接。您应该会看到这样一个屏幕:

    当您按下“删除”按钮时,它会将您重定向到主页,在那里您会看到一条消息,说明该项目已成功删除:

    要验证删除是否有效,只需再进行一次空字符串搜索。您的结果应该在表格中少显示一项:

    现在,您应该知道如何对数据库中的搜索结果进行一些基本的过滤。您还学习了如何在 Flask 应用程序中成功地从数据库中删除项目。代码中有几个地方可以使用重构和常规清理。您还可以在应用程序中添加一些 CSS 样式,使其看起来更漂亮。这些是我留给读者的练习。玩代码玩得开心点,试试 Flask 吧。这是一个简洁的 web 框架,非常值得一看!

    从本文下载一段代码: flask_musicdb_v.tar

    本系列的其他文章

  • 第一部分-101 号烧瓶:入门
  • 第二部分 -烧瓶 101: 添加数据库
  • 第三部分 -烧瓶 101: 如何添加搜索表单
  • 第四部分 -烧瓶 101: 添加、编辑和显示数据
  • 烧瓶 101:开始

    原文:https://www.blog.pythonlibrary.org/2017/12/12/flask-101-getting-started/

    Flask 101 系列是我学习 Python 的 Flask 微框架的尝试。对于那些没听说过的人来说,Flask 是用 Python 创建 web 应用程序的微型 web 框架。根据他们的网站, Flask基于 Werkzeug,Jinja 2 和 good intentions 。对于这一系列文章,我想创建一个 web 应用程序,它将做一些有用的事情,而不会太复杂。所以为了我的学习理智,我决定创建一个简单的 web 应用程序,我可以用它来存储我的音乐库的信息。

    在多篇文章中,您将看到这一旅程是如何展开的。

    要开始使用 Flask,您需要安装它。我们将为这一系列教程创建一个虚拟环境,因为我们将需要添加许多其他 Flask 依赖项,而且大多数人可能不想用大量他们可能最终不会使用的 cruft 来污染他们的主 Python 安装。所以在我们安装 Flask 之前,让我们使用 virtualenv 创建一个虚拟环境。如果你想使用 virtualenv,那么我们需要安装 pip:

    pip install virtualenv

    现在我们已经安装了,我们可以创建我们的虚拟环境。在您的本地系统上找到一个您想要存储 web 应用程序的位置。然后打开终端并运行以下命令:

    virtualenv musicdb

    在 Windows 上,您可能必须给出 virtualenv 的完整路径,通常类似于C:\ python 36 \ Scripts \ virtualenv . exe

    注意,从 Python 3.3 开始,还可以使用 Python 内置的 venv 模块来创建虚拟环境,而不是使用 virtualenv。当然,virtualenv 包可以安装在 Python 3 中,所以要用哪个由你决定。它们的工作方式非常相似。

    设置好虚拟环境后,您需要激活它。为此,您需要将终端中的目录更改为您刚刚使用“cd”命令创建的文件夹:

    cd musicdb

    如果您在 Linux 或 Mac OS 上,您应该运行以下程序:

    source bin/activate

    Windows 有点不同。您仍然需要“cd”到您的文件夹中,但是要运行的命令是这样的:

    Scripts/activate

    有关激活和停用虚拟环境的更多详细信息,请查看用户指南

    您可能已经注意到,当您创建您的虚拟环境时,它复制到您的 Python 可执行文件以及 pip 中。这意味着您现在可以使用 pip 将软件包安装到您的虚拟环境中,这也是许多人喜欢虚拟环境的原因。一旦虚拟环境被激活,您应该看到您的终端已经更改为将虚拟环境的名称添加到终端的提示符前面。下面是一个使用 Python 2.7 的截图示例:

    现在我们准备安装 Flask!

    开始使用 Flask

    使用 pip 安装程序很容易安装 Flask。你可以这样做:

    pip install flask

    这个命令将安装 Flask 和它需要的任何依赖项。这是我收到的输出:

    Collecting flask Downloading Flask-0.12.2-py2.py3-none-any.whl (83kB) 100% |████████████████████████████████| 92kB 185kB/s Collecting itsdangerous>=0.21 (from flask) Downloading itsdangerous-0.24.tar.gz (46kB) 100% |████████████████████████████████| 51kB 638kB/s Collecting Jinja2>=2.4 (from flask) Downloading Jinja2-2.10-py2.py3-none-any.whl (126kB) 100% |████████████████████████████████| 133kB 277kB/s Collecting Werkzeug>=0.7 (from flask) Downloading Werkzeug-0.12.2-py2.py3-none-any.whl (312kB) 100% |████████████████████████████████| 317kB 307kB/s Collecting click>=2.0 (from flask) Downloading click-6.7-py2.py3-none-any.whl (71kB) 100% |████████████████████████████████| 71kB 414kB/s Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->flask) Building wheels for collected packages: itsdangerous Running setup.py bdist_wheel for itsdangerous ... done Stored in directory: /home/mdriscoll/.cache/pip/wheels/fc/a8/66/24d655233c757e178d45dea2de22a04c6d92766abfb741129a Successfully built itsdangerous Installing collected packages: itsdangerous, MarkupSafe, Jinja2, Werkzeug, click, flask Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.12.2 click-6.7 flask-0.12.2 itsdangerous-0.24

    现在让我们写一些简单的东西来证明 Flask 工作正常。将下面的代码保存在我们之前创建的 musicdb 文件夹中。

    # test.py from flask import Flask app = Flask(__name__) @app.route('/') def test(): return "Welcome to Flask!"

    这些代码所做的就是导入 Flask 类并创建一个我们称之为 app 的实例。然后,我们为我们网站的主页(又名根或索引)设置默认路径。这是通过下面的装饰器完成的: @app.route('/') 。最后,我们创建一个函数,只返回一个字符串。

    当这段代码在 Flask 中运行时,您将能够导航到您的新 web 应用程序的主页并看到该文本。这就引出了我们如何运行这段代码。在您的终端中,确保您在您的 musicdb 文件夹中。然后在终端中运行以下命令:

    FLASK_APP=test.py flask run

    当您运行这个命令时,您应该在终端中看到类似这样的内容:

    * Serving Flask app "test" * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

    现在你只需要打开一个浏览器,比如 Chrome 或者 Firefox,去上面提到的网址: http://127.0.0.1:5000/ 。以下是我在 Chrome 中访问该网址时得到的结果:

    至此,您应该能够启动并运行 Flask 的工作版本。你可以用你现在拥有的东西做一些非常基本的网络应用。在本系列的下一篇文章中,我们将看看如何为我们的 web 应用程序添加数据库支持。

    本系列的其他文章

  • 第二部分:烧瓶 101 - 添加数据库
  • Flask 101:如何添加搜索表单

    原文:https://www.blog.pythonlibrary.org/2017/12/13/flask-101-how-to-add-a-search-form/

    在上一篇文章中,我们向 Flask web 应用程序添加了一个数据库,但是没有办法向数据库添加任何东西。我们也没有办法查看任何东西,所以基本上我们最终拥有了一个非常无用的 web 应用程序。本文将花时间教你如何做到以下几点:

  • 创建一个表单来添加数据到我们的数据库
  • 使用表单编辑我们数据库中的数据
  • 创建数据库中内容的某种视图
  • 一旦你弄清楚要安装什么扩展,向 Flask 添加表单也很容易。我听说过 WTForms 的优点,所以我将在本教程中使用它。要安装 WTForms,您需要安装 Flask-WTF 。安装 Flask-WTF 相当容易;只要打开你的终端,激活我们在第一教程中设置的虚拟环境。然后使用 pip 运行以下命令:

    pip install Flask-WTF

    这将把 WTForms 和 Flask-WTF(以及任何依赖项)安装到 web 应用程序的虚拟环境中。

    提供 HTML 文件

    最初当我开始这个系列时,我在 web 应用程序的索引页面上提供的只是一个字符串。我们可能应该稍微修饰一下,使用一个真正的 HTML 文件。在“musicdb”文件夹中创建一个名为“templates”的文件夹。现在,在“templates”文件夹中创建一个名为“index.html”的文件,并将以下内容放入其中:

    <title>Flask Music Database</title> ## 烧瓶音乐数据库

    现在,在我们更新 web 应用程序代码之前,让我们创建一个搜索表单来过滤音乐数据库的结果。

    添加搜索表单

    使用数据库时,您需要一种在其中搜索项目的方法。幸运的是,用 WTForms 创建搜索表单非常容易。创建一个名为“forms.py”的 Python 脚本,保存到“musicdb”文件夹,内容如下:

    # forms.py from wtforms import Form, StringField, SelectField class MusicSearchForm(Form): choices = [('Artist', 'Artist'), ('Album', 'Album'), ('Publisher', 'Publisher')] select = SelectField('Search for music:', choices=choices) search = StringField('')

    这里我们只是从 wtforms 模块导入我们需要的项目,然后我们子类化forms类。在我们的子类中,我们创建了一个选择字段(一个组合框)和一个字符串字段。这使我们能够将搜索过滤到艺术家、专辑或出版商类别,并输入要搜索的字符串。

    现在我们准备更新我们的主应用程序。

    更新主应用程序

    让我们将 web 应用程序的脚本从“test.py”重命名为“main.py ”,并对其进行更新,如下所示:

    # main.py from app import app from db_setup import init_db, db_session from forms import MusicSearchForm from flask import flash, render_template, request, redirect from models import Album init_db() @app.route('/', methods=['GET', 'POST']) def index(): search = MusicSearchForm(request.form) if request.method == 'POST': return search_results(search) return render_template('index.html', form=search) @app.route('/results') def search_results(search): results = [] search_string = search.data['search'] if search.data['search'] == '': qry = db_session.query(Album) results = qry.all() if not results: flash('No results found!') return redirect('/') else: # display results return render_template('results.html', results=results) if __name__ == '__main__': app.run()

    我们修改了 index() 函数,使其可以处理 POST 和 GET 请求,并告诉它加载我们的 MusicSearchForm。您会注意到,当您第一次加载 web 应用程序的索引页面时,它将执行 GET,index()函数将呈现我们刚刚创建的 index.html。当然,我们实际上还没有将表单添加到我们的 index.html 中,所以搜索表单还不会出现。

    **我们还添加了一个 search_results() 来处理非常基本的搜索。然而,在我们真正实现显示结果的方法之前,这个函数不会被调用。因此,让我们继续让搜索表单对我们的用户可见。

    在我学习如何用 wtforms 创建表单的时候, Flask-WTF 网站推荐用一个叫做“_formhelpers.html”的宏创建一个模板。继续创建一个同名文件,并将其保存到您的“模板”文件夹中。然后将以下内容添加到该文件中:

    {% macro render_field(field) %}

    {{ field.label }}

    {{ field(**kwargs)|safe }} {% if field.errors %}

  • {{错误}}
  • {% endmacro %}

    这个语法可能看起来有点奇怪,因为它显然不仅仅是 HTML。这其实就是 Jinja2 语法,是 Flask 使用的模板语言。基本上,无论你在哪里看到弯弯曲曲的大括号(即{}),你都会看到 Jinja 语法。这里我们传入一个字段对象,并访问它的标签错误属性。请随意查阅文档以获取更多信息。

    现在打开您的“index.html”文件并更新它,使其包含以下内容:

    <title>Flask Music Database</title> ## 烧瓶音乐数据库 {% from "_formhelpers.html" import render_field %} <form method="post"> {{ render_field(form.select) }} {{ render_field(form.search) }} </form>

    本例中的新代码展示了如何将创建的宏导入到另一个 HTML 文件中。接下来,我们将表单方法设置为 post ,并将选择小部件和搜索小部件传递给我们的 render_field 宏。我们还创建了一个带有以下标签的提交按钮:搜索。当您按下搜索按钮时,它会将表单的其他两个字段中的数据发布到它所在的页面,在本例中是我们的index.html或“/”。

    当这种情况发生时,我们的 main.py 脚本中的 index()方法将执行:

    @app.route('/', methods=['GET', 'POST']) def index(): search = MusicSearchForm(request.form) if request.method == 'POST': return search_results(search) return render_template('index.html', form=search)

    你会注意到我们检查它是哪个请求方法,如果是 POST 方法,那么我们调用 search_results() 函数。如果你真的在这个阶段按下搜索按钮,你会收到一个内部服务器错误,因为我们还没有实现“results.html”。无论如何,现在您的 web 应用程序应该是这样的:

    让我们花点时间让结果函数做些有用的事情。

    更新结果功能

    现在我们的数据库中实际上没有任何数据,所以当我们试图查询它时,我们不会得到任何结果。因此,我们需要让我们的 web 应用程序表明没有找到任何结果。为此,我们需要更新“index.html”页面:

    <title>Flask Music Database</title> ## 烧瓶音乐数据库 {% with messages = get_flashed_messages() %} {% if messages %} * {{消息}} {% endif %} {% endwith %} {% from "_formhelpers.html" import render_field %} <form method="post"> {{ render_field(form.select) }} {{ render_field(form.search) }} </form>

    你会注意到新代码是一个新的金贾块。在这里,我们抓取“闪现”的消息并显示它们。现在我们只需要运行 web 应用程序并尝试搜索一些东西。如果一切按计划进行,当您进行搜索时,应该会看到如下内容:

    现在我们有了一个简洁的搜索表单,可以用来搜索我们的数据库,尽管坦白地说,由于我们的数据库目前是空的,它实际上并没有做太多事情。在我们的下一篇文章中,我们将关注最终创建一种向数据库添加数据、显示搜索结果以及编辑数据的方法!

    从本文下载一个代码包:flask _ music dv _ part _ iii . tar

    本系列的其他文章

  • 第一部分-101 号烧瓶:入门
  • 第二部分 -烧瓶 101: 添加数据库
  • Jinja2 网站
  • Flask-WTForms 网站
  • Flask-SQLAlchemy 网站
  • SQLAlchemy 网站
  • 一个简单的 SQLAlchemy 教程**
  • 关于 Python 的免费书籍(和其他免费资源)

    原文:https://www.blog.pythonlibrary.org/2013/07/11/free-books-and-other-free-resources-about-python/

    有些人没有意识到这一点,但是有很多关于 Python 编程语言的免费书籍。是的,有些并不是很好,但是这里有很多非常好的免费资源。在这篇文章中,我们将看看一些免费的书籍和其他资源,你可以使用我最喜欢的编程语言。

    免费 Python 书籍

    我在网上找到的第一本免费的 Python 书籍是马克·皮尔格林的《深入研究 Python》。你可以在该书的网站上免费获得他的书,或者你可以在亚马逊上购买一本。事实上,他的书已经由出版社出版了一段时间。这些链接是这本书的 Python 2.x 版本。Pilgrim 还为 Python 3 写了一个版本,你可以在这里找到。当我学习 Python 的时候,我自己也使用过他的原版在线书籍,并且在必要的时候我仍然会参考它。

    我听说过的另一本书叫做《思考 Python》,作者是艾伦·b·唐尼。你可以在绿茶出版社的网站上查看免费的 PDF 版本。这本书也是由奥赖利出版的,所以你也可以在亚马逊买到。这本书已经在我的阅读清单上了,但是我还没有开始读。然而,大多数以 O'Reilly 品牌推出的 Python 书籍往往都很好,所以我对这本书寄予厚望。在撰写本文时,PDF 版本最后一次更新是在 2013 年 5 月。

    你也可以在作者的网站上找到由 Swaroop C H 编写的一个字节的 Python 。他有几个版本,包括一个死树版本,他似乎在推销自己。他的网站有点令人困惑,因为你需要向下滚动到底部才能找到这本书的链接。这是另一本书,我一直想读,但没有这样做。

    WikiBooks 推出了 3 本涵盖 Python 的在线书籍:

  • Python 2.6 的非程序员教程
  • Python 3 的非程序员教程
  • Python 编程
  • 我对这些不太了解,但是如果你已经读过了,请随意评论它们是否有用。

    阿尔·斯威加特的三本书都是免费的。我读过他的一些书,它们很有趣。他的书是针对初学者的。这是他的书:

  • 用 Python 发明自己的电脑游戏
  • 用 Python 制作游戏& Pygame
  • 用 Python 破解秘密密码
  • Zed Shaw 是一位著名的 Python 程序员,他编写了自己的在线书籍,名为艰难地学习 Python。我听说过很多关于它的好东西,但我自己没有试过。它看起来更像一个在线课程,而不是一本书,但多个网站称它为一本书,所以你去那里。

    你也可以在http://pythonbooks.revolunet.com/找到这些书和一大堆其他免费的书,它们链接到这些书或它们的网站。

    Python 的其他免费资源

    以下是我最喜欢使用的一些 Python 资源:

  • 官方 Python 文档
  • 其他官方文档和链接
  • 本周 Python 模块系列
  • Raymond Hettinger 的博客——这个博客通常面向中高级程序员
  • 以下是我最近发现或听到的一些好消息,或者两者兼而有之:

  • Python 挑战赛
  • 搭便车者的包装指南
  • Python 在代码学院
  • 学习 Python
  • 谷歌的 Python 类
  • 请随意在评论中列出你最喜欢的资源,不管它们是否在这个列表中。

    Webucator 提供的免费 Python 入门课程

    原文:https://www.blog.pythonlibrary.org/2016/02/02/free-intro-to-python-course-from-webucator/

    Webucator 最近联系了我,告诉我他们已经完成了 Python 培训的介绍,他们允许人们在二月份免费参加。本课程由视频、练习、阅读和测验组成。您可以在注册时使用以下代码免费获得它:PYTHON

    我认为他们基于我的上下文管理器文章制作的视频做得很好。

    免费 Python 资源

    原文:https://www.blog.pythonlibrary.org/2017/04/26/free-python-resources/

    现在有很多学习 Python 的免费资源。早在 2013 年,我就写过关于他们中的一些人,但现在比那时更多!在这篇文章中,我想与你分享这些资源。如果我错过了任何对你有帮助的东西,请在评论中链接到它们。

    博客和网站

    当我学习 Python 时,我首先求助的地方之一是官方 Python 文档:

  • Python 2 文档(注:Python 2 寿命终止为 2020 年)
  • Python 3 文档
  • Python 网站上也可以找到很多其他的文档。

    Dan Bader 和一组贡献者写了一些关于真正的 Python 的文章,上面有很多免费和付费的材料。

    多年来,Doug Hellman 一直在制作一个名为 Python 每周模块(PyMOTW)的系列。他现在也有了 Python 3 的系列版本。以下是链接:

  • PyMOTW-2 (Python 2)
  • PyMOTW-3 (Python 3)
  • Python 上有两个有趣的“搭便车”网站,但我认为它们除了名字之外没有任何联系:

  • Python 的指南
  • 搭便车者的打包指南——学习如何打包你的代码并分发它!
  • 如果你喜欢阅读博客,那么 Planet Python 正适合你。Planet Python 基本上是几十个 Python 博客的 RSS 聚合器。你可以在页面左侧看到每个博客的链接。

    如果你从事 web 开发,你应该查看一下 Marko Denic 的网站,获取不是专门针对 Python web 框架的技巧和教程。有关以 Python 为中心的 web 框架的更多信息,请参见以下内容:

  • 亚当·约翰逊的网站
  • 威廉·文森特的网站
  • 科里·斯查费的 YouTube 频道(不仅仅涵盖姜戈)
  • 免费 Python 书籍

    马克·皮尔格林的书在网上已经有十多年了。他创建了两个版本的 Dive Into Python ,一个用于 Python 2,另一个用于 Python 3。我将在这里链接到 Python 3。

    Al Sweigart 出版 Python 书籍也有一段时间了。他最新的 Python 书籍是用 Python 自动化枯燥的东西。这是一本有趣的书,非常值得一读。你可以在他的网站上看到他的其他书。它们都是免费的,但是你也可以购买。

    WikiBooks 有一本 Python 3 的书叫做Python 3 的非程序员教程仍然推荐。

    虽然没看过,但是听说过全栈 Python 不错。

    如果你想学习测试驱动开发,有一本关于服从测试山羊的书。我会注意到这本书非常关注用 Python 进行 web 编程以及如何测试,所以请记住这一点。

    有一本整洁的在线书籍叫做Program Arcade Games with Python 和 Pygame 可以免费获得多种语言版本,这是以前的书籍所不提供的。

    最后,我想我应该提到我自己的书, Python 101 ,这本书可以免费获得,或者在 Leanpub 上付费,或者你可以在这里在线阅读

    还有大量其他关于 Python 的免费资源和书籍。这些只是一个概述。如果你碰巧陷入了这些书籍或资源中,那么你会很高兴地知道,在以下网站上有很多乐于助人的人会回答你的问题:

  • reddit 的学习曲面的子 Reddit
  • comp.lang.python 在谷歌群组上
  • 享受学习 Python 的乐趣。这是一门伟大的语言!

    曼宁出版社的免费 Python 视频

    原文:https://www.blog.pythonlibrary.org/2020/11/24/free-python-videos-from-manning-publications/

    Manning Publications 最近联系我,让我知道他们有一些新的 Python 视频要放在他们的 YouTube 频道上。

    卡尔·奥西波夫云原生机器学习的作者。他创建了一个关于 py torch autogradated 用于深度学习的自动微分的会话:

    https://www.youtube.com/embed/HOWm_C_P4NM?feature=oembed

    Jonathan Rioux 是《使用 Python 和 PySpark 进行数据分析》一书的作者,他在 PySpark 上做了一个讲座,讲述了如何在编写代码之前进行推理,保持数据操作代码整洁,以及对代码性能进行推理。

    https://www.youtube.com/embed/DPGN3CaHyYs?feature=oembed

    注:曼宁出版公司不是这篇文章的赞助商。我只是觉得他们推出新的免费 Python 内容很棒!

    更多 Python 视频,请查看 MouseVsPython YouTube 频道

    Python 函数重载(视频)

    原文:https://www.blog.pythonlibrary.org/2022/05/31/function-overloading-with-python-video/

    在本教程中,您将学习如何使用 Python 及其 functools 模块进行函数重载。

    https://www.youtube.com/embed/2ldqYOfTwtw?feature=oembed

    Python 3-single dispatch 函数重载

    https://www.blog.pythonlibrary.org/2016/02/23/python-3-function-overloading-with-singledispatch/embed/#?secret=sHzLevxuJb#?secret=pUrCSSajj5

    从文件生成对话框

    原文:https://www.blog.pythonlibrary.org/2010/01/20/generating-a-dialog-from-a-file/

    前几天写了一篇关于 wxPython 使用 ConfigObj 的文章。关于这篇文章,我被问到的第一个问题是关于使用配置文件来生成对话框。我认为这是一个有趣的想法,所以我尝试实现这个功能。我个人认为,使用 XRC 创建对话框并使用 ConfigObj 帮助管理以这种方式加载的对话框文件可能会更好。然而,这对我来说是一个有趣的练习,我想你也会发现它很有启发性。

    免责声明:这是一个总的黑客,可能会或可能不会满足您的需求。我给出了各种扩展示例的建议,所以我希望这有所帮助!

    既然已经解决了这个问题,让我们创建一个超级简单的配置文件。为了方便起见,我们称它为“config.ini ”:

    config . ini

    [Labels] server = Update Server: username = Username: password = Password: update interval = Update Interval: agency = Agency Filter: filters = "" [Values] server = http://www.someCoolWebsite/hackery.php username = "" password = "" update interval = 2 agency_choices = Include all agencies except, Include all agencies except, Exclude all agencies except filters = ""

    这个配置文件有两个部分:标签和值。标签部分有我们将用来创建 wx 的标签。StaticText 控件。部分有一些样本值,我们可以将它们用于相应的文本控件和一个组合框。请注意,机构选择字段是一个列表。列表中的第一项将是组合框中的默认选项,另外两项是小部件的实际内容。

    现在,让我们来看看构建该对话框的代码:

    偏好 sDlg.py

    import configobj import wx ######################################################################## class PreferencesDialog(wx.Dialog): Creates and displays a preferences dialog that allows the user to change some settings. #---------------------------------------------------------------------- def __init__(self): Initialize the dialog wx.Dialog.__init__(self, None, wx.ID_ANY, 'Preferences', size=(550,300)) self.createWidgets() #---------------------------------------------------------------------- def createWidgets(self): Create and layout the widgets in the dialog lblSizer = wx.BoxSizer(wx.VERTICAL) valueSizer = wx.BoxSizer(wx.VERTICAL) btnSizer = wx.StdDialogButtonSizer() colSizer = wx.BoxSizer(wx.HORIZONTAL) mainSizer = wx.BoxSizer(wx.VERTICAL) iniFile = "config.ini" self.config = configobj.ConfigObj(iniFile) labels = self.config["Labels"] values = self.config["Values"] self.widgetNames = values font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD) for key in labels: value = labels[key] lbl = wx.StaticText(self, label=value) lbl.SetFont(font) lblSizer.Add(lbl, 0, wx.ALL, 5) for key in values: print key value = values[key] if isinstance(value, list): default = value[0] choices = value[1:] cbo = wx.ComboBox(self, value=value[0], size=wx.DefaultSize, choices=choices, style=wx.CB_DROPDOWN|wx.CB_READONLY, name=key) valueSizer.Add(cbo, 0, wx.ALL, 5) else: txt = wx.TextCtrl(self, value=value, name=key) valueSizer.Add(txt, 0, wx.ALL|wx.EXPAND, 5) saveBtn = wx.Button(self, wx.ID_OK, label="Save") saveBtn.Bind(wx.EVT_BUTTON, self.onSave) btnSizer.AddButton(saveBtn) cancelBtn = wx.Button(self, wx.ID_CANCEL) btnSizer.AddButton(cancelBtn) btnSizer.Realize() colSizer.Add(lblSizer) colSizer.Add(valueSizer, 1, wx.EXPAND) mainSizer.Add(colSizer, 0, wx.EXPAND) mainSizer.Add(btnSizer, 0, wx.ALL | wx.ALIGN_RIGHT, 5) self.SetSizer(mainSizer) #---------------------------------------------------------------------- def onSave(self, event): Saves values to disk for name in self.widgetNames: widget = wx.FindWindowByName(name) if isinstance(widget, wx.ComboBox): selection = widget.GetValue() choices = widget.GetItems() choices.insert(0, selection) self.widgetNames[name] = choices else: value = widget.GetValue() self.widgetNames[name] = value self.config.write() self.EndModal(0) ######################################################################## class MyApp(wx.App): """""" #---------------------------------------------------------------------- def OnInit(self): """Constructor""" dlg = PreferencesDialog() dlg.ShowModal() dlg.Destroy() return True if __name__ == "__main__": app = MyApp(False) app.MainLoop()

    首先,我们创建 wx 的子类。对话框及其所有的 createWidgets 方法。这个方法将读取我们的配置文件,并使用其中的数据来创建显示。一旦配置被读取,我们循环遍历标签部分中的键,并根据需要创建静态文本控件。接下来,我们遍历另一部分中的值,并使用一个条件来检查小部件的类型。在这种情况下,我们只关心 wx。这就是 ConfigObj 有帮助的地方,因为它实际上可以对我们的配置文件中的一些条目进行类型转换。如果您使用 configspec,您可以得到更细粒度的,这可能是您想要扩展本教程的方式。注意,对于文本控件和组合框,我设置了 name 字段。这对保存数据很重要,我们一会儿就会看到。

    无论如何,在这两个循环中,我们使用垂直的 BoxSizers 来存放我们的小部件。对于您的专用接口,您可能希望将其替换为 GridBagSizer 或 FlexGridSizer。我个人真的很喜欢 BoxSizers。在 Steven Sproat ( Whyteboard )的建议下,我还为按钮使用了 StdDialogButtonSizer。如果您为按钮使用正确的标准 id,这个 sizer 会以跨平台的方式将它们按正确的顺序放置。它相当方便,虽然它不需要很多参数。还要注意,这个 sizer 的文档暗示您可以指定方向,但实际上您不能。我和 Robin Dunn(wxPython 的创建者)在 IRC 上讨论了这个问题,他说 epydoc 抓取了错误的文档字符串。

    我们关心的下一个方法是 onSave 。这里是我们保存用户输入内容的地方。在程序的早些时候,我从配置中获取了小部件的名称,现在我们对它们进行循环。我们叫 wx。FindWindowByName 按名称查找小部件。然后我们再次使用 isinstance 来检查我们有哪种小部件。完成后,我们使用 GetValue 获取小部件保存的值,并将该值分配给配置中的正确字段。当循环结束时,我们将数据写入磁盘。立即改进警告:我在这里没有任何验证!这是你要做的事情来扩展这个例子。最后一步是调用 EndModal(0)关闭对话框,然后关闭应用程序。

    现在您已经知道了从配置文件生成对话框的基本知识。我认为使用某种带有小部件类型名称(可能是字符串)的字典可能是让这个脚本与其他小部件一起工作的简单方法。发挥你的想象力,让我知道你想到了什么。

    注意:所有代码都是在 Windows XP 上用 Python 2.5、ConfigObj 4.6.0 和 Validate 1.0.0 测试的。

    ConfigObj 教程

    XRC 和 wxPython

    [wx。对话框

    ](http://www.wxpython.org/docs/api/wx.Dialog-class.html)

  • dialog_from_config.zip
  • dialog_from_config.tar
  • 提前获取 Python 测验书籍和课程

    原文:https://www.blog.pythonlibrary.org/2022/12/07/get-early-access-to-the-python-quiz-book-and-course/

    Python 测验书和Python 测验课程现在可以提前获取。课程和书都将有 100 多个测验和答案。

    以下是您将要了解的一些内容:

  • (听力或阅读)理解测试
  • 希腊字母的第 11 个
  • 模数运算符
  • 三元表达式
  • 可召回商品
  • 赋值表达式(Walrus 运算符)
  • 还有更多!
  • 课程与书的主要区别在于,课程允许我包含更多的链接、媒体和互动,而这些是我在电子书上做不到的。

    您可以从以下网址获得Python 问答书电子书:

  • Leanpub
  • Gumroad
  • 可以在教我 Python 上获取 Python 小测验课程。

    免费获取 Python 101 第二版 72 小时!

    原文:https://www.blog.pythonlibrary.org/2021/01/11/get-python-101-2nd-edition-free-for-72-hours/

    Python 101 第二版是 Python 101 的最新版本。这本书旨在帮助你学习 Python,然后超越基础。我一直觉得初学者的书不应该只教语法。如果你想尝试 Python 101,你可以在接下来的 72 小时内通过使用以下链接免费试用:https://leanpub.com/py101/c/mvp2021

    **如果你有一个 Gumroad 帐户,你可以在这里(https://gumroad.com/l/pypy101)用这张优惠券免费得到这本书: mvp2021

    上一次我让 Python 101 免费 3 天,就获得了 3-4 万的新读者。让我们看看我们是否能战胜它!

    第二版 Python 101 完全从头重写。在本书中,您将学习 Python 编程语言以及更多内容。

    这本书分为四个部分:

  • Python 语言
  • 创建示例应用程序
  • 分发您的代码
  • 查看 LeanpubGumroad 了解书中所有内容的全部细节。**

    使用 Python 获取 GPS EXIF 数据

    原文:https://www.blog.pythonlibrary.org/2021/01/13/getting-gps-exif-data-with-python/

    您知道可以使用 Python 编程语言从 JPG 图像文件中获取 EXIF 数据吗?您可以使用 Pillow 来实现这一点,Pillow 是 Python 图像库的友好分支。如果你想的话,你可以在这个网站上阅读一篇文章。

    以下是从 JPG 文件中获取常规 EXIF 数据的示例代码:

    # exif_getter.py
    from PIL import Image
    from PIL.ExifTags import TAGS
    def get_exif(image_file_path):
        exif_table = {}
        image = Image.open(image_file_path)
        info = image.getexif()
        for tag, value in info.items():
            decoded = TAGS.get(tag, tag)
            exif_table[decoded] = value
        return exif_table
    if __name__ == "__main__":
        exif = get_exif("bridge.JPG")
        print(exif)
    

    该代码使用以下图像运行:

    在本文中,您将关注如何从图像中提取 GPS 标签。这些是特殊的 EXIF 标签,只有在拍摄照片的相机打开了其位置信息时才会出现。你也可以事后在电脑上添加 GPS 标签。

    例如,我在杰斯特公园的这张照片上添加了 GPS 标签,杰斯特公园位于伊利诺伊州的格兰杰:

    要访问这些标记,您需要使用前面的代码示例并做一些小的调整:

    # gps_exif_getter.py
    from PIL import Image
    from PIL.ExifTags import TAGS, GPSTAGS
    def get_exif(image_file_path):
        exif_table = {}
        image = Image.open(image_file_path)
        info = image.getexif()
        for tag, value in info.items():
            decoded = TAGS.get(tag, tag)
            exif_table[decoded] = value
        gps_info = {}
        for key in exif_table['GPSInfo'].keys():
            decode = GPSTAGS.get(key,key)
            gps_info[decode] = exif_table['GPSInfo'][key]
        return gps_info
    if __name__ == "__main__":
        exif = get_exif("jester.jpg")
        print(exif)
    

    要访问 GPS 标签,您需要从 PIL.ExifTags 导入 GPS tags。如果存在,那么你就可以提取 GPS 标签。

    运行此代码时,您应该会看到以下输出:

    {'GPSLatitudeRef': 'N',
     'GPSLatitude': (41.0, 47.0, 2.17),
     'GPSLongitudeRef': 'W',
     'GPSLongitude': (93.0, 46.0, 42.09)}
    

    您可以获取这些信息,并使用 Python 加载 Google 地图,或者使用流行的 GIS 相关 Python 库。

    使用 Python 获取照片元数据(EXIF)

    给图像浏览器添加 EXIF 浏览器

    使用 Python 通过构建状态获取 Jenkins 作业

    原文:https://www.blog.pythonlibrary.org/2020/01/14/getting-jenkins-jobs-by-build-state-with-python/

    我最近一直在与 Python 和 Jenkins 一起工作,最近需要找到一种方法在构建级别检查作业的状态。我发现了 jenkinsapi 包,并试用了一下,看看它是否能让我深入到 Jenkins 中的构建和结果集级别。

    在我运行的构建中,有 X 数量的子作业。这些子作业中的每一个都可能通过或失败。如果其中一个失败了,整个构建就会被标上黄色,并被标记为“不稳定”,这在我的书中是失败的。我需要一种方法来跟踪这些子作业中哪个失败了,以及在一段时间内失败的频率。这些作业中的一些可能不稳定,因为它们访问网络资源,而另一些可能由于最近对代码库的提交而中断。

    我最终想出了一些代码来帮助我理解这些信息。但是在深入研究代码之前,您需要安装一个包。

    安装必备组件

    jenkinsapi 包很容易安装,因为它是 pip 兼容的。您可以使用以下命令将其安装到您的主 Python 安装或 Python 虚拟环境中:

    pip install jenkinsapi

    您还需要安装请求,这也是 pip 兼容的:

    pip install requests

    这些是你唯一需要的包裹。现在你可以进入下一部分了!

    询问詹金斯

    您想要完成的第一步是按状态获取作业。Jenkins 中的标准状态包括成功、不稳定或中止。

    让我们编写一些代码来查找不稳定的作业:

    from jenkinsapi.jenkins import Jenkins from jenkinsapi.custom_exceptions import NoBuildData from requests import ConnectionError def get_job_by_build_state(url, view_name, state='SUCCESS'): server = Jenkins(url) view_url = f'{url}/view/{view_name}/' view = server.get_view_by_url(view_url) jobs = view.get_job_dict() jobs_by_state = [] for job in jobs: job_url = f'{url}/{job}' j = server.get_job(job) build = j.get_last_completed_build() status = build.get_status() if status == state: jobs_by_state.append(job) except NoBuildData: continue except ConnectionError: return jobs_by_state if __name__ == '__main__': jobs = get_job_by_build_state(url='http://myJenkins:8080', view_name='VIEW_NAME', state='UNSTABLE')

    在这里,您创建了一个 Jenkins 的实例,并将其分配给服务器。然后使用 get_view_by_url() 获取指定的视图名称。该视图基本上是您设置的一组相关联的职务。例如,您可以创建一组做开发/操作类事情的作业,并将它们放入 Utils 视图中。

    一旦有了视图对象,就可以使用 get_job_dict() 来获取该视图中所有作业的字典。既然已经有了字典,就可以对它们进行循环,并在视图中获得各个作业。您可以通过调用 Jenkin 对象的 get_job() 方法来获得作业。既然有了 job 对象,您终于可以深入到构建本身了。

    为了防止错误,我发现可以使用get _ last _ completed _ build()来获得最后一次完整的构建。这是最好的,如果你使用 get_build() 并且构建还没有完成,构建对象可能没有你期望的内容。现在您已经有了构建,您可以使用 get_status() 来获取它的状态,并将其与您传入的那个进行比较。如果它们匹配,那么将该作业添加到 jobs_by_state ,这是一个 Python 列表。

    您还会发现一些可能发生的错误。你可能看不到 NoBuildData ,除非作业被中止或者你的服务器上发生了一些非常奇怪的事情。当你试图连接到一个不存在或离线的 URL 时,就会发生 ConnectionError 异常。

    此时,您应该有一个筛选到您所要求的状态的作业列表。

    如果您想进一步深入到作业中的子作业,那么您需要调用构建的 has_resultset() 方法来验证是否有要检查的结果。然后你可以这样做:

    resultset = build.get_resultset() for item in resultset.items(): # do something here

    根据作业类型的不同,返回的 resultset 会有很大不同,所以您需要自己解析条目元组,看看它是否包含您需要的信息。

    此时,您应该有足够的信息来开始挖掘 Jenkin 的内部信息,以获得您需要的信息。我使用了这个脚本的一个变体来帮助我提取构建失败的信息,帮助我更快地发现重复失败的作业。不幸的是, jenkinsapi 的文档不是很详细,所以你将会在调试器中花费大量的时间试图弄清楚它是如何工作的。然而,一旦你搞清楚了,它总体上工作得很好。

    使用 Python 获取照片元数据(EXIF)

    原文:https://www.blog.pythonlibrary.org/2010/03/28/getting-photo-metadata-exif-using-python/

    上周,我试图找出如何获得我的照片的元数据。我注意到 Windows 可以在我的照片上显示相机型号、创建日期和许多其他数据,但我不记得这些数据叫什么了。我终于找到了我要找的东西。术语是 EXIF(可交换图像文件格式)。在本帖中,我们将看看各种第三方软件包,它们让您可以访问这些信息。

    我的第一个想法是 Python 图像库会有这个功能,但是我还没有找到 EXIF 术语,如果没有它,在 PIL 的手册中也找不到这个信息。幸运的是,我最终通过一个 stackoverflow 线程找到了使用 PIL 的方法。这是它展示的方法:

    from PIL import Image from PIL.ExifTags import TAGS def get_exif(fn): ret = {} i = Image.open(fn) info = i._getexif() for tag, value in info.items(): decoded = TAGS.get(tag, tag) ret[decoded] = value return ret

    这工作得很好,并返回一个很好的字典对象。我发现有几个字段没有用,比如“MakerNote”字段,它看起来像许多十六进制值,所以您可能只想使用某些数据。以下是我得到的一些信息的例子:

    {'YResolution': (180, 1), 'ResolutionUnit': 2, 'Make': 'Canon', 'Flash': 16, 'DateTime': '2009:09:11 11:29:10', 'MeteringMode': 5, 'XResolution': (180, 1), 'ColorSpace': 1, 'ExifImageWidth': 3264, 'DateTimeDigitized': '2009:09:11 11:29:10', 'ApertureValue': (116, 32), 'FocalPlaneYResolution': (2448000, 169), 'CompressedBitsPerPixel': (3, 1), 'SensingMethod': 2, 'FNumber': (35, 10), 'DateTimeOriginal': '2009:09:11 11:29:10', 'FocalLength': (26000, 1000), 'FocalPlaneXResolution': (3264000, 225), 'ExifOffset': 196, 'ExifImageHeight': 2448, 'ISOSpeedRatings': 100, 'Model': 'Canon PowerShot S5 IS', 'Orientation': 1, 'ExposureTime': (1, 200), 'FileSource': '\x03', 'MaxApertureValue': (116, 32), 'ExifInteroperabilityOffset': 3346, 'FlashPixVersion': '0100', 'FocalPlaneResolutionUnit': 2, 'YCbCrPositioning': 1, 'ExifVersion': '0220'}

    我真的不知道所有这些值意味着什么,但我知道我可以使用其中的一些。我想要这些数据的目的是扩展我的简单的图像浏览器,这样它可以向用户显示更多关于他们照片的信息。

    以下是我发现的其他几个可以访问 EXIF 数据的图书馆:

  • Python 的媒体元数据
  • EXIF.py
  • Python Exif 解析器
  • 一个博主的 Exif 解析器
  • pyexiv2
  • 我尝试了 Python Exif 解析器,它工作得相当好。当我在工作中试图在我的 Python 2.5 机器上安装 pyexiv2 时,我收到了一条关于 Python 2.6 未找到的错误消息,然后安装程序退出了。pyexiv2 网站上没有提到它需要特定版本的 Python 才能工作,所以这有点令人沮丧。这些模块中的大多数很少或者没有文档,这也非常令人沮丧。据我所知,EXIF.py 应该通过命令行使用,而不是作为一个可导入的模块。

    总之,回到 Python Exif 解析器。它实际上比 PIL 更容易使用。将 exif.py 文件复制到 Python 路径后,您需要做的就是:

    import exif photo_path = "somePath\to\a\photo.jpg" data = exif.parse(photo_path)

    上面的代码返回的信息与 PIL 代码片段返回的信息基本相同,尽管它对“MakersNote”使用了整数而不是十六进制,并且它有几个“Tag0xa406”字段,而 PIL 数据有一些数字字段(我在上面排除了这些字段)。我假设他们以不同的方式引用相同的信息。

    无论如何,当你试图发现这些信息时,如果你发现自己在网上游荡,希望你会偶然发现这篇文章,它会给你指出正确的方向。

    获取 Windows 上的远程驱动器空间

    原文:https://www.blog.pythonlibrary.org/2010/09/09/getting-remote-drive-space-on-windows/

    在我目前的工作岗位上工作了大约一年后,当我们还在将最后几台 Windows 98 机器升级到 Windows XP 时,我们需要检查我们网络上哪些机器的磁盘空间越来越少。这个问题之所以会突然出现,是因为我们在几台有 10 GB 硬盘、几台有 20 GB 硬盘、一两台只有 4 GB 硬盘的机器上安装了 Windows XP。总之,在网上做了一些调查后,我发现 PyWin32 包可以完成我需要的功能。

    以下是我使用的代码:

    import win32com.client as com def TotalSize(drive): """ Return the TotalSize of a shared drive [GB]""" fso = com.Dispatch("Scripting.FileSystemObject") drv = fso.GetDrive(drive) return drv.TotalSize/2**30 except: return 0 def FreeSpace(drive): """ Return the FreeSpace of a shared drive [GB]""" fso = com.Dispatch("Scripting.FileSystemObject") drv = fso.GetDrive(drive) return drv.FreeSpace/2**30 except: return 0 workstations = ['computeNameOne'] print 'Hard drive sizes:' for compName in workstations: drive = '\\\\' + compName + '\\c$' print '*************************************************\n' print compName print 'TotalSize of %s = %f GB' % (drive, TotalSize(drive)) print 'FreeSpace on %s = %f GB' % (drive, FreeSpace(drive)) print '*************************************************\n'

    注意在底部,我使用了一个列表。通常,我会列出我想检查的每台计算机的名称。然后,我将遍历这些名称,并从一台拥有完全域管理权限的机器上将我需要的正确路径放在一起。

    为了让它工作,我们需要导入 win32com.client 并调用下面的代码: com。Dispatch("脚本。FileSystemObject") 。这将为我们提供一个 COM 对象,我们可以通过查询来获得一个 disk 对象。一旦我们有了这些,我们可以问磁盘它有多少总空间和多少空闲空间。今天来看看这段代码,我会将这两个函数合并成一个函数,并返回一个元组。如您所见,我对结果做了一点数学运算,让它返回以千兆字节为单位的大小。

    这就是全部了。简单的东西。我怀疑我没有完全写好这段代码,因为变量名太烂了。它可能来自于一个活动状态的食谱或者一个论坛,但是我忘了注明它的属性。如果你认识这个代码,请在评论中告诉我!

    JupyterLab 入门

    原文:https://www.blog.pythonlibrary.org/2019/02/05/getting-started-with-jupyterlab/

    JupyterLab 是来自 Project Jupyter 的最新包。在某些方面,它是 Jupyter 笔记本的替代品。然而,Jupyter 笔记本是 JupyterLab 的一个独立项目。我喜欢把 JupyterLab 想象成一种基于网络的集成开发环境,你可以用它来操作 Jupyter 笔记本,也可以使用终端、文本编辑器和代码控制台。你可能会说 JupyterLab 是 Jupyter Notebook 的更强大版本。

    无论如何,这里有一些 JupyterLab 能够做到的事情:

  • 代码控制台——这些是代码暂存区,你可以用它来交互式地运行代码,有点像 Python 的 IDLE
  • 内核支持的文档——这些文档允许您启用任何文本文件(Markdown、Python、R 等)中的代码,然后这些代码可以在 Jupyter 内核中运行
  • 镜像笔记本单元输出-这让您可以创建简单的仪表板
  • 同一文档的多个视图-让您能够实时编辑文档并查看结果
  • JupyterLab 将允许您查看和处理多种类型的数据。您还可以使用各种可视化或降价来显示这些格式的丰富输出。

    对于导航,您可以使用 vim、emacs 甚至 SublimeText 中的可定制键盘快捷键或键映射。

    您可以通过扩展向 JupyterLab 实例添加新的行为。这包括主题支持、文件编辑器等等。

    可以使用 conda、pip 或 pipenv 来安装 JupyterLab。

    如果您是 Anaconda 用户,那么您可以使用以下命令将 conda 用于安装目的:

    conda install -c conda-forge jupyterlab

    如果您喜欢使用 Python 的本地安装程序 pip,那么这就是您想要的命令:

    pip install jupyterlab

    注意:如果您使用的是 pip install - user ,那么您需要将用户级的“bin”目录添加到 PATH 环境变量中,以便能够启动 jupyterlab。

    pipenv

    pipenv 工具是一个新的包,可用于创建 Python 虚拟环境并将包下载到其中。如果您碰巧安装了它,那么您可以使用以下两个命令来获取 JupyterLab:

    pipenv install jupyterlab pipenv shell

    请注意,如果您想从安装 JupyterLab 的 virtualenv 中启动 JupyterLab,则需要调用 shell 命令。

    运行 JupyterLab

    现在我们已经安装了 JupyterLab,我们应该试着运行它。你可以使用 jupyter-lab 或者 jupyter lab 来运行它。当我运行这些命令时,我得到了下面的初始 web 应用程序:

    新 JupyterLab 的初始登录页面

    右边的标签叫做启动器。这是一个地方,你可以去开始一个新的笔记本,代码控制台,终端或文本文件。新文档作为新选项卡打开。你会注意到,当你创建一个新的笔记本或其他项目,启动消失。如果你想打开第二个文档,只需点击左边的“+”按钮,我在下面画了圈:

    在 JupyterLab 中添加新项目

    让我们打开笔记本,然后单击加号按钮。如果你这样做,你的屏幕应该是这样的:

    JupyterLab 中的多个选项卡

    您也可以使用屏幕顶部的菜单* *创建新项目。只需转到文件**-> * 新建 *,然后选择您要创建的项目类型。如果你用过 Jupyter Notebook,大部分菜单项你应该很熟悉。不过,这里有一些新条目是专门针对 JupyterLab 的。例如:

  • 新启动器-启动一个新的启动器
  • 从路径打开-从不同于开始路径的路径打开文档
  • 将笔记本另存为...-让您用新文件名保存当前选定的笔记本
  • 将笔记本导出为...-让您将笔记本导出为不同的格式,如 PDF、Markdown 等
  • 浏览菜单,看看你还能找到什么。这是不言自明的。

    文件浏览器

    左边的树被称为文件浏览器。它显示了从您启动 JupyterLab 的位置可用的文件。只需单击文件夹图标使树折叠,以便选项卡可以充满浏览器:

    文件浏览器最小化

    您会注意到,您也可以通过单击文件夹+图标(下面画圈的)在文件浏览器中创建新文件夹:

    创建新文件夹

    如果您需要从计算机上的另一个位置向 JupyterLab 添加文件,您需要点击上传按钮:

    将文件上传/保存到工作区

    当你这样做时,它会弹出一个文件打开对话框:

    上传对话框

    就像在另一个程序中打开文件一样使用它。请记住,您不是打开一个文件,而是将它“上传”或“复制”到您的 JupyterLab 工作区。

    最后,如果您碰巧通过使用上传按钮之外的方法将文件复制到工作区中,则可以使用刷新按钮来刷新工作区:

    刷新文件浏览器按钮

    特殊 URL

    与 Jupyter Notebook 一样,JupyterLab 允许用户将 URL 复制到浏览器中,以打开特定的笔记本或文件。然而,JupyterLab 还增加了通过 URL 管理工作区和文件导航的能力。

    例如,如果你想使用文件导航,你可以使用特殊的关键字来实现。以下是使用无标题笔记本的 URL 示例:

    http://localhost:8888/lab/tree/Untitled.ipynb

    如果你尝试这样做,你会看到普通的 Jupyter 笔记本界面,而不是 JupyterLab 内部的笔记本。

    默认的工作区没有名字,但是可以在 /lab 找到。如果您想要克隆您的工作区,您可以使用以下格式:

    http://localhost:8888/lab/workspaces/test?clone

    这将把您当前的工作区复制到一个名为 test 的工作区中。如果您想要将测试工作区复制到您的默认工作区中,URL 应该是这样的:

    http://localhost:8888/lab?clone=test

    您也可以使用重置 URL 参数重置工作区。重置工作区时,您正在清除其内容。以下是重置默认工作空间的示例:

    http://localhost:8888/lab/workspaces/lab?reset

    牢房检查员

    让我们在 JupyterLab 实例中创建一个笔记本。转到启动器,选择一个内核。默认情况下,您将拥有 Python 2 或 Python 3。创建之后,您应该会看到一个名为“Untitled.ipynb”的新选项卡,如下所示:

    JupyterLab 的一个空笔记本

    如你所见,我们有一个只有一个电池的笔记本。让我们将以下代码添加到幻灯片中:

    def adder(a, b): return a + b adder(2, 3)

    现在,让我们单击左侧工具栏中的小扳手。下面是一个按钮被圈起来的屏幕截图:

    牢房检查员

    当您单击那个扳手时,您的屏幕应该看起来如上所示。这被称为细胞检查员。您可以在这里设置笔记本以用于演示目的。您可以设置哪些单元格是载玻片或子载玻片。我们在第 9 章中谈到的与笔记本本身相关的几乎任何事情都可以在这里完成。您还会注意到,单元格检查器将显示 JupyterLab / Notebook 添加到单元格中的任何元数据。

    如果你想看实际操作,那么试着将你的第一个单元格设置为一个幻灯片。现在,您应该看到元数据字段是这样填充的:

    单元格的元数据

    您可以使用 JupyterLab 的文件浏览器和文件菜单来处理系统中的文件和目录。这允许您打开、创建、删除、重命名、下载/上传、复制和共享文件和目录。您可以在左侧边栏中找到文件浏览器:

    文件浏览器

    如果您的浏览器中有文件,您只需双击该文件即可打开它,就像您通常在系统的文件浏览器中所做的那样。您也可以将文件从文件浏览器拖到工作区(右侧),这将打开该文件。

    JupyterLab 支持的许多文件类型也有多个查看器和编辑器。例如,您可以在编辑器中打开 Markdown 文件,或者以 HTML 格式查看它。如果您想在非默认的查看器/编辑器中打开该文件,只需右键单击该文件并选择“打开方式...”即可从上下文菜单中:

    文件的上下文菜单

    请注意,您可以在多个查看器/编辑器中打开一个文件,它们将保持同步。

    文本编辑器

    JupyterLab 带有一个内置的文本编辑器,可以用来创建或打开文本文件。打开启动程序,不要创建笔记本,转到启动程序的底部,创建一个文本文件。

    启动文本编辑器

    它会默认创建一个 untitled.txt 文件。但是你可以进入文件菜单,使用“另存为……”把它存为别的东西。这允许你创建 Python 文件,Markdown 和几乎任何你想做的事情。它甚至为某些文件类型提供语法高亮,尽管不支持代码完成。您也可以通过文件菜单创建文件。

    文本编辑器还支持可配置的缩进(制表符和空格)、键映射和基本主题。只需进入设置菜单查看或编辑即可:

    如果你想编辑一个现有的文本文件,你需要做的就是在文件浏览器中双击它。

    交互式代码控制台

    JupyterLab 的新特性之一是代码控制台,它基本上是浏览器中的 REPL。它将让你在当前选择的内核中交互式地运行代码。代码控制台的“单元”显示代码运行的顺序。要创建新的代码控制台,请单击文件浏览器中的“+”按钮,并选择您选择的内核:

    代码控制台启动器

    输入一些代码。如果你自己想不起来,这里有一个例子:

    print('Hello Console!')

    现在按下 Shift+Enter 运行代码。如果一切正常,您应该会看到以下输出:

    代码控制台

    代码完成通过选项卡键工作。你也可以通过按下 Shift+Tab 来调出工具提示。

    如果需要在不重启内核的情况下清除代码控制台,可以右击控制台本身,选择“清除控制台单元格”。

    JupyterLab 项目继续支持浏览器中的系统外壳。对于 Mac / Linux,它支持 bash、tsch 等,而在 Windows 上,它支持 Powershell。这些终端可以运行您通常从系统终端运行的任何程序,包括其他程序,如 vim 或 emacs。请注意,JupyterLab 终端运行在您安装了 JupyterLab 的系统上,因此它也将使用您的用户权限。

    无论如何,如果你想看到一个运行中的终端,只需按下文件浏览器中的“+”按钮启动启动器。然后选择终端:

    终端发射器

    如果您关闭终端标签,JupyterLab 将让它在后台运行。下面是一个运行的终端:

    正在运行的终端

    如果您想重新打开终端,只需转到运行选项卡:

    运行应用程序

    然后从运行的应用程序列表中选择终端。

    命令选项板

    JupyterLab 中的用户操作都要通过一个中央指挥系统。这包括菜单栏、上下文菜单、键盘快捷键等使用的命令。您可以通过命令面板访问可用的命令,您可以在命令选项卡下找到:

    命令选项板

    在这里,您可以搜索命令并直接执行它们,而不是在菜单系统中搜索它们。你也可以用下面的快捷键调出命令面板: Command/Ctrl Shift C

    支持的文件类型

    JupyterLab 支持相当多的文件类型,它可以显示或允许您编辑。这允许您在笔记本或代码控制台中布局丰富的单元格输出。对于文件,JupyterLab 将通过查看文件的扩展名或完整的文件名(如果扩展名不存在)来检测数据格式。请注意,多个编辑器/查看器可以与一个文件类型相关联。例如,您可以编辑降价文件并以 HTML 格式查看。只需右击一个文件,进入打开方式上下文菜单项,查看该文件类型可用的编辑器和查看器:

    使用打开方式

    您可以使用 Python 代码在笔记本或代码控制台中显示不同的数据格式。这里有一个例子:

    from IPython.display import display, HTML display(HTML('你好,来自 JupyterLab'))

    当您在笔记本中运行这段代码时,它应该是这样的:

    在笔记本中运行 HTML

    关于 JupyterLab 支持的文件类型的完整列表,我建议查看文档。这应该总是最新的,而且比我自己列出这些项目更有用。

    关于扩展的一句话

    如您所料,JupyterLab 支持扩展,并且在设计时考虑了可扩展性。扩展可以定制用户体验或增强 JupyterLab 的一个或多个部分。例如,您可以向菜单或命令面板添加新项目,或者添加一些新的键盘快捷键。JupyterLab 本身其实就是一个扩展的集合。

    如果你想为 JupyterLab 创建一个扩展,那么你需要熟悉 Javascript 或者愿意学习。扩展需要采用 npm 打包格式。要安装预制的扩展,您需要在您的机器上安装 Node.js 。一定要查看他们的网站,以获得你的操作系统的正确安装说明。

    安装/卸载扩展

    一旦安装了 Node.js,就可以通过运行以下命令来安装 JupyterLab 的扩展:

    jupyter labextension install the-extension-name

    如果您需要特定版本的扩展,那么该命令将如下所示:

    jupyter labextension install [email protected]

    其中“1.2”是您需要的版本。您还可以扩展为 gzipped tarball 或 gzipped tarball 的 URL。

    要获得当前安装的 JupyterLab 扩展的列表,只需运行

    jupyter labextension list

    如果您想卸载某个扩展,可以像这样轻松地完成:

    jupyter labextension uninstall the-extension-name

    您也可以通过在 install 或 uninstall 命令后列出软件包的名称来安装或卸载多个扩展。由于 JupyterLab 在每次安装后都会重新构建,这可能需要相当长的时间。为了在安装或卸载多个扩展时加快速度,可以包含** - no-build**标志。安装或卸载完成后,您需要自己运行构建命令,如下所示:

    jupyter lab build

    如果你不想卸载一个扩展,但你想禁用它,这也很容易做到。只需运行禁用命令:

    jupyter labextension disable the-extension-name

    然后当你想重新启用它时,你可以运行 enable 命令:

    jupyter labextension enable the-extension-name

    JupyterLab 包真的很神奇。比起 Jupyter 笔记本,你可以用它做更多的事情。然而,用户界面也更复杂,所以学习曲线会更陡一些。然而,我认为值得学习如何使用它,因为编辑文档和实时查看文档的能力在创建演示文稿或做其他类型的工作时非常有用。至少,我会在虚拟环境中尝试一下,看看它是否适合您的工作流程。

  • JupyterLab on Github
  • 使用 Jupyter 笔记本小工具
  • Jupyter 笔记本调试
  • pywebview 入门

    原文:https://www.blog.pythonlibrary.org/2017/04/25/getting-started-with-pywebview/

    几周前,我偶然发现了 pywebview 项目。pywebview 包“是一个轻量级的跨平台 webview 组件包装器,它允许在自己的本地 GUI 窗口中显示 HTML 内容它在 OSX 和 Linux 上使用 WebKit,在 Windows 上使用 Trident (MSHTML),这实际上也是 wxPython 的 webview 小工具所做的。pywebview 背后的想法是,它让你能够在桌面应用程序中加载网站,有点像电子

    虽然 pywebview 声称它“不依赖于外部 GUI 框架”,但在 Windows 上,它需要安装 pythonnet、PyWin32 和 comtypes。OSX 需要“pyobjc”,尽管它包含在 OSX 安装的默认 Python 中。对于 Linux 来说,这有点复杂。在基于 GTK3 的系统上,你需要 PyGObject,而在基于 Debian 的系统上,你需要安装 PyGObject + gir1.2-webkit-3.0。最后,你也可以使用 PyQt 4 或 5。

    你可以通过 pywebview 使用 Python 微 web 框架,比如 Flask 或者 bottle,用 HTML5 代替 Python 来创建很酷的应用。

    要安装 pywebview 本身,只需使用 pip:

    pip install pywebview
    

    安装完成后,假设您也具备了先决条件,您可以这样做:

    import webview
    webview.create_window('My Web App', 'http://www.mousevspython.com')
    webview.start()
    

    这将在具有指定标题(即第一个参数)的窗口中加载指定的 URL。您的新应用程序应该看起来像这样:

    pywebview 的 API 非常简短,可以在以下位置找到:

  • https://github.com/r0x0r/pywebview#api
  • 你能使用的方法屈指可数,这使得它们很容易记住。但是因为您不能为 pywebview 应用程序创建任何其他控件,所以您需要在 web 应用程序中完成所有的用户界面逻辑。

    pywebview 包支持使用 PyInstaller for Windows 和 py2app for OSX 进行冻结。它也适用于 virtualenv,尽管在使用 virtualenv 之前,您需要阅读一些已知的问题。

    pywebview 包实际上非常简洁,我个人认为值得一看。如果您想要一些更好地集成到您的桌面的东西,那么您可能想要尝试 wxPython 或 PyQt。但是如果你需要做的只是发布一个基于 HTML5 的 web 应用程序,那么这个包可能就是你想要的。

    Python 入门

    原文:https://www.blog.pythonlibrary.org/2018/04/18/getting-started-with-qt-for-python/

    Qt 团队最近发布了消息,Qt 现在将正式支持 PySide2 项目,他们称之为“Python 的 Qt”。它将是原 PySide 的完整端口,原 py side 只支持 Qt 4。PySide2 支持 Qt 5。Qt for Python 将拥有以下许可类型:GPL、LGPL 和商业许可。

    PySide2 支持 Python 2.7 以及 Python 3.4 - 3.6。这里有可用的快照轮版本。假设我们下载了 Windows Python wheel。要安装它,您可以像这样使用 pip:

    python -m pip install PySide2-5.11.0a1-5.11.0-cp36-cp36m-win_amd64.whl

    一旦安装了 PySide2,我们就可以从一个非常简单的例子开始:

    import sys from PySide2.QtWidgets import QApplication, QLabel if __name__ == '__main__': app = QApplication([]) label = QLabel("Qt for Python!") label.show() sys.exit(app.exec_())

    这段代码将创建我们的应用程序对象(QApplication)和一个 QLabel。当您运行 app.exec_() 时,您启动了 PySide2 的事件循环。因为我们没有指定标签或应用程序的大小,所以应用程序的大小默认为刚好足以容纳屏幕上的标签:

    这是一个很无聊的例子,所以让我们看看如何把一个事件和一个按钮联系起来。

    添加事件处理

    PySide2 中的事件处理使用了信号和底层插槽的概念。你可以在他们的文档中了解这是如何工作的。让我们来看看如何设置按钮事件:

    import sys from PySide2.QtWidgets import QApplication, QLabel, QLineEdit from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout class Form(QDialog): """""" def __init__(self, parent=None): """Constructor""" super(Form, self).__init__(parent) self.edit = QLineEdit("What's up?") self.button = QPushButton("Print to stdout") layout = QVBoxLayout() layout.addWidget(self.edit) layout.addWidget(self.button) self.setLayout(layout) self.button.clicked.connect(self.greetings) def greetings(self): """""" text = self.edit.text() print('Contents of QLineEdit widget: {}'.format(text)) if __name__ == "__main__": app = QApplication([]) form = Form() form.show() sys.exit(app.exec_())

    这里,我们通过 QLineEdit 小部件创建一个文本框,并通过 QPushButton 小部件创建一个按钮。然后,我们将这两个小部件放在 QVBoxLayout 中,这个容器允许您更改应用程序的大小,并让布局中包含的小部件相应地更改大小和位置。在这种情况下,我们使用垂直方向的布局,这意味着小部件垂直“堆叠”。

    最后,我们将按钮的“clicked”信号与 greetings (slot)函数联系起来。每当我们点击按钮时,它都会调用我们指定的函数。这个函数将获取我们的文本框的内容,并将其打印到 stdout。下面是我运行代码时的样子:

    我认为这看起来不错,但它仍然不是一个非常有趣的界面。

    创建简单的表单

    让我们通过用 PySide2 创建一个简单的表单来总结一下。在这个例子中,我们不会将表单与任何东西挂钩。这只是一段简单快速的示例代码,展示了如何创建一个简单的表单:

    import sys from PySide2.QtWidgets import QDialog, QApplication from PySide2.QtWidgets import QHBoxLayout, QVBoxLayout from PySide2.QtWidgets import QLineEdit, QLabel, QPushButton class Form(QDialog): """""" def __init__(self, parent=None): """Constructor""" super(Form, self).__init__(parent) main_layout = QVBoxLayout() name_layout = QHBoxLayout() lbl = QLabel("Name:") self.name = QLineEdit("") name_layout.addWidget(lbl) name_layout.addWidget(self.name) name_layout.setSpacing(20) add_layout = QHBoxLayout() lbl = QLabel("Address:") self.address = QLineEdit("") add_layout.addWidget(lbl) add_layout.addWidget(self.address) phone_layout = QHBoxLayout() self.phone = QLineEdit("") phone_layout.addWidget(QLabel("Phone:")) phone_layout.addWidget(self.phone) phone_layout.setSpacing(18) button = QPushButton('Submit') main_layout.addLayout(name_layout, stretch=1) main_layout.addLayout(add_layout, stretch=1) main_layout.addLayout(phone_layout, stretch=1) main_layout.addWidget(button) self.setLayout(main_layout) if __name__ == "__main__": app = QApplication([]) form = Form() form.show() sys.exit(app.exec_())

    在这段代码中,我们使用了几个盒子布局来排列屏幕上的小部件。也就是说,我们使用 QVBoxLayout 作为顶层布局,然后在其中嵌套 QHBoxLayouts。您还会注意到,当我们添加 QHBoxLayouts 时,我们告诉它们在我们调整主小部件大小时进行拉伸。代码的其余部分与您已经看到的几乎相同。

    我已经很多年没有玩 PySide2(或者 PyQt)了,所以看到 Qt 再次拿起这个很令人兴奋。我认为 PySide2 和 PyQt 之间的一些竞争将是一件好事,它也可能推动其他 Python UI 框架的一些创新。虽然 PySide2 背后的开发人员目前没有支持移动平台的计划,但不幸的是,他们似乎很想知道开发人员是否会对此感兴趣。坦率地说,我希望很多人附和并告诉他们是的,因为我们在 Python 移动 UI 领域需要其他选择。

    无论如何,我认为这个项目有很大的潜力,我期待看到它如何成长。

  • PySide2 Wiki
  • Python 的 Qt 是来到你身边的计算机
  • 快照将 PySide2 的构建为 Python 轮子
  • ReportLab 画布入门

    原文:https://www.blog.pythonlibrary.org/2021/09/15/getting-started-with-reportlabs-canvas/

    ReportLab 是一个非常强大的库。只需一点点努力,你就可以做出任何你能想到的布局。这些年来,我用它复制了许多复杂的页面布局。在本教程中,您将学习如何使用 ReportLab 的 pdfgen 包。您将发现如何执行以下操作:

  • 了解字体和文本颜色
  • 创建文本对象
  • 画各种形状
  • pdfgen 包很低级。您将在画布上绘制或“绘画”来创建您的 PDF。画布从 pdfgen 包中导入。当您在画布上进行绘制时,您需要指定 X/Y 坐标来告诉 ReportLab 从哪里开始绘制。默认值为(0,0),其原点位于页面的左下角。许多桌面用户界面工具包,如 wxPython、Tkinter 等,也有这个概念。您也可以使用 X/Y 坐标在这些套件中放置按钮。这样可以非常精确地放置您添加到页面中的元素。

    你需要知道的另一件事是,当你在 PDF 中定位一个项目时,你是根据你离原点的点数来定位的。是点,不是像素或毫米或英寸。积分!让我们来看看一张信纸大小的纸上有多少个点:

    >>> from reportlab.lib.pagesizes import letter
    >>> letter
    (612.0, 792.0)
    

    这里你了解到一个字母宽 612 点,高 792 点。让我们分别找出一英寸和一毫米中有多少个点:

    >>> from reportlab.lib.units import inch
    >>> from reportlab.lib.units import mm
    2.834645669291339
    

    这些信息将帮助您在绘画中定位您的绘图。至此,您已经准备好创建 PDF 了!

    画布对象位于 pdfgen 包中。让我们导入它并绘制一些文本:

    # hello_reportlab.py
    from reportlab.pdfgen import canvas
    c = canvas.Canvas("hello.pdf")
    c.drawString(100, 100, "Welcome to Reportlab!")
    c.showPage()
    c.save()
    

    在本例中,您导入 canvas 对象,然后实例化一个 Canvas 对象。您会注意到唯一需要的参数是文件名或路径。接下来,调用 canvas 对象上的 drawString(),告诉它开始在原点右侧 100 点和上方 100 点处绘制字符串。之后,你调用 showPage() 方法。 showPage() 方法将保存画布的当前页面。其实不要求,但是推荐。

    方法还会结束当前页面。如果您在调用 showPage()后绘制另一个字符串或其他元素,该对象将被绘制到一个新页面。最后,调用 canvas 对象的 save()方法,将文档保存到磁盘。现在你可以打开它,看看我们的 PDF 是什么样的:

    您可能会注意到,您的文本位于文档底部附近。原因是原点(0,0)是文档的左下角。因此,当您告诉 ReportLab 绘制您的文本时,您是在告诉它从左侧开始绘制 100 个点,从底部开始绘制 100 个点。这与在像 Tkinter 或 wxPython 这样的 Python GUI 框架中创建用户界面形成对比,其中原点在左上方。

    还要注意,因为您没有指定页面大小,所以它默认为 ReportLab 配置中的大小,通常是 A4。在 reportlab.lib.pagesizes 中可以找到一些常见的页面大小。

    现在您已经准备好查看画布的构造函数,看看它需要什么参数:

    def __init__(self,filename,
                 pagesize=None,
                 bottomup = 1,
                 pageCompression=None,
                 invariant = None,
                 verbosity=0,
                 encrypt=None,
                 cropMarks=None,
                 pdfVersion=None,
                 enforceColorSpace=None,
    

    在这里你可以看到你可以把页面大小作为一个参数传入。页面大小实际上是以磅为单位的宽度和高度的元组。如果您想改变默认的左下角的原点,那么您可以将 bottomup 参数设置为 0,这会将原点改变到左上角。

    pageCompression 参数默认为零或关闭。基本上,它会告诉 ReportLab 是否压缩每个页面。启用压缩后,文件生成过程会变慢。如果您的工作需要尽快生成 pdf,那么您会希望保持默认值零。

    但是,如果速度不是问题,并且您希望使用更少的磁盘空间,那么您可以打开页面压缩。请注意,pdf 中的图像总是被压缩的,因此打开页面压缩的主要用例是当每页有大量文本或大量矢量图形时。

    ReportLab 的用户指南没有提到不变参数的用途,所以我查看了源代码。根据消息来源,它用相同的时间戳信息产生可重复的、相同的 pdf。我从未见过任何人在他们的代码中使用这个参数,既然源代码说这是为了回归测试,我想你可以放心地忽略它。

    下一个参数是 verbosity,用于记录级别。在零(0)时,ReportLab 将允许其他应用程序从标准输出中捕获 PDF。如果您将其设置为一(1),则每次创建 PDF 时都会打印出一条确认消息。可能会添加额外的级别,但在撰写本文时,只有这两个级别有文档记录。

    encrypt 参数用于确定 PDF 是否应该加密,以及如何加密。缺省值显然是 None,这意味着根本没有加密。如果您传递一个要加密的字符串,该字符串将成为 PDF 的密码。如果您想要加密 PDF,那么您将需要创建一个report lab . lib . PDF encrypt . standard encryption的实例,并将其传递给 encrypt 参数。

    可以将 cropMarks 参数设置为 True、False 或某个对象。印刷厂使用裁切标记来知道在哪里裁切页面。当您在 ReportLab 中将 cropMarks 设置为 True 时,页面将比您设置的页面大小大 3 mm,并在边角添加一些裁剪标记。可以传递给裁剪标记的对象包含以下参数:边框宽度标记颜色标记宽度标记长度。对象允许您自定义裁剪标记。

    pdfVersion 参数用于确保 PDF 版本大于或等于传入的版本。目前,ReportLab 支持版本 1-4。

    最后, enforceColorSpace 参数用于在 PDF 中实施适当的颜色设置。您可以将其设置为以下选项之一:

  • 用于印刷的四分色
  • sep_cmyk
  • 当其中一个被设置时,一个标准的 _PDFColorSetter 可调用函数将被用来执行颜色强制。您还可以传入一个用于颜色实施的可调用。

    让我们回到你最初的例子,稍微更新一下。在 ReportLab 中,您可以使用点来定位元素(文本、图像等)。但是当你习惯使用毫米或英寸时,用点来思考就有点困难了。有一个巧妙的函数可以帮助你处理堆栈溢出:

    def coord(x, y, height, unit=1):
        x, y = x * unit, height -  y * unit
        return x, y
    

    这个函数需要你的 x 和 y 坐标以及页面的高度。也可以传入单位大小。这将允许您执行以下操作:

    # canvas_coords.py
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import letter
    from reportlab.lib.units import mm
    def coord(x, y, height, unit=1):
        x, y = x * unit, height -  y * unit
        return x, y
    c = canvas.Canvas("hello.pdf", pagesize=letter)
    width, height = letter
    c.drawString(*coord(15, 20, height, mm), text="Welcome to Reportlab!")
    c.showPage()
    c.save()
    

    在这个例子中,您向 coord 函数传递 x 和 y 坐标,但是您告诉它使用毫米作为您的单位。因此,不是以磅为单位,而是告诉 ReportLab,我们希望文本从页面左侧 15 毫米和顶部 20 毫米开始。

    是的,你没看错。当您使用坐标功能时,它使用高度从底部到顶部交换原点的 y。如果你已经将画布的底向上参数设置为零,那么这个函数就不会像预期的那样工作。事实上,您可以将坐标函数简化为以下内容:

    def coord(x, y, unit=1):
        x, y = x * unit, y * unit
        return x, y
    

    现在,您可以像这样更新前面的示例:

    # canvas_coords2.py
    from reportlab.pdfgen import canvas	
    from reportlab.lib.units import mm
    def coord(x, y, unit=1):
        x, y = x * unit, y * unit
        return x, y
    c = canvas.Canvas("hello.pdf", bottomup=0)
    c.drawString(*coord(15, 20, mm), text="Welcome to Reportlab!")
    c.showPage()
    c.save()
    

    这似乎很简单。您应该花一两分钟的时间来试验这两个例子。尝试更改传入的 x 和 y 坐标。然后尝试改变文本,看看会发生什么!

    canvas 对象有许多方法。在本节中,您将学习如何使用这些方法使您的 PDF 文档更有趣。最容易使用的方法之一是 setFont ,它将允许您使用 PostScript 字体名称来指定您想要使用的字体。这里有一个简单的例子:

    # font_demo.py
    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    def font_demo(my_canvas, fonts):
        pos_y = 750
        for font in fonts:
            my_canvas.setFont(font, 12)
            my_canvas.drawString(30, pos_y, font)
            pos_y -= 10
    if __name__ == '__main__':
        my_canvas = canvas.Canvas("fonts.pdf",
                                  pagesize=letter)
        fonts = my_canvas.getAvailableFonts()
        font_demo(my_canvas, fonts)
        my_canvas.save()
    

    为了让事情变得更有趣一点,您将使用getAvailableFonts()canvas 方法来获取您可以在运行代码的系统上使用的所有可用字体。然后你将把画布对象和字体名称列表传递给你的 font_demo ()函数。在这里,您循环遍历字体名称,设置字体,并调用 drawString ()方法将每个字体的名称绘制到页面上。

    您还会注意到,您已经为起始 Y 位置设置了一个变量,然后每次循环时都将这个变量减 10。这是为了让每个文本字符串绘制在单独的一行上。如果你不这样做,字符串会写在对方的顶部,你会以一片混乱结束。

    以下是运行字体演示的结果:

    如果您想使用 canvas 方法来改变字体颜色,那么您会希望查看 setFillColor 或它的一个相关方法。只要在绘制字符串之前调用它,文本的颜色也会改变。

    您可以使用画布的旋转方法从不同角度绘制文本。你还将学习如何使用翻译方法。让我们来看一个例子:

    # rotating_demo.py
    from reportlab.lib.pagesizes import letter
    from reportlab.lib.units import inch
    from reportlab.pdfgen import canvas
    def rotate_demo():
        my_canvas = canvas.Canvas("rotated.pdf",
                                  pagesize=letter)
        my_canvas.translate(inch, inch)
        my_canvas.setFont('Helvetica', 14)
        my_canvas.drawString(inch, inch, 'Normal')
        my_canvas.line(inch, inch, inch+100, inch)
        my_canvas.rotate(45)
        my_canvas.drawString(inch, -inch, '45 degrees')
        my_canvas.line(inch, inch, inch+100, inch)
        my_canvas.rotate(45)
        my_canvas.drawString(inch, -inch, '90 degrees')
        my_canvas.line(inch, inch, inch+100, inch)
        my_canvas.save()
    if __name__ == '__main__':
        rotate_demo()
    

    在这里,您使用 translate 方法将您的原点从左下方设置为距左下方一英寸并向上一英寸。然后你设置字体和字体大小。接下来,正常写出一些文本,然后在你画一个字符串之前,你把坐标系本身旋转 45 度。

    根据 ReportLab 用户指南,由于坐标系现在处于旋转状态,您可能希望以负数指定 y 坐标。如果你不这样做,你的字符串将被绘制在页面的边界之外,你将看不到它。最后,将坐标系再旋转 45 度,总共旋转 90 度,写出最后一个字符串并绘制最后一条线。

    每次旋转坐标系时,观察线条如何移动是很有趣的。你可以看到最后一行的原点一直移动到了页面的最左边。

    以下是运行代码时的结果:

    现在是时候学习对齐了。

    字符串对齐

    画布支持更多的字符串方法,而不仅仅是普通的 drawString 方法。您也可以使用 drawRightString,它将绘制与 x 坐标右对齐的字符串。您也可以使用 drawAlignedString,它将绘制一个与第一个轴心字符对齐的字符串,默认为句点。

    如果您想在页面上排列一系列浮点数,这很有用。最后,还有 drawCentredString 方法,它将绘制一个以 x 坐标为“中心”的字符串。让我们来看看:

    # string_alignment.py
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import letter
    def string_alignment(my_canvas):
        width, height = letter
        my_canvas.drawString(80, 700, 'Standard String')
        my_canvas.drawRightString(80, 680, 'Right String')
        numbers = [987.15, 42, -1,234.56, (456.78)]
        y = 650
        for number in numbers:
            my_canvas.drawAlignedString(80, y, str(number))
            y -= 20
        my_canvas.drawCentredString(width / 2, 550, 'Centered String')
        my_canvas.showPage()
    if __name__ == '__main__':
        my_canvas = canvas.Canvas("string_alignment.pdf")
        string_alignment(my_canvas)
        my_canvas.save()
    

    当您运行这段代码时,您将很快看到这些字符串是如何对齐的。

    下面是运行代码的结果:

    接下来你要学习的画布方法是如何绘制线条、矩形和网格!

    在画布上画线

    在 ReportLab 中画线其实挺容易的。一旦您习惯了它,您实际上可以在您的文档中创建非常复杂的绘图,尤其是当您将它与 ReportLab 的一些其他功能结合使用时。画直线的方法简单来说就是线

    以下是一些示例代码:

    # drawing_lines.py
    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    def draw_lines(my_canvas):
        my_canvas.setLineWidth(.3)
        start_y = 710
        my_canvas.line(30, start_y, 580, start_y)
        for x in range(10):
            start_y -= 10
            my_canvas.line(30, start_y, 580, start_y)
    if __name__ == '__main__':
        my_canvas = canvas.Canvas("lines.pdf", pagesize=letter)
        draw_lines(my_canvas)
        my_canvas.save()
    

    这里您创建了一个简单的 draw_lines 函数,它接受一个 canvas 对象作为它的唯一参数。然后通过设置线宽方法设置线条的宽度。最后,创建一条直线。line 方法接受四个参数: x1,y1,x2,y2 。这些是开始的 x 和 y 坐标以及结束的 x 和 y 坐标。通过使用一个用于循环的来添加另外 10 行。

    如果您运行这段代码,您的输出将如下所示:

    画布支持其他几种绘图操作。例如,你也可以画矩形、楔形和圆形。这里有一个简单的演示:

    # drawing_polygons.py
    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    def draw_shapes():
        c = canvas.Canvas("draw_other.pdf")
        c.setStrokeColorRGB(0.2, 0.5, 0.3)
        c.rect(10, 740, 100, 80, stroke=1, fill=0)
        c.ellipse(10, 680, 100, 630, stroke=1, fill=1)
        c.wedge(10, 600, 100, 550, 45, 90, stroke=1, fill=0)
        c.circle(300, 600, 50)
        c.save()
    if __name__ == '__main__':
        draw_shapes()
    

    当您运行这段代码时,您应该会得到一个类似这样的文档:

    让我们花点时间来看一下这些多边形方法接受的各种参数。rect 的代码签名如下所示:

    def rect(self, x, y, width, height, stroke=1, fill=0):
    

    这意味着您通过其 x/y 参数设置矩形位置的左下角。然后你设置它的宽度高度。stroke 参数告诉 ReportLab 它是否应该画线,因此在演示代码中,我设置 stroke=1 或 True。fill 参数告诉 ReportLab 用一种颜色填充我绘制的多边形的内部。

    现在让我们看看椭圆的定义:

    def ellipse(self, x1, y1, x2, y2, stroke=1, fill=0):
    

    这个和 rect 很像。根据方法的 docstring,x1、y1、x2、y2 参数是外接矩形的角点。stroke 和 fill 参数的操作方式与 rect 相同。只是为了好玩,你继续设置椭圆的填充为 1。

    接下来,你有楔子:

    def wedge(self, x1,y1, x2,y2, startAng, extent, stroke=1, fill=0):
    

    楔形体的 x1、y1、x2、y2 参数实际上对应于围绕楔形体的完整 360 度圆形的不可见封闭矩形的坐标。所以你需要想象一个有矩形环绕的完整的圆来帮助你正确定位一个楔子。它也有一个起始角度参数( startAng )和范围参数,基本上是告诉楔形区要弧出多远。其他参数已经解释过了。

    最后,你到达多边形。它的方法如下所示:

    def circle(self, x_cen, y_cen, r, stroke=1, fill=0):
    

    在你看过的所有多边形中,圆的论点可能是最不言自明的。x_cen 和 y_cen 参数是圆心的 x/y 坐标。r 参数是半径。描边和填充参数非常明显。

    所有多边形都能够通过 setStrokeColorRGB 方法设置笔画(或线条)颜色。它接受红色、绿色、蓝色的参数值。您也可以使用 setStrokeColorsetStrokeColorCMYK 方法设置描边颜色。

    也有相应的填充颜色设置器(即 setFillColorsetfillcolorgbsetFillColorCMYK ),虽然这些方法在这里没有演示。您可以通过将正确的名称或元组传递给适当的函数来使用这些函数。

    现在,您已经准备好了解如何添加分页符了!

    创建分页符

    使用 ReportLab 创建 PDF 时,您首先需要知道的一件事是如何添加分页符,以便您可以拥有多页 PDF 文档。canvas 对象允许您通过 showPage 方法来实现这一点。

    但是请注意,对于复杂的文档,您几乎肯定会使用 ReportLab 的 flowables,这是专门用于跨多个页面“流动”您的文档的特殊类。Flowables 本身就有点令人费解,但比起试图一直跟踪你在哪一页和你的光标位置,它们使用起来要好得多。

    画布方向(纵向与横向)

    ReportLab 将其页面方向默认为纵向,这也是所有文字处理程序所做的。但有时你会想用横向页面来代替。至少有两种方法可以告诉 Reportlab 使用风景:

    from reportlab.lib.pagesizes import landscape, letter
    from reportlab.pdfgen import canvas
    c = canvas.Canvas('test.pdf', pagesize=letter)
    c.setPageSize( landscape(letter) )
    

    设置横向的另一种方法是直接设置页面大小:

    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    from reportlab.lib.units import inch
    c = canvas.Canvas('test.pdf', pagesize=letter)
    c.setPageSize( (11*inch, 8.5*inch) )
    

    您可以通过这样做来使它更通用:

    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    width, height = letter
    c = canvas.Canvas('test.pdf', pagesize=letter)
    c.setPageSize( (height, width) )
    

    这可能更有意义,尤其是如果您想使用其他流行的页面大小,如 A4。

    一个简单的示例应用程序

    有时候,看看你如何运用你所学到的东西,看看是否能应用到实践中,这是一件好事。因此,让我们采用您在这里学到的一些方法,创建一个简单的应用程序来创建一个表单:

    # sample_form_letter.py
    from reportlab.lib.pagesizes import letter
    from reportlab.pdfgen import canvas
    def create_form(filename, date, amount, receiver):
        @param date: The date to use
        @param amount: The amount owed
        @param receiver: The person who received the amount owed
        my_canvas = canvas.Canvas(filename, pagesize=letter)
        my_canvas.setLineWidth(.3)
        my_canvas.setFont('Helvetica', 12)
        my_canvas.drawString(30, 750,'OFFICIAL COMMUNIQUE')
        my_canvas.drawString(30, 735,'OF ACME INDUSTRIES')
        my_canvas.drawString(500, 750, date)
        my_canvas.line(480, 747, 580, 747)
        my_canvas.drawString(275, 725,'AMOUNT OWED:')
        my_canvas.drawString(500, 725, amount)
        my_canvas.line(378,723, 580, 723)
        my_canvas.drawString(30, 703,'RECEIVED BY:')
        my_canvas.line(120, 700, 580, 700)
        my_canvas.drawString(120, 703, receiver)
        my_canvas.save()
    if __name__ == '__main__':
        create_form('form.pdf', '01/23/2018',
                    '$1,999', 'Mike')
    

    这里创建一个名为 create_form 的简单函数,它接受文件名、表单日期、欠款金额和收款人。然后,在所需的位置绘制所有内容,并保存文件。运行该程序时,您将看到以下内容:

    对于一小段代码来说,这看起来相当专业。

    在本教程中,您了解了许多关于 ReportLab 画布及其许多方法的内容。虽然没有涵盖所有的 canvas 方法,但是您现在已经知道如何执行以下操作:

  • 了解字体和文本颜色
  • 创建文本对象
  • 画各种形状
  • 试试 ReportLab。你会发现它非常有用,很快你就可以创建自己的令人惊叹的 PDF 报告了!

    想了解更多关于 ReportLab 和 Python 的信息吗?查看以下一些资源:

    ReportLab - 关于字体的一切

    reportlab—如何使用 Python 在 pdf 中创建条形码

    Reportlab 表格–使用 Python 在 pdf 中创建表格

    ReportLab: 使用 Python 向 PDF 添加图表

    virtualenv 入门

    原文:https://www.blog.pythonlibrary.org/2012/07/17/getting-started-with-virtualenv/

    虚拟环境对于测试软件来说非常方便。在编程界也是如此。Ian Bicking 创建了 virtualenv 项目,这是一个用于创建隔离 Python 环境的工具。你可以使用这些环境来测试你的软件的新版本,你所依赖的软件包的新版本,或者只是作为一个沙箱来测试一些新的软件包。当您不能将文件复制到站点包中时,您也可以使用 virtualenv 作为工作空间,因为它位于共享主机上。当您使用 virtualenv 创建一个虚拟环境时,它会创建一个文件夹,并将 Python 与一个 site-packages 文件夹和几个其他文件夹一起复制到其中。它还安装 pip。一旦你的虚拟环境被激活,就像使用普通的 Python 一样。完成后,您可以删除要清理的文件夹。没有混乱,没有大惊小怪。或者,您可以继续使用它进行开发。

    在本文中,我们将花一些时间来了解 virtualenv 以及如何使用它来制作我们自己的魔术。

    首先你大概需要安装 virtualenv。你可以使用 pip 或 easy_install 来安装它,或者你可以从他们的网站下载 virtualenv.py 文件,然后这样安装。此时,假设您的 Python 文件夹在系统路径上,您应该能够在命令行上调用 virtualenv

    创建虚拟环境

    用 virtualenv 包创建一个虚拟沙箱是相当容易的。你只需要做以下事情:

    python virtualenv.py FOLDER_NAME

    其中,FOLDER_NAME 是您希望沙盒所在的文件夹的名称。在我的 Windows 7 机器上,我将 C:\Python26\Scripts 添加到我的路径中,这样我就可以只调用 virtualenv.py FOLDER_NAME 而不用 Python 部分。如果你没有传递任何东西,那么你会在屏幕上看到一个选项列表。假设我们创建了一个名为沙盒的项目。我们如何使用它?我们需要激活它。方法如下:

    在 Posix 上你可以做 source bin/activate 而在 Windows 上,你可以在命令行上做\ path \ to \ env \ Scripts \ activate。让我们实际经历这些步骤。我们将在桌面上创建 sandbox 文件夹,这样您就可以看到一个示例。这是它在我的机器上的样子:

    C:\Users\mdriscoll\Desktop>virtualenv sandbox New python executable in sandbox\Scripts\python.exe Installing setuptools................done. Installing pip...................done. C:\Users\mdriscoll\Desktop>sandbox\Scripts\activate (sandbox) C:\Users\mdriscoll\Desktop>

    您将会注意到,一旦您的虚拟环境被激活,您将会看到您的提示更改为包含您创建的文件夹名称的前缀,在本例中是“sandbox”。这让你知道你正在使用你的沙箱。现在,您可以使用 pip 将其他包安装到您的虚拟环境中。完成后,您只需调用 deactivate 脚本来退出环境。

    在创建虚拟游乐场时,有几个标志可以传递给 virtualenv,您应该知道。例如,您可以使用 - system-site-packages 来继承默认 Python 站点包中的包。如果你想使用 distribute 而不是 setuptools,你可以给 virtualenv 传递 - distribute 标志。

    virtualenv 还为您提供了一种只安装库,但使用系统 Python 本身来运行它们的方法。根据文档,您只需创建一个特殊的脚本来完成它。你可以在这里阅读更多

    还有一个简洁的(实验性的)标志叫做 -可重定位的,可以用来使文件夹可重定位。然而,在我写这篇文章的时候,它还不能在 Windows 上运行,所以我无法测试它。

    最后,还有一个 - extra-search-dir 标志,您可以使用它来保持您的虚拟环境离线。基本上,它允许您在搜索路径中添加一个目录,以便安装 pip 或 easy_install。这样,您就不需要访问互联网来安装软件包。

    至此,你应该可以自己使用 virtualenv 了。在这一点上,有几个其他项目值得一提。有道格·赫尔曼的 virtualenvwrapper 库,它使创建、删除和管理虚拟环境变得更加容易,还有 zc.buildout ,它可能是最接近 virtualenv 的东西,可以被称为竞争对手。我建议把它们都看看,因为它们可能对你的编程冒险有所帮助。

    在 wxPython 中跨平台获取正确的笔记本选项卡

    原文:https://www.blog.pythonlibrary.org/2019/06/05/getting-the-correct-notebook-tab-across-platforms-in-wxpython/

    我最近在开发一个 GUI 应用程序,它有一个wx.Notebook in it. When the user changed tabs in the notebook, I wanted the application to do an update based on the newly shown (i.e. selected) tab. I quickly discovered that while it is easy to catch the tab change event, getting the right tab is not as obvious.

    这篇文章将带你了解我的错误,并向你展示两个解决问题的方法。

    下面是我最初做的一个例子:

    # simple_note.py import random import wx class TabPanel(wx.Panel): def __init__(self, parent, name): """""" super().__init__(parent=parent) self.name = name colors = ["red", "blue", "gray", "yellow", "green"] self.SetBackgroundColour(random.choice(colors)) btn = wx.Button(self, label="Press Me") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(btn, 0, wx.ALL, 10) self.SetSizer(sizer) class DemoFrame(wx.Frame): Frame that holds all other widgets def __init__(self): """Constructor""" super().__init__(None, wx.ID_ANY, "Notebook Tutorial", size=(600,400) panel = wx.Panel(self) self.notebook = wx.Notebook(panel) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_tab_change) tabOne = TabPanel(self.notebook, name='Tab 1') self.notebook.AddPage(tabOne, "Tab 1") tabTwo = TabPanel(self.notebook, name='Tab 2') self.notebook.AddPage(tabTwo, "Tab 2") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5) panel.SetSizer(sizer) self.Layout() self.Show() def on_tab_change(self, event): # Works on Windows and Linux, but not Mac current_page = self.notebook.GetCurrentPage() print(current_page.name) event.Skip() if __name__ == "__main__": app = wx.App(False) frame = DemoFrame() app.MainLoop()

    这段代码可以在 Linux 和 Windows 上正常运行。然而,当你在 Mac OSX 上运行它时,报告的当前页面总是你在选择当前页面之前所在的标签。这有点像一个错误,但是是在 GUI 中。

    在尝试了我自己的一些想法后,我决定向 wxPython Google group 寻求帮助。

    他们有两种解决方法:

  • 使用GetSelection() along with the notebook's GetPage() method``
  • 使用平板笔记本小部件
  • 使用 GetSelection()

    使用事件对象的GetSelection() method will return the index of the currently selected tab. Then you can use the notebook's GetPage() method to get the actual page. This was the suggestion that Robin Dunn, the maintainer of wxPython, gave to me.``

    下面是更新后使用该修复程序的代码:

    # simple_note2.py import random import wx class TabPanel(wx.Panel): def __init__(self, parent, name): """""" super().__init__(parent=parent) self.name = name colors = ["red", "blue", "gray", "yellow", "green"] self.SetBackgroundColour(random.choice(colors)) btn = wx.Button(self, label="Press Me") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(btn, 0, wx.ALL, 10) self.SetSizer(sizer) class DemoFrame(wx.Frame): Frame that holds all other widgets def __init__(self): """Constructor""" super().__init__(None, wx.ID_ANY, "Notebook Tutorial", size=(600,400) panel = wx.Panel(self) self.notebook = wx.Notebook(panel) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_tab_change) tabOne = TabPanel(self.notebook, name='Tab 1') self.notebook.AddPage(tabOne, "Tab 1") tabTwo = TabPanel(self.notebook, name='Tab 2') self.notebook.AddPage(tabTwo, "Tab 2") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5) panel.SetSizer(sizer) self.Layout() self.Show() def on_tab_change(self, event): # Works on Windows, Linux and Mac current_page = self.notebook.GetPage(event.GetSelection()) print(current_page.name) event.Skip() if __name__ == "__main__": app = wx.App(False) frame = DemoFrame() app.MainLoop()

    这是一个相当简单的修复,但有点烦人,因为不清楚为什么需要这么做。

    使用平板笔记本

    另一个选择是换掉wx.Notebook for the FlatNotebook. Let's see how that looks:

    # simple_note.py import random import wx import wx.lib.agw.flatnotebook as fnb class TabPanel(wx.Panel): def __init__(self, parent, name): """""" super().__init__(parent=parent) self.name = name colors = ["red", "blue", "gray", "yellow", "green"] self.SetBackgroundColour(random.choice(colors)) btn = wx.Button(self, label="Press Me") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(btn, 0, wx.ALL, 10) self.SetSizer(sizer) class DemoFrame(wx.Frame): Frame that holds all other widgets def __init__(self): """Constructor""" super().__init__(None, wx.ID_ANY, "Notebook Tutorial", size=(600,400) panel = wx.Panel(self) self.notebook = fnb.FlatNotebook(panel) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_tab_change) tabOne = TabPanel(self.notebook, name='Tab 1') self.notebook.AddPage(tabOne, "Tab 1") tabTwo = TabPanel(self.notebook, name='Tab 2') self.notebook.AddPage(tabTwo, "Tab 2") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5) panel.SetSizer(sizer) self.Layout() self.Show() def on_tab_change(self, event): # Works on Windows, Linux and Mac current_page = self.notebook.GetCurrentPage() print(current_page.name) event.Skip() if __name__ == "__main__": app = wx.App(False) frame = DemoFrame() app.MainLoop()

    现在你可以回到使用笔记本的GetCurrentPage() method. You can also use self.notebook.GetPage(event.GetSelection()) like you do in the other workaround, but I feel like `GetCurrentPage() is just more obvious what it is that you are doing.

    这是我在 wxPython 中被一个奇怪的陷阱抓住的少数几次之一。当您编写旨在跨多个平台运行的代码时,您会不时地遇到这类事情。检查文档以确保您没有使用并非所有平台都支持的方法总是值得的。然后你会想自己做一些研究和测试。但是一旦你做了你的尽职调查,不要害怕寻求帮助。我会一直寻求帮助,避免浪费我自己的时间,尤其是当我的解决方案在三分之二的情况下都有效的时候。

    使用 Python 获取 Windows 系统信息

    原文:https://www.blog.pythonlibrary.org/2010/01/27/getting-windows-system-information-with-python/

    我不得不为我的雇主想出的另一个脚本处理关于我们每个用户的物理机器的各种信息。我们希望跟踪他们的 CPU 速度、硬盘大小和 RAM 容量(以及其他信息),这样我们就能知道什么时候该升级他们的电脑了。从互联网上的各个地方收集所有的碎片是一件非常痛苦的事情,所以为了省去你的麻烦,我将把我发现的贴出来。请注意,这些代码中有很多是从 ActiveState 或邮件列表上的各种食谱中提取的。以下大部分内容几乎一字不差地出现在这份食谱中。

    出于我不明白的原因,我们想知道用户在他们的机器上安装了哪个 Windows 操作系统。当我开始的时候,我们混合了 Windows 98 和 Windows XP Professional,后者超过了 90%。不管怎样,下面是我们用来判断用户正在运行什么的脚本:

    def get_registry_value(key, subkey, value): import _winreg key = getattr(_winreg, key) handle = _winreg.OpenKey(key, subkey) (value, type) = _winreg.QueryValueEx(handle, value) return value def os_version(): def get(key): return get_registry_value( "HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", os = get("ProductName") sp = get("CSDVersion") build = get("CurrentBuildNumber") return "%s %s (build %s)" % (os, sp, build)

    正确运行这段代码的方法是调用 os_version 函数。这将使用两个不同的键调用嵌套的 get 函数两次,以获取操作系统和服务包。从嵌套函数中调用了 get_registry_value 两次,我们也直接调用它来获取构建信息。最后,我们使用字符串替换来组合一个代表 PC 操作系统版本的字符串。

    下面的代码片段用于找出客户端电脑中的处理器:

    def cpu(): cputype = get_registry_value( "HKEY_LOCAL_MACHINE", "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString") except: import wmi, pythoncom pythoncom.CoInitialize() c = wmi.WMI() for i in c.Win32_Processor (): cputype = i.Name pythoncom.CoUninitialize() if cputype == 'AMD Athlon(tm)': c = wmi.WMI() for i in c.Win32_Processor (): cpuspeed = i.MaxClockSpeed cputype = 'AMD Athlon(tm) %.2f Ghz' % (cpuspeed / 1000.0) elif cputype == 'AMD Athlon(tm) Processor': import wmi c = wmi.WMI() for i in c.Win32_Processor (): cpuspeed = i.MaxClockSpeed cputype = 'AMD Athlon(tm) %s' % cpuspeed else: return cputype

    注意,如果你想继续下去,你需要下载蒂姆·戈尔登的 WMI (Windows 管理规范)模块,我认为它依赖于 PyWin32 包(即使不是,在后面的例子中你也需要那个包)。请注意,我们首先尝试使用在前面的示例中定义的函数从 Windows 注册表中获取 cpu 类型。如果失败了,我们就用 WMI 模块来得到它。这样做的主要原因是在注册表中查找比拨打 WMI 电话要快。还要注意,我们将 WMI 代码包装在 pythoncom 方法中。我记得,之所以有这些,是因为我们在一个线程中运行这个脚本,你需要初始化的东西,让 WMI 高兴。否则,你会以一些愚蠢的错误或崩溃而告终。如果你不想用线,那么我想你可以去掉那些线。

    这个片段中的下一部分是一个条件,它检查返回哪种 cpu 类型。如果它是一个 AMD 处理器,那么我们做另一个 WMI 调用来获得处理器的时钟速度,并将其添加到 CPU 字符串中。否则,我们只是按原样返回字符串(这通常意味着安装了 Intel 芯片)。

    我们使用 VNC 连接到我们的大多数机器,所以我们想知道机器的名称。为此,我们运行以下命令:

    from platform import node def compname(): return get_registry_value( "HKEY_LOCAL_MACHINE", 'SYSTEM\\ControlSet001\\Control\\ComputerName\\ComputerName', 'ComputerName') except: compName = node return compName

    同样,我们首先检查 Windows 注册表,看看我们想要的东西是否存放在那里。如果失败,那么我们使用 Python 的平台模块。如您所见,我们使用了 bare except 语句,这是我们的糟糕设计。我必须解决这个问题。在我的辩护中,我在成为 Python 程序员的第一年就做了大部分这样的东西,我真的不知道还有什么更好的。无论如何,还有另一种方法可以得到这些信息,那就是 WMI:

    c = wmi.WMI() for i in c.Win32_ComputerSystem(): compname = i.Name

    这不是很简单吗?我真的很喜欢这个东西,虽然我不知道为什么我们必须使用一个循环来获取 WMI 的信息。如果你知道,请在下面的评论中给我留言。

    下一个话题是网络浏览器。在我工作的地方,除了 Internet Explorer,我们还在所有的机器上安装了 Mozilla Firefox。奇怪的是,我们有许多供应商没有升级他们的软件或网站,使其在 Internet Explorer 8 上正常运行,所以当微软推出更新时,我们有时会遇到问题。这为我们介绍了下一段代码:

    def firefox_version(): version = get_registry_value( "HKEY_LOCAL_MACHINE", "SOFTWARE\\Mozilla\\Mozilla Firefox", "CurrentVersion") version = (u"Mozilla Firefox", version) except WindowsError: version = None return version def iexplore_version(): version = get_registry_value( "HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Internet Explorer", "Version") version = (u"Internet Explorer", version) except WindowsError: version = None return version def browsers(): browsers = [] firefox = firefox_version() if firefox: browsers.append(firefox) iexplore = iexplore_version() if iexplore: browsers.append(iexplore) return browsers

    正确的运行方式是调用浏览器函数。它将调用另外两个函数,这两个函数继续重用我们从 Windows 注册表中获取所需信息的 get_registry_value 。这件作品有点无聊,但很容易使用。

    我们的下一个脚本将获得大约安装的 RAM:

    import ctypes def ram(): kernel32 = ctypes.windll.kernel32 c_ulong = ctypes.c_ulong class MEMORYSTATUS(ctypes.Structure): _fields_ = [ ('dwLength', c_ulong), ('dwMemoryLoad', c_ulong), ('dwTotalPhys', c_ulong), ('dwAvailPhys', c_ulong), ('dwTotalPageFile', c_ulong), ('dwAvailPageFile', c_ulong), ('dwTotalVirtual', c_ulong), ('dwAvailVirtual', c_ulong) memoryStatus = MEMORYSTATUS() memoryStatus.dwLength = ctypes.sizeof(MEMORYSTATUS) kernel32.GlobalMemoryStatus(ctypes.byref(memoryStatus)) mem = memoryStatus.dwTotalPhys / (1024*1024) availRam = memoryStatus.dwAvailPhys / (1024*1024) if mem >= 1000: mem = mem/1000 totalRam = str(mem) + ' GB' else: # mem = mem/1000000 totalRam = str(mem) + ' MB' return (totalRam, availRam)

    当我最初写这篇文章时,我使用了下面的 WMI 方法:

    c = wmi.WMI() for i in c.Win32_ComputerSystem(): mem = int(i.TotalPhysicalMemory)

    它后面的条件是我的,但它们的主要用途是使返回的数字更有意义。我还没有完全理解 ctypes 是如何工作的,但是可以说上面的代码比 WMI 方法在更低的层次上获得信息。可能也会快一点。

    最后一部分是获取硬盘空间,这是通过以下方式完成的:

    def _disk_c(self): drive = unicode(os.getenv("SystemDrive")) freeuser = ctypes.c_int64() total = ctypes.c_int64() free = ctypes.c_int64() ctypes.windll.kernel32.GetDiskFreeSpaceExW(drive, ctypes.byref(freeuser), ctypes.byref(total), ctypes.byref(free)) return freeuser.value

    这是原始配方作者使用 ctypes 的另一个例子。因为我不想听起来像个白痴,所以我不会假装理解得足够好来解释它。然而,Tim Golden 展示了一个类似的使用 WMI 查找硬盘剩余空闲空间的方法,您可能会感兴趣。去他的网站看看就知道了。

    我希望这些都有意义。如果你有任何关于它的问题让我知道,我将尽力回答。

    使用 Python 获得屏幕分辨率

    原文:https://www.blog.pythonlibrary.org/2015/08/18/getting-your-screen-resolution-with-python/

    我最近在寻找用 Python 获得我的屏幕分辨率的方法,以帮助诊断一个不能正常运行的应用程序的问题。在这篇文章中,我们将看看获得屏幕分辨率的一些方法。并非所有的解决方案都是跨平台的,但是在讨论这些方法时,我一定会提到这一点。我们开始吧!

    使用 Linux 命令行

    在 Linux 中有几种方法可以获得你的屏幕分辨率。如果你在谷歌上搜索,你会看到人们使用各种 Python GUI 工具包。我想找到一种不用安装第三方模块就能获得屏幕分辨率的方法。我最终找到了以下命令:

    xrandr | grep '*'

    然后我必须把这些信息翻译成 Python。这是我想到的:

    import subprocess cmd = ['xrandr'] cmd2 = ['grep', '*'] p = subprocess.Popen(cmd, stdout=subprocess.PIPE) p2 = subprocess.Popen(cmd2, stdin=p.stdout, stdout=subprocess.PIPE) p.stdout.close() resolution_string, junk = p2.communicate() resolution = resolution_string.split()[0] width, height = resolution.split('x')

    每当需要使用 Python 传输数据时,都需要创建两个不同的子流程实例。以上就是我做的。我通过 stdin 将来自 xrandr 的输出传送到我的第二个子流程。然后,我关闭了第一个进程的 stdout,基本上清除了它返回给第二个进程的所有内容。剩下的代码只是解析出监视器的宽度和高度。

    使用 PyGTK

    当然,上面的方法只适用于 Linux。如果你碰巧安装了 PyGTK ,那么你可以用它来获得你的屏幕分辨率。让我们来看看:

    import gtk width = gtk.gdk.screen_width() height = gtk.gdk.screen_height()

    这非常简单,因为 PyGTK 内置了这些方法。请注意,PyGTK 适用于 Windows 和 Linux。应该还有一个正在开发中的 Mac 版本。

    使用 wxPython

    正如您所料, wxPython 工具包也提供了一种获得屏幕分辨率的方法。它的用处不大,因为您实际上需要创建一个 App 对象,然后才能获得解决方案。

    import wx app = wx.App(False) width, height = wx.GetDisplaySize()

    这仍然是获得您想要的分辨率的简单方法。还应该注意的是,wxPython 运行在所有三个主要平台上。

    使用 Tkinter

    Tkinter 库通常包含在 Python 中,所以您应该将这个库作为默认库。它还提供屏幕分辨率,尽管它也要求您创建一个“app”对象:

    import Tkinter root = Tkinter.Tk() width = root.winfo_screenwidth() height = root.winfo_screenheight()

    幸运的是,Tkinter 也可以在所有 3 个主要平台上使用,所以你几乎可以在任何地方使用这种方法。

    使用 PySide / PyQt

    正如你可能已经猜到的,你也可以使用 PySidePyQt 来获得屏幕分辨率。以下是 PySide 版本:

    from PySide import QtGui app = QtGui.QApplication([]) screen_resolution = app.desktop().screenGeometry() width, height = screen_resolution.width(), screen_resolution.height()

    如果您使用 PyQt4,那么您需要将开头的导入更改为:

    from PyQt4 import QtGui

    其余都一样。你可能知道,这两个库都可以在 Windows、Linux 和 Mac 上使用。

    此时,您应该能够在任何操作系统上获得屏幕分辨率。还有其他方法可以获得这些信息,这些方法依赖于平台。例如,在 Windows 上,您可以使用 PyWin32 的 win32api 或 ctypes。在 Mac 上,有 AppKit。但是这里列出的工具包方法可以在大多数平台上很好地工作,因为它们是跨平台的,所以您不需要使用特殊的情况来导入特定的包来使其工作。

  • 在 Ubuntu 上用 Python 获取显示器分辨率
  • 如何在 Python 中获得显示器分辨率?
  • 圭多以 BDFL 的身份退休

    原文:https://www.blog.pythonlibrary.org/2018/07/13/guido-retire-as-bdfl/

    Python 的创造者,仁慈的终身独裁者(BDFL 饰)吉多·范·罗苏姆已经退休,成为 BDFL,截至 2018 年 7 月 12 日没有继任者。参见下面来自 Python 提交者列表的电子邮件,了解全部细节。

    基本上有很多关于 PEP 572 赋值表达式的负面意见,这似乎促使 Python 的创造者提前退休。虽然他仍然会在周围提供帮助和指导,但他将不再以同样的方式参与社区活动。

    我喜欢 Python 和它的社区,所以 Guido 以这种方式下台让我很难过。不过,我希望他一切顺利,并将继续在我们的社区中使用和推广 Python 和文明。

    Python 书籍的假日销售

    原文:https://www.blog.pythonlibrary.org/2016/12/05/holiday-sale-on-python-books/

    现在是假期,所以我从今天开始把我所有的书都降价出售。拍卖将持续到 12 月 23 日。你可以在 Gumroad 或 Leanpub 上花 6.99 美元购买我的任何一本书。实际上,我现在推荐 Leanpub,因为我发现它的用户界面对我的读者来说更容易导航,但是如果你已经有一个 Gumroad 帐户,那么请随意使用它。

    您将从 Leanpub 和 Gumroad 收到 PDF、mobi 和 epub 格式的书籍。

    以下是链接:

    Gumroad

  • Python 101
  • Python 201:中级 Python
  • wxPython 食谱 (95%完成...您将收到早期版本+成品)
  • Leanpub

  • Python 101
  • Python 201:中级 Python
  • wxPython 食谱 (95%完成...您将收到早期版本+成品)
  • 我还有 10 份第一次运行的 Python 201:中级 Python 的拷贝,你现在可以购买。你还会收到这本书的电子版。请注意,第一次运行在 asyncio 章节中有一个错误,该错误已在数字副本中更正。平装本的未来版本将很快确定。

    我如何写关于 Python 的书

    原文:https://www.blog.pythonlibrary.org/2019/02/26/how-i-write-books-about-python/

    我不时会被问到关于我写书过程的问题,我一直想写这个话题。我写第一本书 Python 101 的主要原因是因为我博客上的读者。他们鼓励我写一本关于 wxPython 的书已经有一段时间了,我决定我应该从写一本介绍性的书开始,这样我就不需要在我的中级书籍中包括一大堆介绍性的信息,如果我有时间去写它的话。

    当我在写那本书的时候,我不得不寻找生成 PDF、mobi (Kindle)和 epub 格式的方法。我跳过了 Microsoft Word,因为我还没有找到将这种文档类型转换成其他文件类型的好方法,而且它在跨平台上也不太好用。

    我最终选择了重组文本。我也尝试过 Sphinx,但是在我给自己的时间框架内,我无法让它按照我想要的方式工作。然而,RestructuredText 允许我用 rst2pdf 轻松地转换成 PDF。

    然后我用 rst2html 创建了这本书的 html 版本。当你有了 HTML,你就可以使用图书转换工具 Calibre 来转换成 mobi 和 epub 格式。最后,我得到了一个 Python 脚本,它会调用 rst2pdf、rst2html 和 Calibre 将我的书转换成适当的格式。

    这工作得很好,但是没有创建一个非常好的目录。

    当我在开发 Python 101 的续集 Python 201:中级 Python 时,我发现了 Leanpub ,它对他们的书使用 Markdown,并将该格式转换为我想要的所有输出格式。输出看起来不错,最棒的是,它有一个合适的目录。

    因此,我目前的工具链(截至 2019 年初)现在是用 RestructuredText 编写,并使用 Pandoc 将其转换为 Markdown。我这样做是为了在我出于某种原因决定放弃 Leanpub 的情况下,更容易切换回我自己创作的图书制作脚本。坦白地说,我想做的是使用 ReportLab 创建一个脚本,可以将 Markdown 或 RestructuredText 转换为 PDF。我怀疑我可以得到同样质量的东西,至少是 pdf。

    2020 更新:我最终放弃了 RestructuredText,转而使用 Markdown,因为我发现 Pandoc 没有正确地转换代码示例和其他特殊结构。这导致语法突出显示无法正常工作。

    研究与开发

    当谈到为我的书选择主题时,我通常会使用我知道在我的博客上流行的主题。对于 Python 101 来说,有点不同,因为我已经阅读了许多关于 Python 的初学者书籍,并决定涵盖许多我在初学者书籍中不常看到的主题。其中一个例子是展示如何将代码发布到 PyPI 或者用 Python 创建可执行文件。

    我密切关注我博客上的统计数据,以了解哪些文章做得很好,因为这也给了我关于书籍内容的想法。在 ReportLab 上创作我的书的两个原因是

  • 没有这方面的书籍
  • ReportLab 上的文章往往在我的前 10 名中
  • Kickstarter 在这里也发挥了一些作用,因为我会问我的支持者他们认为书里应该有什么,然后我会把这些想法排序,决定哪些会成功,哪些不会。

    评论这本书

    作为一名自行出版的作者,我的管理非常严格。我没有出版商付钱让人评论我的作品,所以我必须有创意。在某种程度上,我最终把我的博客当成了一个测试网站。我通常会在我的博客上发布我的书的新章节,以被动地获得读者的反馈。我也相信让我的书大部分是开源的,所以把章节放在那里对我的读者和我需要查找的时候都很好。

    我也用 Kickstarter 做一些小的测试。通常会有支持者想要尽早阅读这本书,他们也给了我很多反馈。这很有帮助,这些书也因此变得更好。

    在这一点上,我已经和两家出版商合作过,他们都没有给我读者给我的那种支持和反馈。我感谢你们所有人。

    从读者那里获得反馈

    说到反馈,我主要通过 Kickstarter 和我博客上的评论获得反馈。我所有的书都有电子邮件地址,读者也可以用它给我发邮件。我确实通过这种方法收到了不少读者的邮件,但我认为我从我提到的前两个来源得到了更多。

    大多数反馈都是积极的,真的鼓励我继续写作。我偶尔会收到一些脾气暴躁的邮件,但即使是那些罕见的情况也有助于我看到我可以做得更好。

    更新您的图书

    当你选择写科技或计算机科学时,你知道你的书会随着时间的推移而过时。自助出版的最大好处之一是,我可以接受反馈,在几个小时或几天内修改一本书,并将这些更新直接推送给最终读者。在收到错误报告的几个小时内,我已经修复了错误并推出了新版本。

    我更新书籍有几个不同的原因:

  • 这本书现在已经过时了
  • 这本书有一个印刷错误
  • 这本书错了(该死!)
  • 我尽量写一些暂时不会改变的话题。例如,wxPython 和 ReportLab 不会经常以中断的方式进行更改。所以我可以写它们,而不用担心我的例子在书出版时会被破坏。Python 本身在很大程度上也是如此。然而从 3.5 开始,Python 的变化超出了我的预期,所以我确实需要重写 Python 101 来解释这些差异。

    谈到卖书,我最初的想法是把它贴在我的博客上,看看会发生什么。然后我意识到我可以用 Kickstarter 来衡量人们对我的想法的兴趣,所以我决定这么做。Kickstarter 在这方面很棒。这真的帮助我与我的读者建立了联系,并保持了早期采用者的反馈回路。

    Kickstarter 在更新书籍和我未来的作品方面也很好。请注意,Kickstarter 确实收取总额的 8-10%,所以如果你决定使用它,你需要记住这一点。

    我读到过,如果你做广告,你应该用不超过 5%的毛收入。我没怎么尝试过,因为我在网络广告方面的体验不是很好。

    现在我有多本书,我可以把它们以不同的方式捆绑在一起。Leanpub 还支持将你的书与他们平台上其他作者的书捆绑在一起,如果你能找到一些想要这样做的人的话。

    我最近开始在 Youtube 上做视频,我认为这有助于提高我的博客的知名度,但不是很多。Youtube 是一个非常不同的媒体,目前真的没有带来太多的流量,但我认为如果利用得当,它是可以的。

    你也可以使用 gum road 来销售你的书。如果你能找到代销商,你可以使用他们的代销商计划。我已经尝试了一下,看起来效果不错。Leanpub 停止了分支机构,这很不幸。

    与读者保持联系

    与你的读者保持联系是困难的。根据您的销售平台,您可能无法做到。例如,亚马逊和 Leanpub 根本不共享买家信息。读者可以在 Leanpub 上选择接收更新,但我看不到他们的任何信息。Gumroad 确实给了卖家一个电子邮件地址,所以你可以用它来建立一个邮件列表。只要确保你除掉了所有不感兴趣的人。

    正如我提到的,Kickstarter 对此很有用。我可以通过他们的网站向我所有的支持者发送更新。我还从他们那里得到了发送电子书的电子邮件地址。从技术上讲,你也可以用这种方式建立一个邮件列表。

    我应该指出,我没有这样做。我只使用电子邮件地址来递送他们的货物,然后我不会再打扰任何人,除非我需要。

    在你为一本书设定最后期限之前,你应该尽可能多地勾勒出这本书的轮廓。我发现创建一个我想涵盖的章节列表有助于我缩小书的范围。我通常会把章节列表拿出来,用几种不同的方式重新排序。然后我把它们削减到必须拥有的章节和想要拥有的章节。

    必读书籍是我所说的最少出货的书。这是我非常喜欢敏捷开发的一点,它确实很好地教授了范围界定。我想写的其他章节将在时间允许的情况下添加。这些是我通常在我的 Kickstarter 中作为延伸目标保留的章节,尽管除了这些延伸目标之外,我还有其他章节放在我的后兜里。

    额外章节的好处是,你可能会发现你的主列表没有足够的内容。然后你可以添加一些想拥有的章节来弥补差异。

    总之,所有这些都是说你需要写 4-10 章才能真正发现你的写作节奏是什么。一旦你知道了这一点,你就可以算出平均值,并预测你要花多长时间才能写出一本最少出货的书。这对我很有效。我知道我的速度是多少,然后我通常会在此基础上增加 1-3 个月,因为假期、旅行和不可避免的疾病似乎会在你最意想不到的时候突然出现。

    Github 已经成为事实上存储代码的地方。为了让我的读者简单起见,我已经开始把我的书的所有源代码放在与书相关的特定存储库中。然后,我可以在书的正文中添加一个链接,还可以从我的各种供应商网站上添加链接。

    理论上,您可以将一个持续集成服务挂接到 Github 或类似的可以针对您的代码运行 linters 和测试的服务上。虽然我没有这样做,但我认为这可能是一个非常好的想法,我可能会在未来的书中尝试这样做。

    让外国读者看到你的书有点难。幸运的是,亚马逊、Gumroad 和 Leanpub 确实在国际上销售,所以从技术上来说,世界上任何地方的人都可以看到你的书。然而,如果你想让他们能够用自己的语言阅读,那就变得困难多了。

    有几个人就翻译我的书找到我。你必须小心这类事情,因为你不知道他们是否有信誉。如果你想和某人一起工作并分享利润,Leanpub 提供了一种方法。然而,如果你把你的书的来源给了他们,他们就不会保护你,他们最终会把翻译贴在别的地方。

    有类似于 Babelcube 的服务,你可以用它来翻译你的书。我还没有尝试过这些,所以我真的不能评论

    电子书与印刷品

    你会从电子书中赚到大部分的钱。因此,创建所有三种最流行的格式是绝对值得的:PDF、epub 和 mobi。据 Leanpub 称,PDF 是目前最流行的。

    对于纸质书,我用的是 Lulu ,最近用的是亚马逊的 Createspace 。亚马逊的设置向导比 Lulu 的好。然而,他们每个人检查你的内容不同。如果你的截图分辨率太低,他们会告诉你。亚马逊会对你的作品进行拼写检查。

    你需要一张 300 dpi 的封面图片,正面和背面都要。否则会显得模糊。你应该有 300 dpi 的截图,但我发现在那个分辨率下获取截图几乎是不可能的。尽你所能把它们弄高。

    请注意,对于电子书封面,您不需要 300 dpi 的图像,因为这将使书籍的下载大小比它需要的大得多。这意味着你可以保留这本书的两个版本。

    还要注意,亚马逊和 Lulu 都不希望封面成为 PDF 打印版本的一部分。封面需要分开。

    作为一名技术作家,我喜欢对我的书进行修改。所以我用 Git 来做这个。我所有的源文件都进入 Git 存储库并保存在 Dropbox 和 Bitbucket 中。如果我开始使用技术评审员,我会考虑转而使用 Gitlab,因为他们对私有库有更好的政策。

    我希望这篇有些脱节的文章对你有所帮助。我将在另一篇文章中写更多关于 indy 出版的利与弊。如果你有任何问题,欢迎在评论中提问。

    如何用 Python 给你的照片添加边框

    原文:https://www.blog.pythonlibrary.org/2017/10/26/how-to-add-a-border-to-your-photos-with-python/

    有时给照片添加简单的边框很有趣。Pillow 软件包有一个非常简单的方法,通过它的 ImageOps 模块给你的图像添加这样的边框。像往常一样,您需要安装 Pillow 来完成本文中的任何示例。如果您还没有它,您可以使用 pip 安装它:

    pip install Pillow

    现在,我们已经处理好了那部分内务,让我们学习如何添加一个边框!

    本文的重点是使用 ImageOps 模块来添加我们的边框。对于这个例子,我们将使用我拍摄的这张整洁的蝴蝶照片。我们写点代码吧!

    from PIL import Image, ImageOps def add_border(input_image, output_image, border): img = Image.open(input_image) if isinstance(border, int) or isinstance(border, tuple): bimg = ImageOps.expand(img, border=border) else: raise RuntimeError('Border is not an integer or tuple!') bimg.save(output_image) if __name__ == '__main__': in_img = 'butterfly.jpg' add_border(in_img, output_image='butterfly_border.jpg', border=100)

    在上面的代码中,我们创建了一个可以接受三个参数的函数:

  • 输入图像路径
  • 输出图像路径
  • 边框,可以是一个整数或最多 4 个整数的元组,表示图像四个边中每一个边的像素
  • 我们打开输入图像,然后检查边界的类型。是 int 还是 tuple 还是别的?如果是前两者之一,我们通过调用 expand() 函数来添加边框。否则我们会引发一个错误,因为我们传入了一个无效的类型。最后,我们保存图像。这是我得到的结果:

    正如你所看到的,当你只是传入一个整数作为你的边界,它适用于图像的所有四边。如果我们希望顶部和底部的边界不同于右边和左边,我们需要指定。让我们更新代码,看看会发生什么!

    from PIL import Image, ImageOps def add_border(input_image, output_image, border): img = Image.open(input_image) if isinstance(border, int) or isinstance(border, tuple): bimg = ImageOps.expand(img, border=border) else: raise RuntimeError('Border is not an integer or tuple!') bimg.save(output_image) if __name__ == '__main__': in_img = 'butterfly.jpg' add_border(in_img, output_image='butterfly_border_top_bottom.jpg', border=(10, 50))

    在这里,我们想添加一个 10 像素的边界到左边和右边,一个 50 像素的边界到图片的顶部和底部。如果运行此代码,您应该会得到以下结果:

    现在让我们尝试为所有四个边指定不同的值!

    from PIL import Image, ImageOps def add_border(input_image, output_image, border): img = Image.open(input_image) if isinstance(border, int) or isinstance(border, tuple): bimg = ImageOps.expand(img, border=border) else: raise RuntimeError('Border is not an integer or tuple!') bimg.save(output_image) if __name__ == '__main__': in_img = 'butterfly.jpg' add_border(in_img, output_image='butterfly_border_all_different.jpg', border=(10, 30, 20, 50))

    在这个例子中,我们告诉 Pillow 我们想要一个左边是 10 像素,上边是 30 像素,右边是 20 像素,下边是 50 像素宽的边框。当我运行这段代码时,我得到了这个:

    坦白地说,我不知道为什么你希望所有的四个边都有不同大小的边框,但是如果你这样做了,就很容易应用了。

    更改边框颜色

    您还可以设置正在添加的边框的颜色。默认明显是黑色的。Pillow package 支持通过“rgb ”(即红色为“ff0000”)、“rgb(红、绿、蓝)”指定颜色,其中 RGB 值为 0 到 255 之间的整数、HSL 值或 HTML 颜色名称。让我们更新代码并给边框添加一些颜色:

    from PIL import Image, ImageOps def add_border(input_image, output_image, border, color=0): img = Image.open(input_image) if isinstance(border, int) or isinstance(border, tuple): bimg = ImageOps.expand(img, border=border, fill=color) else: raise RuntimeError('Border is not an integer or tuple!') bimg.save(output_image) if __name__ == '__main__': in_img = 'butterfly.jpg' add_border(in_img, output_image='butterfly_border_indianred.jpg', border=100, color='indianred')

    你会注意到我们在这里添加了一个新的参数来指定我们想要的边框颜色。默认为黑色,即零(0)。在这个例子中,我们传入了 HTML 颜色‘Indian red’。结果如下:

    通过将传入的值从' indianred '更改为' #CD5C5C ',可以获得相同的效果。

    只是为了好玩,试着把你传入的值改成‘RGB(255,215,0)’,这是一种金色。如果你这样做,你可以让你的边界看起来像这样:

    请注意,您也可以传入' gold '、' Gold '或' #FFD700 ',结果会是相同的颜色。

    此时,你应该知道如何给你的照片添加简单的边框。如您所见,您可以单独或成对更改每条边的边框颜色像素数量,甚至可以同时更改所有四条边的边框颜色像素数量。你也可以把边框的颜色改成任何颜色。花点时间研究一下代码,看看你能想出什么来!

  • Kanoki - 为你的照片画铅笔素描
  • 如何用 Python 给你的照片加水印
  • 如何用 Python 调整照片大小
  • 用 Python 将一张照片转换成黑白
  • 如何用 Python 旋转/镜像照片
  • 如何用 Python 裁剪照片
  • 使用 Python 增强照片
  • How to Override a List Attribute's Append() Method in Python

    原文:https://www.blog.pythonlibrary.org/2021/11/10/how-to-add-list-attribute-append-updates-to-a-class-in-python/

    I had a use-case where I needed to create a class that had an attribute that was a Python list. Seems simple, right? The part that made it complicated is that I needed to do something special when anything was appended to that attribute. Watching for attribute changes don't work the same way for lists as it would for a string.

    I tried a lot of different solutions, but most of them either didn't work or made the code really hard to understand.

    Finally, someone on the Real Python Slack channel mentioned sub-classing collections.UserList and over-riding the append() method so that it executed a callback whenever that list object was appended to.

    Here is a very simplified version of the code:

    import datetime
    from collections import UserList
    from dataclasses import dataclass, field
    from typing import Callable, Dict, List, Tuple
    class ListWithCallback(UserList):
        Create a class that emulates a Python list and supports a callback
        def __init__(self, callback: Callable, *args: Tuple, **kwargs: Dict
                     ) -> None:
            super().__init__(*args, **kwargs)
            self.callback = callback
        def append(self, item) -> None:
            super().append(item)
            self.callback()
    @dataclass
    class Media:
        channels: List = field(default_factory=list)
        def update(self) -> None:
            now = datetime.datetime.today()
            print(f"{now:%B %d - %H:%m:%S}")
        def __post_init__(self) -> None:
            self.channels = ListWithCallback(self.update)  # type: ignore
    if __name__ == "__main__":
        import time
        impl = Media()
        impl.channels.append("Blah")
        time.sleep(2)
        impl.channels.append("Blah")
    

    The main class of interest here is Media, which is a data class. It has a single attribute, channels, which is a Python list. To make this work, you use post_init() to set channels to an instance of your custom class, ListWithCallback. This class takes in a function or method to call when an item is appended to your special list.

    In this case, you call Media's update() method whenever an item is appended. To test that this functionality works, you import the time module at the bottom of the code and append two strings to the list with a sleep() between them.

    Wrapping Up

    If you ever find yourself needing to subclass a Python built-in, check out Python's collections module. It has several classes that are usually recommended over directly subclassing from the built-ins themselves. In this case, you used collections.UserList.

    Subclassing from the collections module is straightforward. You will learn a lot and your code may even be better because you did that.

    如何用 Python 检查文件是否是有效图像

    原文:https://www.blog.pythonlibrary.org/2020/02/09/how-to-check-if-a-file-is-a-valid-image-with-python/

    Python 的标准库中有许多模块。一个经常被忽视的是 imghdr ,它可以让你识别文件、字节流或类路径对象中包含的图像类型。

    imghdr 可以识别以下图像类型:

  • 可交换的图像格式
  • precision-guided munition 精密制导武器
  • jpeg / jpg
  • 位图文件的扩展名
  • 遗嘱执行人
  • 下面是如何使用 imghdr 来检测文件的图像类型:

    >>> import imghdr
    >>> path = 'python.jpg'
    >>> imghdr.what(path)
    'jpeg'
    >>> path = 'python.png'
    >>> imghdr.what(path)
    'png'
    

    你所需要做的就是传递一个路径到 imghdr.what(path) 它会告诉你它认为图像类型是什么。

    另一种方法是使用枕头包,如果你还没有 pip,你可以安装它。

    以下是枕头的使用方法:

    >>> from PIL import Image
    >>> img = Image.open('/home/mdriscoll/Pictures/all_python.jpg')
    >>> img.format
    'JPEG'
    

    这个方法几乎和使用 imghdr 一样简单。在这种情况下,您需要创建一个图像对象,然后调用它的格式属性。Pillow 支持的图像类型比 imghdr,但是文档并没有真正说明格式属性是否适用于所有这些图像类型。

    无论如何,我希望这有助于您识别文件的图像类型。

    如何用 Python 连接 Twitter

    原文:https://www.blog.pythonlibrary.org/2014/09/26/how-to-connect-to-twitter-with-python/

    有几个第三方包包装了 Twitter 的 API。我们将关注 tweepy 和 T2 的 twitter。tweepy 文档比 twitter 的更广泛一些,但是我觉得 twitter 包有更多具体的例子。让我们花一些时间来看看如何使用这些软件包!

    要开始使用 Twitter 的 API,您需要创建一个 Twitter 应用程序。为此,你必须去他们的开发者网站创建一个新的应用程序。创建应用程序后,您将需要获得您的 API 密钥(或者生成一些)。您还需要生成您的访问令牌。

    因为 Python 中没有包含这两个包,所以您也需要安装它们。要安装 tweepy,只需执行以下操作:

    pip install tweepy

    要安装 twitter,你可以做同样的事情:

    pip install twitter

    现在你应该准备好出发了!

    发布状态更新

    你应该能够用这些包做的一个基本事情是在你的 Twitter 账户上发布一个更新。让我们看看这两个软件包在这方面是如何工作的。我们从十二层开始。

    import tweepy auth = tweepy.OAuthHandler(key, secret) auth.set_access_token(token, token_secret) client = tweepy.API(auth) client.update_status("#Python Rocks!")

    嗯,这是相当直截了当的。我们必须用我们的密钥创建一个 OAuth 处理程序,然后设置访问令牌。最后,我们创建了一个表示 Twitter API 的对象,并更新了状态。这个方法对我很有效。现在让我们看看我们是否能让 twitter 包工作。

    import twitter auth=twitter.OAuth(token, token_secret, key, secret) client = twitter.Twitter(auth=auth) client.statuses.update(status="#Python Rocks!")

    这段代码也非常简单。事实上,我认为 twitter 包的 OAuth 实现比 tweepy 的更干净。

    注意:我在使用 twitter 包时有时会得到以下错误:错误的认证数据,代码 215 。我不完全确定为什么当你查找这个错误时,它应该是因为你使用 Twitter 的旧 API 而引起的。如果是这样的话,那么它就永远不会起作用。

    接下来,我们将看看如何获得我们的时间线。

    获取时间线

    在这两个包中获得你自己的 Twitter 时间表真的很容易。让我们来看看 tweepy 的实现:

    import tweepy auth = tweepy.OAuthHandler(key, secret) auth.set_access_token(token, token_secret) client = tweepy.API(auth) timeline = client.home_timeline() for item in timeline: text = "%s says '%s'" % (item.user.screen_name, item.text) print text

    所以在这里我们得到认证,然后我们调用 home_timeline() 方法。这将返回一个对象的 iterable,我们可以循环遍历这些对象并从中提取各种数据。在这种情况下,我们只提取屏幕名称和 Tweet 的文本。让我们看看 twitter 包是如何做到这一点的:

    import twitter auth=twitter.OAuth(token, token_secret, key, secret) client = twitter.Twitter(auth=auth) timeline = client.statuses.home_timeline() for item in timeline: text = "%s says '%s'" % (item["user"]["screen_name"], item["text"]) print text

    twitter 包非常相似。主要区别在于它返回一个字典列表。

    如果你想得到别人的时间线。在十二岁时,你会这样做:

    import tweepy auth = tweepy.OAuthHandler(key, secret) auth.set_access_token(token, token_secret) client = tweepy.API(auth) user = client.get_user(screen_name='pydanny') timeline = user.timeline()

    twitter 包有点不同:

    import twitter auth=twitter.OAuth(token, token_secret, key, secret) client = twitter.Twitter(auth=auth) user_timeline = client.statuses.user_timeline(screen_name='pydanny')

    在这种情况下,我认为 twitter 包更干净一些,尽管有人可能会说 tweepy 的实现更直观。

    让你的朋友和追随者

    几乎每个人在 Tritter 上都有朋友(他们追随的人)和追随者。在本节中,我们将了解如何访问这些项目。twitter 包并没有一个很好的例子来寻找你的 Twitter 朋友和追随者,所以在这一节我们将只关注 tweepy。

    import tweepy auth = tweepy.OAuthHandler(key, secret) auth.set_access_token(token, token_secret) client = tweepy.API(auth) friends = client.friends() for friend in friends: print friend.name

    如果您运行上面的代码,您会注意到它打印出来的最大朋友数是 20。如果你想打印出你所有的朋友,那么你需要使用光标。使用光标有两种方式。您可以使用它来返回页面或特定数量的项目。在我的例子中,我关注了 32 个人,所以我选择了 items 的工作方式:

    for friend in tweepy.Cursor(client.friends).items(200): print friend.name

    这段代码将迭代多达 200 项。如果你有很多朋友或者你想迭代别人的朋友,但是不知道他们有多少,那么使用 pages 方法更有意义。让我们来看看这可能是如何工作的:

    for page in tweepy.Cursor(client.friends).pages(): for friend in page: print friend.name

    这很简单。获取您的关注者列表完全相同:

    followers = client.followers() for follower in followers: print follower.name

    这也将只返回 20 个项目。我有很多追随者,所以如果我想获得他们的列表,我必须使用上面提到的光标方法之一。

    这些包提供了比本文所涵盖的更多的功能。我特别推荐看 tweepy,因为使用 Python 的自省工具比 twitter 包更直观、更容易理解。如果你还没有一堆这样的应用程序,你可以很容易地使用 tweepy,并围绕它创建一个用户界面,让你与你的朋友保持同步。另一方面,对于初学者来说,这仍然是一个很好的程序。

  • tweepy - github读取文档
  • 推特上的 PyPI
  • 其他 Python Twitter 客户端
  • 如何用 Python 和熊猫把 CSV 转换成 Excel(视频)

    原文:https://www.blog.pythonlibrary.org/2022/06/30/how-to-convert-csv-to-excel-with-python-and-pandas-video/

    了解如何使用 Python 和 pandas 包,使用 3 行代码将 CSV 文件转换为 Excel 文件!

    还演示了当出现问题时如何修复问题!

    https://www.youtube.com/embed/bXjoQuf9xMY?feature=oembed

    如何用 Python 将十进制数转换成单词

    原文:https://www.blog.pythonlibrary.org/2012/06/02/how-to-convert-decimal-numbers-to-words-with-python/

    将这篇文章命名为“如何将浮点数转换成单词”可能是一个更好的主意,但是因为我谈论的是货币,所以我认为使用十进制更准确。总之,几年前,我写过关于如何将数字转换成 Python。我重提这个话题的主要原因是因为我最终需要再做一次,我发现我自己的例子相当缺乏。它没有展示如何实际使用它将类似“10.12”的东西转换为“十美元十二美分”。因此,我将在本文中向您展示如何做到这一点,然后我们还将看看我的读者给我的一些替代方案。

    首先,我们将获取原始代码,并在最后添加一些测试,以确保它按照我们想要的方式工作。然后我会告诉你一个稍微不同的方法。最后,我们将看看另外两个试图做这类事情的项目。

    '''Convert number to English words $./num2eng.py 1411893848129211 one quadrillion, four hundred and eleven trillion, eight hundred and ninety three billion, eight hundred and forty eight million, one hundred and twenty nine thousand, two hundred and eleven Algorithm from http://mini.net/tcl/591 # modified to exclude the "and" between hundreds and tens - mld __author__ = 'Miki Tebeka ' __version__ = '$Revision: 7281 $' # $Source$ import math # Tokens from 1000 and up _PRONOUNCE = [ 'vigintillion', 'novemdecillion', 'octodecillion', 'septendecillion', 'sexdecillion', 'quindecillion', 'quattuordecillion', 'tredecillion', 'duodecillion', 'undecillion', 'decillion', 'nonillion', 'octillion', 'septillion', 'sextillion', 'quintillion', 'quadrillion', 'trillion', 'billion', 'million', 'thousand', # Tokens up to 90 _SMALL = { '0' : '', '1' : 'one', '2' : 'two', '3' : 'three', '4' : 'four', '5' : 'five', '6' : 'six', '7' : 'seven', '8' : 'eight', '9' : 'nine', '10' : 'ten', '11' : 'eleven', '12' : 'twelve', '13' : 'thirteen', '14' : 'fourteen', '15' : 'fifteen', '16' : 'sixteen', '17' : 'seventeen', '18' : 'eighteen', '19' : 'nineteen', '20' : 'twenty', '30' : 'thirty', '40' : 'forty', '50' : 'fifty', '60' : 'sixty', '70' : 'seventy', '80' : 'eighty', '90' : 'ninety' def get_num(num): '''Get token <= 90, return '' if not matched''' return _SMALL.get(num, '') def triplets(l): '''Split list to triplets. Pad last one with '' if needed''' res = [] for i in range(int(math.ceil(len(l) / 3.0))): sect = l[i * 3 : (i + 1) * 3] if len(sect) < 3: # Pad last section sect += [''] * (3 - len(sect)) res.append(sect) return res def norm_num(num): """Normelize number (remove 0's prefix). Return number and string""" n = int(num) return n, str(n) def small2eng(num): '''English representation of a number <= 999''' n, num = norm_num(num) hundred = '' ten = '' if len(num) == 3: # Got hundreds hundred = get_num(num[0]) + ' hundred' num = num[1:] n, num = norm_num(num) if (n > 20) and (n != (n / 10 * 10)): # Got ones tens = get_num(num[0] + '0') ones = get_num(num[1]) ten = tens + ' ' + ones else: ten = get_num(num) if hundred and ten: return hundred + ' ' + ten #return hundred + ' and ' + ten else: # One of the below is empty return hundred + ten def num2eng(num): '''English representation of a number''' num = str(long(num)) # Convert to string, throw if bad number if (len(num) / 3 >= len(_PRONOUNCE)): # Sanity check raise ValueError('Number too big') if num == '0': # Zero is a special case return 'zero ' # Create reversed list x = list(num) x.reverse() pron = [] # Result accumolator ct = len(_PRONOUNCE) - 1 # Current index for a, b, c in triplets(x): # Work on triplets p = small2eng(c + b + a) if p: pron.append(p + ' ' + _PRONOUNCE[ct]) ct -= 1 # Create result pron.reverse() return ', '.join(pron) if __name__ == '__main__': numbers = [1.37, 0.07, 123456.00, 987654.33] for number in numbers: dollars, cents = [int(num) for num in str(number).split(".")] dollars = num2eng(dollars) if dollars.strip() == "one": dollars = dollars + "dollar and " else: dollars = dollars + "dollars and " cents = num2eng(cents) + "cents" print dollars + cents

    我们只关注测试程序的最后一部分。这里我们有一个列表,列出了我们在程序中运行的各种值,并确保它输出了我们想要的。请注意,我们有不到一美元的金额。这是我见过的一个边缘案例,因为我的雇主想用真实金额测试我们的代码,但不希望转移巨额资金。以下是一种略有不同的数据输出方式:

    temp_amount = 10.34 if '.' in temp_amount: amount = temp_amount.split('.') dollars = amount[0] cents = amount[1] else: dollars = temp_amount cents = '00' amt = num2eng.num2eng(dollars) total = amt + 'and %s/100 Dollars' % cents print total

    在这种情况下,我们不把美分部分写成单词,而只是把数字写在一百以上。是的,我知道这很微妙,但这篇文章对我来说也是一个大脑垃圾场,所以下次我必须这样做时,我会在我的指尖上有所有的信息。

    试用 PyNum2Word

    在我发布了我的原创文章后,有人过来告诉我关于 PyNum2Word 项目的事情,以及我应该如何使用它。PyNum2Word 项目当时还不存在,但我决定这次尝试一下。遗憾的是,这个项目没有我能找到的文档。连一个自述文件都没有!另一方面,它声称可以为美国、德国、英国、欧盟和法国做货币。我以为德国、英国和法国都在欧盟,所以我不知道在他们现在都使用欧元的情况下,使用法郎等货币有什么意义。

    无论如何,在我们的例子中,我们将使用下面的文件, num2word_EN.py ,来自他们的测试包。文件底部实际上有一个测试,与我构建的测试相似。事实上我的测试是基于他们的。让我们试着编辑这个文件,在他们的第二个列表中添加一个小于 1 的数字,比如 0.45 ,看看这是否可行。下面是第二个列表的输出结果(为了简洁,我跳过了第一个列表的输出):

    0.45 is zero point four five cents 0.45 is zero point four five 1 is one cent 1 is one 120 is one dollar and twenty cents 120 is one hundred and twenty 1000 is ten dollars 1000 is one thousand 1120 is eleven dollars and twenty cents 1120 is eleven hundred and twenty 1800 is eighteen dollars 1800 is eighteen hundred 1976 is nineteen dollars and seventy-six cents 1976 is nineteen hundred and seventy-six 2000 is twenty dollars 2000 is two thousand 2010 is twenty dollars and ten cents 2010 is two thousand and ten 2099 is twenty dollars and ninety-nine cents 2099 is two thousand and ninety-nine 2171 is twenty-one dollars and seventy-one cents 2171 is twenty-one hundred and seventy-one

    它起作用了,但不是以我期望的方式。在美国,当我们谈论货币时,我们会称0.45“45 美分”而不是“0.45 美分”。当我研究这个的时候,我确实了解到其他一些国家的人们确实使用后一种术语。我觉得有趣的是,这个模块接受任何高于 100 的东西,并将其分为美元和美分。例如,注意 120 被翻译成“一美元二十美分”而不是“一百二十美元”。还要注意,上面写的是“二十美分”,不是“零点二零美分”。我不知道如何解释这种矛盾。如果你给它传递一个小于 100 的整数,它就能工作。因此,如果您让用户放入一个 float,您会希望像我前面所做的那样分解它:

    if '.' in temp_amount: amount = temp_amount.split('.') dollars = amount[0] cents = amount[1] else: dollars = temp_amount cents = '00'

    然后通过脚本传递每个部分以获得片段,然后将它们放在一起。

    使用数字. py

    我的另一个名叫埃里克·沃尔德的读者联系了我关于他的数字. py 脚本。让我们看看这是怎么回事!

    看一下代码,你会很快发现它不能处理 float,所以我们必须分解我们的 float 并分别传递美元和美分。我用几个不同的数字试了一下,似乎可以正确地转换它们。该脚本甚至在千位标记处添加了逗号。它没有在任何地方添加“和”字,但我现在不关心这个。

    所有这三种方法都需要某种包装器来添加“美元”和“美分”(或数字/100)单词,并将浮点数分成两部分。我认为 Eric 的代码非常简单,也是最好的文档。PyNum2Word 项目的代码也非常简洁,并且运行良好,但是没有文档。我很久以前找到的解决方案也能工作,但是我发现代码非常难看,不太容易阅读。我真的没有推荐,但我想我最喜欢埃里克的。如果你需要做多币种的灵活性,那么 PyNum2Word 项目值得一看。

    如何用 Python 和 Pillow 把图片转换成 pdf(视频)

    原文:https://www.blog.pythonlibrary.org/2022/08/22/how-to-convert-images-to-pdfs-with-python-and-pillow-video/

    在 Mike Driscoll 的最新视频教程中,学习如何使用 Python 编程语言和 Pillow 包将一张或多张照片转换为 PDF!

    https://www.youtube.com/embed/KDs5YMo011I?feature=oembed

    在 Mike 的书中了解更多关于使用 Python 处理 pdf 的信息:

  • ReportLab - 用 Python 处理 PDF
  • 想进一步了解 Python 和 Pillow 的图像处理吗?看看迈克的书:

  • 枕头:用 Python 进行图像处理
  • 如何使用 argparse 创建命令行应用程序

    原文:https://www.blog.pythonlibrary.org/2022/05/19/how-to-create-a-command-line-application-with-argparse/

    当你创建一个应用程序时,你通常会希望能够告诉你的应用程序如何去做一些事情。有两种流行的方法来完成这项任务。您可以让您的应用程序接受命令行参数,也可以创建一个图形用户界面。有些应用程序两者都支持。

    当您需要在服务器上运行代码时,命令行界面非常有用。大多数服务器没有连接监视器,尤其是如果它们是 Linux 服务器。在这些情况下,即使您想运行图形用户界面,也可能无法运行。

    Python 附带了一个名为argparse的内置库,可以用来创建命令行界面。在本文中,您将了解以下内容:

  • Parsing Arguments
  • Creating Helpful Messages
  • Adding Aliases
  • Using Mutually Exclusive Arguments
  • Creating a Simple Search Utility
  • argparse模块的内容远不止本文将介绍的内容。如果你想了解更多,你可以查看一下文档。

    现在是时候开始从命令行解析参数了!

    在学习如何使用argparse之前,最好知道还有另一种方法可以将参数传递给 Python 脚本。您可以向 Python 脚本传递任何参数,并通过使用sys模块来访问这些参数。

    要查看它是如何工作的,创建一个名为sys_args.py的文件,并在其中输入以下代码:

    # sys_args.py
    import sys
    def main():
        print('You passed the following arguments:')
        print(sys.argv)
    if __name__ == '__main__':
        main()
    

    这段代码导入sys并打印出sys.argv中的内容。argv属性包含传递给脚本的所有内容的列表,第一项是脚本本身。

    下面是一个示例,说明了在运行这段代码和几个示例参数时会发生什么:

    $ python3 sys_args.py --s 45
    You passed the following arguments:
    ['sys_args.py', '--s', '45']
    

    使用sys.argv的问题是您无法控制可以传递给应用程序的参数:

  • You can't ignore arguments
  • You can't create default arguments
  • You can't really tell what is a valid argument at all
  • 这就是为什么在使用 Python 的标准库时使用argparse是正确的方法。argparse模块非常强大和有用。让我们考虑命令行应用程序遵循的一个常见过程:

  • pass in a file
  • do something to that file in your program
  • output the result
  • 这是一个如何工作的一般例子。继续创建file_parser.py并添加以下代码:

    # file_parser.py
    import argparse
    def file_parser(input_file, output_file=''):
        print(f'Processing {input_file}')
        print('Finished processing')
        if output_file:
            print(f'Creating {output_file}')
    def main():
        parser = argparse.ArgumentParser('File parser')
        parser.add_argument('--infile', help='Input file')
        parser.add_argument('--out', help='Output file')
        args = parser.parse_args()
        if args.infile:
            file_parser(args.infile, args.out)
    if __name__ == '__main__':
        main()
    

    file_parser()函数是解析的逻辑所在。对于这个例子,它只接受一个文件名并打印出来。output_file参数默认为空字符串。

    尽管如此,这个项目的核心仍在main()中。在这里,您创建了一个argparse.ArgumentParser()的实例,并为您的解析器命名。然后你添加两个参数,--infile--out。要使用解析器,您需要调用parse_args(),它将返回传递给程序的任何有效参数。最后,检查用户是否使用了--infile标志。如果是,那么你运行file_parser()

    以下是您在终端中运行代码的方式:

    $ python file_parser.py --infile something.txt
    Processing something.txt
    Finished processing
    

    在这里,您使用带有文件名的--infile标志运行您的脚本。这将运行main(),而 T1 又调用file_parser()

    下一步是使用您在代码中声明的两个命令行参数来尝试您的应用程序:

    $ python file_parser.py --infile something.txt --out output.txt
    Processing something.txt
    Finished processing
    Creating output.txt
    

    这一次,您会得到一行额外的输出,其中提到了输出文件名。这代表了代码逻辑中的一个分支。当指定输出文件时,可以使用新的代码块或函数让代码经历生成该文件的过程。如果不指定输出文件,那么该代码块将不会运行。

    当你使用argparse创建你的命令行工具时,当你的用户不确定如何正确地与你的程序交互时,你可以很容易地添加信息来帮助他们。

    现在是时候了解如何从您的应用程序中获得帮助了!

    创建有用的信息

    argparse库将使用您在创建每个参数时提供的信息,自动为您的应用程序创建一条有用的消息。下面是您的代码:

    # file_parser.py
    import argparse
    def file_parser(input_file, output_file=''):
        print(f'Processing {input_file}')
        print('Finished processing')
        if output_file:
            print(f'Creating {output_file}')
    def main():
        parser = argparse.ArgumentParser('File parser')
        parser.add_argument('--infile', help='Input file')
        parser.add_argument('--out', help='Output file')
        args = parser.parse_args()
        if args.infile:
            file_parser(args.infile, args.out)
    if __name__ == '__main__':
        main()
    

    现在尝试运行带有-h标志的代码,您应该看到以下内容:

    $ file_parser.py -h
    usage: File parser [-h] [--infile INFILE] [--out OUT]
    optional arguments:
      -h, --help       show this help message and exit
      --infile INFILE  Input file
      --out OUT        Output file
    

    add_argument()help参数用于创建上面的帮助消息。-h--help选项由argparse自动添加。你可以通过给你的帮助加上一个description和一个epilog来增加它的信息量。

    让我们使用它们来改进您的帮助信息。首先将上面的代码复制到一个名为file_parser_with_description.py的新文件中,然后将其修改为如下所示:

    # file_parser_with_description.py
    import argparse
    def file_parser(input_file, output_file=''):
        print(f'Processing {input_file}')
        print('Finished processing')
        if output_file:
            print(f'Creating {output_file}')
    def main():
        parser = argparse.ArgumentParser(
                'File parser',
                description='PyParse - The File Processor',
                epilog='Thank you for choosing PyParse!',
        parser.add_argument('--infile', help='Input file for conversion')
        parser.add_argument('--out', help='Converted output file')
        args = parser.parse_args()
        if args.infile:
            file_parser(args.infile, args.out)
    if __name__ == '__main__':
        main()
    

    在这里,您将descriptionepilog参数传递给ArgumentParser。您还可以将help参数更新为add_argument(),使其更具描述性。

    在进行这些更改后,当您使用-h--help运行这个脚本时,您将看到以下输出:

    $ python file_parser_with_description.py -h
    usage: File parser [-h] [--infile INFILE] [--out OUT]
    PyParse - The File Processor
    optional arguments:
      -h, --help       show this help message and exit
      --infile INFILE  Input file for conversion
      --out OUT        Converted output file
    Thank you for choosing PyParse!
    

    现在,您可以在帮助输出中看到新的描述和附录。这让您的命令行应用程序更加完美。

    您也可以通过add_helpArgumentParser的参数来完全禁用应用程序中的帮助。如果您认为您的帮助文本过于冗长,您可以像这样禁用它:

    # file_parser_no_help.py
    import argparse
    def file_parser(input_file, output_file=''):
        print(f'Processing {input_file}')
        print('Finished processing')
        if output_file:
            print(f'Creating {output_file}')
    def main():
        parser = argparse.ArgumentParser(
                'File parser',
                description='PyParse - The File Processor',
                epilog='Thank you for choosing PyParse!',
                add_help=False,
        parser.add_argument('--infile', help='Input file for conversion')
        parser.add_argument('--out', help='Converted output file')
        args = parser.parse_args()
        if args.infile:
            file_parser(args.infile, args.out)
    if __name__ == '__main__':
        main()
    

    通过将add_help设置为False,可以禁用-h--help标志。

    You can see this demonstrated below:

    $ python file_parser_no_help.py --help
    usage: File parser [--infile INFILE] [--out OUT]
    File parser: error: unrecognized arguments: --help
    

    In the next section, you'll learn about adding aliases to your arguments!

    Adding Aliases

    An alias is a fancy word for using an alternate flag that does the same thing. For example, you learned that you can use both -h and --help to access your program's help message. -h is an alias for --help, and vice-versa

    Look for the changes in the parser.add_argument() methods inside of main():

    # file_parser_aliases.py
    import argparse
    def file_parser(input_file, output_file=''):
        print(f'Processing {input_file}')
        print('Finished processing')
        if output_file:
            print(f'Creating {output_file}')
    def main():
        parser = argparse.ArgumentParser(
                'File parser',
                description='PyParse - The File Processor',
                epilog='Thank you for choosing PyParse!',
                add_help=False,
        parser.add_argument('-i', '--infile', help='Input file for conversion')
        parser.add_argument('-o', '--out', help='Converted output file')
        args = parser.parse_args()
        if args.infile:
            file_parser(args.infile, args.out)
    if __name__ == '__main__':
        main()
    

    Here you change the first add_argument() to accept -i in addition to --infile and you also added -o to the second add_argument(). This allows you to run your code using two new shortcut flags.

    Here's an example:

    $ python3 file_parser_aliases.py -i something.txt -o output.txt
    Processing something.txt
    Finished processing
    Creating output.txt
    

    If you go looking through the argparse documentation, you will find that you can add aliases to subparsers too. A subparser is a way to create sub-commands in your application so that it can do other things. A good example is Docker, a virtualization or container application. It has a series of commands that you can run under docker as well as docker compose and more. Each of these commands has separate sub-commands that you can use.

    Here is a typical docker command to run a container:

    docker exec -it container_name bash
    

    This will launch a container with docker. Whereas if you were to use docker compose, you would use a different set of commands. The exec and compose are examples of subparsers.

    The topic of subparsers are outside the scope of this tutorial. If you are interested in more details dive right into the documentation.

    Using Mutually Exclusive Arguments

    Sometimes you need to have your application accept some arguments but not others. For example, you might want to limit your application so that it can only create or delete files, but not both at once.

    The argparse module provides the add_mutually_exclusive_group() method that does just that!

    Change your two arguments to be mutually exclusive by adding them to a group object like in the example below:

    # file_parser_exclusive.py
    import argparse
    def file_parser(input_file, output_file=''):
        print(f'Processing {input_file}')
        print('Finished processing')
        if output_file:
            print(f'Creating {output_file}')
    def main():
        parser = argparse.ArgumentParser(
                'File parser',
                description='PyParse - The File Processor',
                epilog='Thank you for choosing PyParse!',
                add_help=False,
        group = parser.add_mutually_exclusive_group()
        group.add_argument('-i', '--infile', help='Input file for conversion')
        group.add_argument('-o', '--out', help='Converted output file')
        args = parser.parse_args()
        if args.infile:
            file_parser(args.infile, args.out)
    if __name__ == '__main__':
        main()
    

    First, you created a mutually exclusive group. Then, you added the -i and -o arguments to the group instead of to the parser object. Now these two arguments are mutually exclusive.

    Here is what happens when you try to run your code with both arguments:

    $ python3 file_parser_exclusive.py -i something.txt -o output.txt
    usage: File parser [-i INFILE | -o OUT]
    File parser: error: argument -o/--out: not allowed with argument -i/--infile
    

    Running your code with both arguments causes your parser to show the user an error message that explains what they did wrong.

    After covering all this information related to using argparse, you are ready to apply your new skills to create a simple search tool!

    Creating a Simple Search Utility

    Before starting to create an application, it is always good to figure out what you are trying to accomplish. The application you want to build in this section should be able to search for files of a specific file type. To make it more interesting, you can add an additional argument that allows you to optionally search for specific file sizes as well.

    You can use Python's glob module for searching for file types. You can read all about this module here:

  • https://docs.python.org/3/library/glob.html
  • There is also the fnmatch module, which glob itself uses. You should use glob for now as it is easier to use, but if you're interested in writing something more specialized, then fnmatch may be what you are looking for.

    However, since you want to be able to optionally filter the files returned by the file size, you can use pathlib which includes a glob-like interface. The glob module itself does not provide file size information.

    You can start by creating a file named pysearch.py and entering the following code:

    # pysearch.py
    import argparse
    import pathlib
    def search_folder(path, extension, file_size=None):
        Search folder for files
        folder = pathlib.Path(path)
        files = list(folder.rglob(f'*.{extension}'))
        if not files:
            print(f'No files found with {extension=}')
            return
        if file_size is not None:
            files = [
                    for f in files
                    if f.stat().st_size >= file_size
        print(f'{len(files)} *.{extension} files found:')
        for file_path in files:
            print(file_path)
    

    You start the code snippet above by importing argparse and pathlib. Next you create the search_folder() function which takes in three arguments:

  • path - The folder to search within
  • extension - The file extension to look for
  • file_size - What file size to filter on in bytes
  • You turn the path into a pathlib.Path object and then use its rglob() method to search in the folder for the extension that the user passed in. If no files are found, you print out a meaningful message to the user and exit.

    If any files are found, you check to see whether file_size has been set. If it was set, you use a list comprehension to filter out the files that are smaller than the specified file_size.

    Next, you print out the number of files that were found and finally loop over these files to print out their names.

    To make this all work correctly, you need to create a command-line interface. You can do that by adding a main() function that contains your argparse code like this:

    def main():
        parser = argparse.ArgumentParser(
                'PySearch',
                description='PySearch - The Python Powered File Searcher',
        parser.add_argument('-p', '--path',
                            help='The path to search for files',
                            required=True,
                            dest='path')
        parser.add_argument('-e', '--ext',
                            help='The extension to search for',
                            required=True,
                            dest='extension')
        parser.add_argument('-s', '--size',
                            help='The file size to filter on in bytes',
                            type=int,
                            dest='size',
                            default=None)
        args = parser.parse_args()
        search_folder(args.path, args.extension, args.size)
    if __name__ == '__main__':
        main()
    

    This ArgumentParser() has three arguments added to it that correspond to the arguments that you pass to search_folder(). You make the --path and --ext arguments required while leaving the --size argument optional. Note that the --size argument is set to type=int, which means that you cannot pass it a string.

    There is a new argument to the add_argument() function. It is the dest argument which you use to tell your argument parser where to save the arguments that are passed to them.

    Here is an example run of the script:

    $ python3 pysearch.py -p /Users/michael/Dropbox/python101code/chapter32_argparse -e py -s 650
    6 *.py files found:
    /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_aliases2.py
    /Users/michael/Dropbox/python101code/chapter32_argparse/pysearch.py
    /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_aliases.py
    /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_with_description.py
    /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_exclusive.py
    /Users/michael/Dropbox/python101code/chapter32_argparse/file_parser_no_help.py
    

    That worked quite well! Now try running it with -s and a string:

    $ python3 pysearch.py -p /Users/michael/Dropbox/python101code/chapter32_argparse -e py -s python
    usage: PySearch [-h] -p PATH -e EXTENSION [-s SIZE]
    PySearch: error: argument -s/--size: invalid int value: 'python'
    

    This time, you received an error because -s and --size only accept integers. Go try this code on your own machine and see if it works the way you want when you use -s with an integer.

    Here are some ideas you can use to improve your version of the code:

  • Handle the extensions better. Right now it will accept *.py which won't work the way you might expect
  • Update the code so you can search for multiple extensions at once
  • Update the code to filter on a range of file sizes (Ex. 1 MB - 5MB)
  • There are lots of other features and enhancements you can add to this code, such as adding error handling or unittests.

    Wrapping Up

    The argparse module is full featured and can be used to create great, flexible command-line applications. In this chapter, you learned about the following:

  • Parsing Arguments
  • Creating Helpful Messages
  • Adding Aliases
  • Using Mutually Exclusive Arguments
  • Creating a Simple Search Utility
  • You can do a lot more with the argparse module than what was covered in this chapter. Be sure to check out the documentation for full details. Now go ahead and give it a try yourself. You will find that once you get the hang of using argparse, you can create some really neat applications!

    如何在 Python 中创建图像的差异

    原文:https://www.blog.pythonlibrary.org/2016/10/11/how-to-create-a-diff-of-an-image-in-python/

    在过去的几年里,我一直在为我的雇主编写自动化测试。我做的许多测试类型之一是比较应用程序如何绘制。它每次都是以同样的方式画的吗?如果不是,那么我们就有一个严重的问题。检查它每次都绘制相同图形的一个简单方法是截取一个屏幕截图,然后在应用程序更新时将其与同一图形的未来版本进行比较。

    枕头库为这种叫做图像印章的东西提供了一个方便的工具。如果你还没有枕头,你应该现在就去安装它,这样你就可以跟随这个简短的教程。

    比较两幅图像

    我们需要做的第一件事是找到两幅略有不同的图像。你可以使用相机的连拍模式,拍摄一组动物移动的照片,最好是使用三脚架。或者你可以在一张现有的照片上添加某种覆盖,比如文字。我打算采用后一种方法。这是我在俄勒冈州摩特诺玛瀑布的原始照片:

    这是修改后的版本,我添加了一些文字来标识照片的位置:

    现在让我们使用 ImageChops 来找出我们的不同之处!

    import Image import ImageChops def compare_images(path_one, path_two, diff_save_location): Compares to images and saves a diff image, if there is a difference @param: path_one: The path to the first image @param: path_two: The path to the second image image_one = Image.open(path_one) image_two = Image.open(path_two) diff = ImageChops.difference(image_one, image_two) if diff.getbbox(): diff.save(diff_save_location) if __name__ == '__main__': compare_images('/path/to/multnomah_falls.jpg', '/path/to/multnomah_falls_text.jpg', '/path/to/diff.jpg')

    这里我们有一个简单的函数,我们可以用它来寻找图像中的差异。你需要做的就是通过三条路径!前两条路径用于我们想要比较的图像。最后一个路径是保存 diff 图像的位置,如果我们找到一个 diff。对于这个例子,我们肯定应该找到一个差异,我们做到了。下面是我运行这段代码时得到的结果:

    枕头包有许多惊人的功能来处理图像。我喜欢摄影,所以能够拍摄照片,然后使用我最喜欢的编程语言来帮助我处理结果,这很有趣。你也应该尝试一下,看看枕头文档,看看这个聪明的包还能做什么!

  • 蟒蛇枕官网
  • 枕头文档
  • 介绍 Python 图像库/ Pillow
  • 如何用 Python 创建“不可变”的类

    原文:https://www.blog.pythonlibrary.org/2014/01/17/how-to-create-immutable-classes-in-python/

    我最近读了很多关于 Python 的神奇方法,最近还读了一些创建不可变类的方法。不可变类不允许程序员向实例添加属性(即猴子补丁)。如果我们实际上先看一个正常的类,会更容易理解一点。我们将从一个猴子补丁的例子开始,然后看一种使类“不可变”的方法。

    猴子修补 Python 类

    首先,我们需要创建一个可以玩的类。这里有一个简单的类,它不做任何事情:

    ######################################################################## class Mutable(object): A mutable class #---------------------------------------------------------------------- def __init__(self): """Constructor"""

    现在让我们创建这个类的一个实例,看看是否可以添加一个属性:

    >>> mut_obj = Mutable() >>> mut_obj.monkey = "tamarin" >>> mut_obj.monkey 'tamarin'

    这个类允许我们在运行时向它添加属性。现在我们知道了如何做一些简单的猴子补丁,让我们尝试阻止这种行为。

    创建不可变的类

    我读到的一个关于不可变类的例子提到,你可以通过用_ _ 插槽 __ 替换一个类的 dict 来创建一个不可变类。让我们看看这是什么样子:

    ######################################################################## class Immutable(object): An immutable class __slots__ = ["one", "two", "three"] #---------------------------------------------------------------------- def __init__(self, one, two, three): """Constructor""" super(Immutable, self).__setattr__("one", one) super(Immutable, self).__setattr__("two", two) super(Immutable, self).__setattr__("three", three) #---------------------------------------------------------------------- def __setattr__(self, name, value): """""" msg = "'%s' has no attribute %s" % (self.__class__, name) raise AttributeError(msg)

    现在我们只需要创建这个类的一个实例,看看我们是否可以用猴子来修补它:

    >>> i = Immutable(1, 2, 3) >>> i.four = 4 Traceback (most recent call last): File "", line 1, in <fragment>AttributeError: 'Immutable' object has no attribute 'four'

    在这种情况下,该类不允许我们对实例进行猴子修补。相反,我们收到一个 AttibuteError。让我们尝试更改其中一个属性:

    >>> i = Immutable(1, 2, 3) >>> i.one = 2 Traceback (most recent call last): File "c:\Users\mdriscoll\Desktop\rep-fonts\immutable\immute_slots.py", line 1, in ######################################################################## File "c:\Users\mdriscoll\Desktop\rep-fonts\immutable\immute_slots.py", line 33, in __setattr__ raise AttributeError(msg) AttributeError: '<class>' has no attribute one

    这是因为我们已经覆盖了 setattr 方法。如果你想的话,你可以重写这个方法,什么都不做。这将阻止追溯的发生,但也防止值被更改。如果您喜欢明确说明正在发生的事情,那么提出一个错误可能是一种方法。

    如果你读了一些关于插槽的书,你会很快发现不鼓励以这种方式使用插槽。为什么?因为槽主要是作为内存优化而创建的(它减少了属性访问时间)。

    您可以通过以下链接了解更多关于插槽的信息:

  • 关于插槽的 Python 文档
  • stack overflow:python _ _ slots _ _
  • 什么是插槽?
  • https://stackoverflow.com/questions/472000/python-slots

    如何用 Python 裁剪照片

    原文:https://www.blog.pythonlibrary.org/2017/10/03/how-to-crop-a-photo-with-python/

    如果你喜欢拍照,你可能会发现自己会时不时地裁剪照片。我会裁剪照片,以消除背景噪音,或者更专注于我试图捕捉的主题。我也喜欢拍摄昆虫或其他小生物的高分辨率照片,然后进行裁剪,让我看起来比实际情况更接近昆虫。

    现在大多数人会使用照片编辑应用程序来裁剪他们的图像,例如 Photoshop Elements。我也使用这些工具,但是你也可以使用 Python 编程语言来为你进行裁剪。一个您可能想要使用 Python 的好例子是,如果您有数千个相同类型的扫描图像,那么只需编写一个脚本来为您进行裁剪就更有意义了。

    Python 中最流行的图像操作包是 Pillow 包,它是“Python 图像库(PIL)的友好分支”。您可以使用 pip 安装枕头:

    pip install Pillow

    现在我们已经安装了枕头,我们只需要一张照片。这是我拍的一只蚱蜢:

    让我们编写一些代码,尝试将图片裁剪到蚱蜢的头部:

    from PIL import Image def crop(image_path, coords, saved_location): @param image_path: The path to the image to edit @param coords: A tuple of x/y coordinates (x1, y1, x2, y2) @param saved_location: Path to save the cropped image image_obj = Image.open(image_path) cropped_image = image_obj.crop(coords) cropped_image.save(saved_location) cropped_image.show() if __name__ == '__main__': image = 'grasshopper.jpg' crop(image, (161, 166, 706, 1050), 'cropped.jpg')

    在这段代码中,我们做的第一件事是从 PIL 导入图像子模块。然后我们创建一个 crop() 函数,它有 3 个参数:

  • image_path -要裁剪的文件的文件路径
  • coords——一个 4 元素元组,包含图像裁剪的开始和结束坐标
  • saved_location -保存裁剪文件的文件路径
  • 在我们打开初始图像后,我们得到一个可以调用 crop() on 的对象。crop 方法获取我们传入的坐标,并适当地裁剪图像,然后返回第二个图像对象。然后我们调用第二个图像对象的 save() 方法,并告诉它将它保存到指定的位置。

    当您运行代码时,它将显示裁剪后的图像并保存它:

    这非常接近我想要的。您可以在上面的代码中对 x/y 坐标进行一点试验,尝试以各种方式裁剪图像,看看效果如何。

    这段代码应该有一个检查,防止用户覆盖原始图像。任何好的照片编辑器都不会覆盖原始照片,因为那真的很烦人,而且通常是件坏事。但是我将把它留给读者去解决。

    无论如何,Pillow 项目对于用 Python 处理图像来说是一个非常强大和有用的包。试一试,看看你能完成什么有趣的事情!

  • 介绍 Python 图像库/ Pillow
  • 如何用 Python 和 functools 做一个简单的缓存(视频)

    原文:https://www.blog.pythonlibrary.org/2022/05/20/how-to-do-a-simple-cache-with-python-and-functools-video/

    了解如何使用 Python 惊人的标准库为函数添加缓存。在本视频教程中,您将学习如何使用 functools.cache 为函数添加缓存

    https://www.youtube.com/embed/CtpSBau84xg?feature=oembed

    如果你想了解更多关于 functools 模块的信息,你可以看看我的另一个视频:

    https://www.youtube.com/embed/gIVRaAb-XzA?feature=oembed

    如何用 Python 下载文件(视频)

    原文:https://www.blog.pythonlibrary.org/2020/06/18/how-to-download-a-file-with-python-video/

    在本视频教程中,您将学习如何使用 Python 的 urllib 从互联网下载文件:

    https://www.youtube.com/embed/dkGRWJD0oQ4?feature=oembed

    如果你喜欢阅读而不是观看,那么你可以看看这个相关的教程:

  • Python 101: 如何下载文件
  • | | 你想了解更多关于 Python 的知识吗?

    Python 101 -第二版

    在 Leanpub 上立即购买 |

    如何将 jupiter 笔记本导出为其他格式

    原文:https://www.blog.pythonlibrary.org/2018/10/09/how-to-export-jupyter-notebooks-into-other-formats/

    使用 Jupyter Notebook 时,您会发现自己需要分发笔记本,而不是笔记本文件。最有可能的原因是,您希望将笔记本的内容共享给非技术用户,这些用户不想安装 Python 或使用笔记本所需的其他依赖项。将笔记本导出为其他格式的最流行的解决方案是内置的 nbconvert 工具。您可以使用 nbconvert 导出到以下格式:

  • HTML ( -到 HTML)
  • 乳胶(至乳胶)
  • PDF ( -至 PDF)
  • 显示 JS ( -到幻灯片)
  • 降价(md)
  • 重新构造的文本(rst)
  • 可执行脚本(- to 脚本)
  • nbconvert 工具使用 Jinja 模板来转换您的笔记本文件()。ipynb )转换为其他静态格式。Jinja 是 Python 的模板引擎。nbconvert 工具依赖于 Pandoc 和 TeX 进行一些转换。您可能需要在您的计算机上单独安装这些软件。这在 ReadTheDocs 上有记录。

    | | 想了解更多关于使用 Jupyter 笔记本的信息吗?然后看看我的书:

    Jupyter 笔记型电脑 101

    在 Leanpub 上立即购买 |

    使用 nbconvert

    我们首先需要的是一台想要转换的笔记本。我用一个 Jupyter 笔记本做了一个关于 Python decorators 的演示。我们将使用那一个。可以在 Github 上获取。如果你想使用其他的东西,请随意下载你最喜欢的笔记本。我还发现了这个有趣的笔记本图库,你也可以用它。

    我们将使用的笔记本名为 Decorators.ipynb 。使用 nbconvert 导出的典型命令如下:

    jupyter nbconvert  --to 
    

    默认的输出格式是 HTML。但是让我们从尝试将 Decorators 笔记本转换成 PDF 开始:

    jupyter nbconvert Decorators.ipynb --to pdf
    

    我不会在每次运行 nbconvert 时都提到这一点,但是当我运行这个命令时,我在终端中得到以下输出:

    [NbConvertApp] Converting notebook Decorators.ipynb to pdf
    [NbConvertApp] Writing 45119 bytes to notebook.tex
    [NbConvertApp] Building PDF
    [NbConvertApp] Running xelatex 3 times: [u'xelatex', u'notebook.tex']
    [NbConvertApp] Running bibtex 1 time: [u'bibtex', u'notebook']
    [NbConvertApp] WARNING | bibtex had problems, most likely because there were no citations
    [NbConvertApp] PDF successfully created
    [NbConvertApp] Writing 62334 bytes to Decorators.pdf
    

    当您将笔记本转换为其他格式时,您会看到类似的内容,尽管输出会明显不同。这是输出的样子:

    如果您将笔记本转换为 reStructuredText 或 latex,那么 nbconvert 将使用封面下的 pandoc 进行转换。这意味着 pandoc 是一个依赖项,在转换成这些格式之前,您可能需要安装它。

    让我们尝试将我们的笔记本电脑转换为 Markdown,看看我们会得到什么:

    jupyter nbconvert Decorators.ipynb --to markdown
    

    当您运行此命令时,您将得到如下所示的输出:

    让我们对笔记本进行一次转换。对于这种转换,我们将把我们的笔记本变成 HTML。HTML 转换实际上有两种模式:

  • -模板完整(默认)
  • -模板基本
  • 完整版将使笔记本的 HTML 呈现看起来非常像普通笔记本在其“交互式视图”中的样子,而基本版使用 HTML 标题,主要针对那些希望将笔记本嵌入网页或博客的人。让我们试一试:

    jupyter nbconvert Decorators.ipynb --to html 
    

    当我运行这个程序时,我得到了一个很好的 HTML 文件。如果在 web 浏览器中打开 HTML,您应该会看到以下内容:

    转换多个笔记本

    nbconvert 实用程序还支持一次转换多个笔记本。如果您有一组名称相似的笔记本,您可以使用以下命令:

    jupyter nbconvert notebook*.ipynb --to FORMAT 
    

    这将把文件夹中的所有笔记本转换为您指定的格式,只要笔记本以“Notebook”开头。您也可以只向 nbconvert 提供一个以空格分隔的笔记本列表:

    jupyter nbconvert Decorators.ipynb my_other_notebook.ipynb --to FORMAT
    

    如果您有许多笔记本,另一种批量转换它们的方法是创建一个 Python 脚本作为配置文件。根据此文档,您可以创建一个包含以下内容的 Python 脚本:

    c = get_config()
    c.NbConvertApp.notebooks = ["notebook1.ipynb", "notebook2.ipynb"]
    

    如果保存该文件,则可以使用以下命令运行它:

    jupyter nbconvert --config mycfg.py
    

    这将把列出的笔记本转换成您选择的格式。

    执行笔记本

    正如您所料,大多数情况下,Jupyter 笔记本是在输出单元格被清除的情况下保存的。这意味着,当您运行转换时,您不会自动在导出中获得输出。要做到这一点,您必须使用 - execute 标志。这里有一个例子:

    jupyter nbconvert --execute my_notebook.ipynb --to pdf
    

    请注意,笔记本中的代码不能有任何错误,否则转换将会失败。这就是为什么我在这个例子中没有使用 Decorators 笔记本的原因,因为我有一些故意创建的单元格,但它们不能用于演示目的。

    使用 Python 执行笔记本

    您还可以创建一个 Python 脚本,用于以编程方式执行笔记本。让我们写一些代码来运行我的 Decorators 笔记本中的所有单元,包括抛出异常的单元。让我们创建一个空的 Python 脚本,并将其命名为 notebook_runner.py 。在编辑器中输入以下代码:

    # notebook_runner.py
    import nbformat
    import os
    from nbconvert.preprocessors import ExecutePreprocessor
    def run_notebook(notebook_path):
        nb_name, _ = os.path.splitext(os.path.basename(notebook_path))
        dirname = os.path.dirname(notebook_path)
        with open(notebook_path) as f:
            nb = nbformat.read(f, as_version=4)
        proc = ExecutePreprocessor(timeout=600, kernel_name='python3')
        proc.allow_errors = True
        proc.preprocess(nb, {'metadata': {'path': '/'}})
        output_path = os.path.join(dirname, '{}_all_output.ipynb'.format(nb_name))
        with open(output_path, mode='wt') as f:
            nbformat.write(nb, f)
    if __name__ == '__main__':
        run_notebook('Decorators.ipynb')
    

    感兴趣的第一项位于代码的顶部。这里我们从 nbconvert.preprocessors 导入 nbformat 和一个预处理器,称为execute preprocessors。接下来,我们创建一个名为 run_notebook 的函数,它接受一个指向我们想要运行的笔记本的路径。在这个函数中,我们从传入的路径中提取文件名和目录名。

    然后我们使用 nbformat.read 读取笔记本文件。您会注意到,您可以告诉 nbformat 将文件读取为哪个版本。请务必将此设置为与您正在使用的 Jupyter 笔记本的版本相匹配。下一步是实例化 ExecutePreprocessor 类。这里我们给它一个超时和内核名。如果您使用的是 Python 之外的东西,那么这里就是您想要指定该信息的地方。

    因为我们想忽略错误,我们将 allow_errors 属性设置为 True 。默认为。如果我们没有这样做,我们将需要在一个 try/except 块中包装下一步。无论如何,我们告诉 Python 通过预处理方法调用进行预处理。您会注意到,我们需要传入我们读取的笔记本数据,并通过元数据字典告诉它笔记本的位置。如果您的路径不同于本例中使用的路径,请务必更新此信息。

    最后,我们创建输出路径,并将笔记本写到一个新位置。如果您打开它,您应该看到所有实际产生输出的代码单元格的输出。

    nbconvert 实用程序有许多配置选项,您可以使用它们来自定义其工作方式。要了解完整的细节,我推荐阅读这里的文档。

    在本文中,我们学习了如何将 Jupyter 笔记本导出/转换为其他格式,如 HTML、Markdown 和 PDF。我们还了解到,我们可以用几种不同的方式一次转换多台笔记本电脑。最后,我们学习了在导出笔记本之前执行它的不同方法。

  • Jupyter 笔记本扩展基础知识
  • 使用 Jupyter 笔记本创建演示文稿
  • 如何用 Python 从 Jenkins 提取构建信息

    原文:https://www.blog.pythonlibrary.org/2019/05/14/how-to-extract-build-info-from-jenkins-with-python/

    我工作的一部分是使用持续集成软件。我在我的角色中同时使用 Hudson 和 Jenkins,偶尔需要以编程方式与他们进行交互。有两个 Python 包可用于此任务:

  • Python Jenkins
  • Python Jenkins 包可以与 Hudson 和 Jenkins 一起工作,而 JenkinsAPI 只能与 Jenkins 一起工作。因为这个原因,我通常使用 Python Jenkins,尽管我最近开始寻找哪一个更适合工件,并且我发现 JenkinsAPI 实际上更适合这种事情。所以你需要根据你需要做什么来评估这两个包。

    安装 Python Jenkins

    为了遵循本文中的代码示例,您需要安装 Python Jenkins。您可以使用画中画来做到这一点:

    pip install python-jenkins

    现在已经安装好了,让我们试一试 Python Jenkins 吧!

    从詹金斯那里得到所有的工作

    一个常见的任务是需要获得构建系统中配置的所有作业的列表。

    要开始,您需要登录到您的 Jenkins 服务器:

    import jenkins server = jenkins.Jenkins('http://server:port/', username='user', password='secret')

    现在您有了一个 Jenkins 对象,您可以使用它对您的 Jenkins CI 服务器执行 REST 请求。返回的结果通常是 Python 字典或字典的字典。

    以下是获取 CI 系统上配置的所有作业的示例:

    import jenkins server = jenkins.Jenkins('http://server:port/', username='user', password='secret') # Get all builds jobs = server.get_all_jobs(folder_depth=None) for job in jobs: print(job['fullname'])

    这将遍历 Jenkins 中配置的所有作业,并打印出它们的作业名。

    获取工作信息

    现在您已经知道了 Jenkins box 上的作业名称,您可以获得关于每个作业的更详细的信息。

    方法如下:

    import jenkins server = jenkins.Jenkins('http://server:port/', username='user', password='secret') # Get information on specific build job # This returns all the builds that are currently shown in # hudson for this job info = server.get_job_info('job-name') # Passed print(info['lastCompletedBuild']) # Unstable print(info['lastUnstableBuild']) # Failed print(info['lastFailedBuild'])

    get_job_info() will give you a lot of information about the job, including all the currently saved builds. It is nice to be able to extract which builds have passed, failed or are unstable.

    获取构建信息

    如果您想知道一个作业运行需要多长时间,那么您需要深入到构建级别。

    让我们来看看如何实现:

    import jenkins server = jenkins.Jenkins('http://server:port/', username='user', password='secret') info = server.get_job_info('job-name') # Loop over builds builds = info['builds'] for build in builds: for build in builds: print(server.get_build_info('job-name', build['number']))

    要获取构建元数据,您需要调用get_build_info(). This method takes in the job name and the build number and returns the metadata as a dictionary.

    使用 Python Jenkins 包可以做更多的事情。例如,您可以使用它来启动一个构建作业、创建一个新作业或删除一个旧作业以及许多其他事情。不幸的是,文档是非常粗略的,所以您必须做一些试验来让它按照您想要的方式工作。

  • Python Jenkins 文档
  • JenkinsAPI 文档
  • 如何用 Python 找到并列出所有正在运行的进程

    原文:https://www.blog.pythonlibrary.org/2010/10/03/how-to-find-and-list-all-running-processes-with-python/

    前几天,我的任务是找到一种方法来获取 Windows XP 虚拟机上所有正在运行的进程的列表。我还应该包括每个进程使用了多少 CPU 和内存的信息。幸运的是,这不必是一个远程脚本,而是一个可以在客户机上运行的脚本。在到处搜索了一番后,我终于找到了解决办法。在这篇文章中,我们将看看一些拒绝以及最终的解决方案,这恰好是跨平台的工作。

    我发现的第一批脚本之一是 2006 年 3 月的这个脚本:

    # http://mail.python.org/pipermail/python-win32/2006-March/004340.html import win32com.client wmi=win32com.client.GetObject('winmgmts:') for p in wmi.InstancesOf('win32_process'): print p.Name, p.Properties_('ProcessId'), \ int(p.Properties_('UserModeTime').Value)+int(p.Properties_('KernelModeTime').Value) children=wmi.ExecQuery('Select * from win32_process where ParentProcessId=%s' %p.Properties_('ProcessId')) for child in children: print '\t',child.Name,child.Properties_('ProcessId'), \ int(child.Properties_('UserModeTime').Value)+int(child.Properties_('KernelModeTime').Value)

    这个脚本需要 PyWin32 包才能工作。然而,虽然这是一个方便的小脚本,但除了 ProcessId 之外,它没有显示我想要的任何内容。我并不真正关心用户或内核模式时间(即用户或内核的总 CPU 时间)。此外,我真的不喜欢使用 COM 的黑魔法,所以我最终拒绝了这个。

    接下来是一个活动状态配方。看起来很有希望:

    # http://code.activestate.com/recipes/303339-getting-process-information-on-windows/ import win32pdh, string, win32api def procids(): #each instance is a process, you can have multiple processes w/same name junk, instances = win32pdh.EnumObjectItems(None,None,'process', win32pdh.PERF_DETAIL_WIZARD) proc_ids=[] proc_dict={} for instance in instances: if instance in proc_dict: proc_dict[instance] = proc_dict[instance] + 1 else: proc_dict[instance]=0 for instance, max_instances in proc_dict.items(): for inum in xrange(max_instances+1): hq = win32pdh.OpenQuery() # initializes the query handle path = win32pdh.MakeCounterPath( (None,'process',instance, None, inum,'ID Process') ) counter_handle=win32pdh.AddCounter(hq, path) win32pdh.CollectQueryData(hq) #collects data for the counter type, val = win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG) proc_ids.append((instance,str(val))) win32pdh.CloseQuery(hq) proc_ids.sort() return proc_ids print procids()

    唉,虽然这也从我的 Windows 系统中获得了一个进程列表(以及 PID),但它没有给我任何关于 CPU 和内存利用率的信息。我认为如果我使用不同的计数器名称,这个方法可能会有效。我猜如果你愿意,你可以通过 MSDN 找到这些信息。我不想搞砸,所以我继续挖。

    这个配方让我想到了下面这个基于 ctypes 的配方:

    # http://code.activestate.com/recipes/305279/ Enumerates active processes as seen under windows Task Manager on Win NT/2k/XP using PSAPI.dll (new api for processes) and using ctypes.Use it as you please. Based on information from http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q175030&ID=KB;EN-US;Q175030 By Eric Koome email [email protected] license GPL from ctypes import * #PSAPI.DLL psapi = windll.psapi #Kernel32.DLL kernel = windll.kernel32 def EnumProcesses(): arr = c_ulong * 256 lpidProcess= arr() cb = sizeof(lpidProcess) cbNeeded = c_ulong() hModule = c_ulong() count = c_ulong() modname = c_buffer(30) PROCESS_QUERY_INFORMATION = 0x0400 PROCESS_VM_READ = 0x0010 #Call Enumprocesses to get hold of process id's psapi.EnumProcesses(byref(lpidProcess), byref(cbNeeded)) #Number of processes returned nReturned = cbNeeded.value/sizeof(c_ulong()) pidProcess = [i for i in lpidProcess][:nReturned] for pid in pidProcess: #Get handle to the process based on PID hProcess = kernel.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid) if hProcess: psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count)) psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname)) print "".join([ i for i in modname if i != '\x00']) #-- Clean up for i in range(modname._length_): modname[i]='\x00' kernel.CloseHandle(hProcess) if __name__ == '__main__': EnumProcesses()

    这看起来很聪明,但是我很不擅长解析 ctypes。这是我想学的东西,但是我有一个截止日期,该死的!另外,这个程序只显示了正在运行的进程列表,但没有关于它们的信息。幸运的是,作者附上了参考文献,但我决定继续寻找。

    接下来,我发现了一个关于使用蒂姆·戈登的便捷的 WMI 模块来做这类事情的帖子(下面是从该帖子直接复制的):

    # http://mail.python.org/pipermail/python-win32/2003-December/001482.html >>> processes = WMI.InstancesOf('Win32_Process') >>> len(processes) >>> [process.Properties_('Name').Value for process in processes] # get the process names [u'System Idle Process', u'System', u'SMSS.EXE', u'CSRSS.EXE', u'WINLOGON.EXE', u'SERVICES.EXE', u'LSASS.EXE', u'SVCHOST.EXE', u'SVCHOST.EXE', u'SVCHOST.EXE', u'SVCHOST.EXE', u'SPOOLSV.EXE', u'ati2evxx.exe', u'BAsfIpM.exe', u'defwatch.exe', u'inetinfo.exe', u'mdm.exe', u'rtvscan.exe', u'SCARDSVR.EXE', u'WLTRYSVC.EXE', u'BCMWLTRY.EXE', u'EXPLORER.EXE', u'Apoint.exe', u'carpserv.exe', u'atiptaxx.exe', u'quickset.exe', u'DSentry.exe', u'Directcd.exe', u'vptray.exe', u'ApntEx.exe', u'FaxCtrl.exe', u'digstream.exe', u'CTFMON.EXE', u'wuauclt.exe', u'IEXPLORE.EXE', u'Pythonwin.exe', u'MMC.EXE', u'OUTLOOK.EXE', u'LineMgr.exe', u'SAPISVR.EXE', u'WMIPRVSE.EXE'] Here is how to get a single process and get its PID. >>> p = WMI.ExecQuery('select * from Win32_Process where Name="Pythonwin.exe"') >>> [prop.Name for prop in p[0].Properties_] # let's look at all the process property names [u'Caption', u'CommandLine', u'CreationClassName', u'CreationDate', u'CSCreationClassName', u'CSName', u'Description', u'ExecutablePath', u'ExecutionState', u'Handle', u'HandleCount', u'InstallDate', u'KernelModeTime', u'MaximumWorkingSetSize', u'MinimumWorkingSetSize', u'Name', u'OSCreationClassName', u'OSName', u'OtherOperationCount', u'OtherTransferCount', u'PageFaults', u'PageFileUsage', u'ParentProcessId', u'PeakPageFileUsage', u'PeakVirtualSize', u'PeakWorkingSetSize', u'Priority', u'PrivatePageCount', u'ProcessId', u'QuotaNonPagedPoolUsage', u'QuotaPagedPoolUsage', u'QuotaPeakNonPagedPoolUsage', u'QuotaPeakPagedPoolUsage', u'ReadOperationCount', u'ReadTransferCount', u'SessionId', u'Status', u'TerminationDate', u'ThreadCount', u'UserModeTime', u'VirtualSize', u'WindowsVersion', u'WorkingSetSize', u'WriteOperationCount', u'WriteTransferCount'] >>> p[0].Properties_('ProcessId').Value # get our ProcessId

    这是一些很酷的东西,我在其他代码中使用了 Golden 的模块。然而,我仍然不确定使用哪个柜台来获取我的信息。我以为这些东西大部分都是为我编码的。好吧,结果是有一个软件包完全满足了我的需求,它可以在所有三个主要平台上运行!太神奇了!

    跨平台解决方案!

    这个包的名字是 psutil ,这是我决定使用的。这是我最后得到的结果:

    import os import psutil import time logPath = r'some\path\proclogs' if not os.path.exists(logPath): os.mkdir(logPath) separator = "-" * 80 format = "%7s %7s %12s %12s %30s, %s" format2 = "%7.4f %7.2f %12s %12s %30s, %s" while 1: procs = psutil.get_process_list() procs = sorted(procs, key=lambda proc: proc.name) logPath = r'some\path\proclogs\procLog%i.log' % int(time.time()) f = open(logPath, 'w') f.write(separator + "\n") f.write(time.ctime() + "\n") f.write(format % ("%CPU", "%MEM", "VMS", "RSS", "NAME", "PATH")) f.write("\n") for proc in procs: cpu_percent = proc.get_cpu_percent() mem_percent = proc.get_memory_percent() rss, vms = proc.get_memory_info() rss = str(rss) vms = str(vms) name = proc.name path = proc.path f.write(format2 % (cpu_percent, mem_percent, vms, rss, name, path)) f.write("\n\n") f.close() print "Finished log update!" time.sleep(300) print "writing new log data!"

    是的,这是一个无限循环,是的,这通常是一件非常糟糕的事情(除了在 GUI 编程中)。然而,出于我的目的,我需要一种方法来每隔 5 分钟左右检查用户的进程,看看是什么导致机器行为如此怪异。因此,脚本需要永远运行,并将结果记录到唯一命名的文件中。这就是这个脚本所做的一切,还有一点格式化的魔力。你觉得合适就随意用或不用。

    我希望这些资料对你有所帮助。希望它能让你省去我所有的挖掘工作!

    注意:虽然最后一个脚本似乎在 Windows XP 上工作得很好,但在 Windows 7 32 和 64 位上,您将得到一个“拒绝访问”的回溯,我怀疑这是由 Windows 7 增强的安全性引起的,但我会尝试找到一个解决方法。

    更新(10/09/2010)-psutil 的人不知道为什么它不能工作,但他们的一个开发者已经确认了这个问题。你可以关注他们的谷歌群列表

    如何在 Python 中获得类属性列表

    原文:https://www.blog.pythonlibrary.org/2013/01/11/how-to-get-a-list-of-class-attributes/

    前几天,我试图弄清楚是否有一种简单的方法来获取类的已定义属性(又名“实例变量”)。原因是我们使用我们创建的属性来匹配我们解析的文件中的字段。所以基本上我们一行一行地读取一个文件,每行可以分成 150 多个片段,这些片段需要映射到我们在类中创建的字段。问题是,我们最近向类中添加了更多的字段,并且在代码中有一个检查,该检查是用文件中应该有的字段的数量硬编码的。因此,当我添加更多的字段时,它打破了检查。我希望这些都有意义。现在你知道背景了,我们可以继续了。我发现了三种不同的方法来实现这一点,所以我们将从最复杂的到最简单的。

    正如大多数 Python 程序员应该知道的,Python 提供了一个方便的小内置程序,叫做 dir 。我可以在一个类实例上使用它来获得该类的所有属性和方法的列表,以及一些继承的神奇方法,如' delattr '、' dict '、' doc '、' format '等。您可以通过执行以下操作自己尝试一下:

    x = dir(myClassInstance)

    然而,我不想要魔法方法,我也不想要方法。我只想要属性。为了让一切都清晰明了,让我们写一些代码吧!

    ######################################################################## class Test: """""" #---------------------------------------------------------------------- def __init__(self): self.varOne = "" self.varTwo = "" self.varThree = "" #---------------------------------------------------------------------- def methodOne(self): """""" print "You just called methodOne!" #---------------------------------------------------------------------- if __name__ == "__main__": t = Test()

    我们想要得到的是一个只包含 self.varOne、self.varTwo 和 self.varThree 的列表。

    import inspect variables = [i for i in dir(t) if not inspect.ismethod(i)]

    看起来不太复杂,是吗?但这需要进口,我不想这么做。另一方面,如果您需要进行自省,inspect 模块是一个不错的选择。它非常强大,可以告诉你很多关于你的班级或者你没有写过的班级的精彩内容。无论如何,我发现的下一个最简单的方法是使用 Python 的可调用内置:

    variables = [i for i in dir(t) if not callable(i)]

    你可以在 Python 文档中阅读更多关于 callable 的内容。基本上 callable 所做的就是根据你传递给它的对象是否可调用来返回一个 True 或 False。方法是可调用的,变量不是。因此,我们循环遍历类字典中的每一项,只有当它们是可调用的(即不是方法)时,才把它们添加到列表中。相当光滑,它不需要任何进口!但是有一个更简单的方法!

    我发现的最简单的方法是使用魔法方法, dict 。除非您覆盖它,否则它内置于您创建的每个类中。因为我们正在处理一个 Python 字典,我们可以直接调用它的方法!

    variables = t.__dict__.keys()

    现在真正的问题是,你应该使用一种神奇的方法来做到这一点吗?大多数 Python 程序员可能会反对它。它们很神奇,所以除非你在做元编程,否则不应该使用它们。我个人认为对于这个用例来说完全可以接受。让我知道我错过的或者你认为更好的其他方法。

  • StackOverflow: 列出对象的属性
  • StackOverflow: Python : 断言变量是实例方法?
  • 如何用 Python 合并字典(视频)

    原文:https://www.blog.pythonlibrary.org/2022/08/10/how-to-merge-dictionaries-with-python-video/

    学习用 Mike Driscoll 合并 Python 字典的三种不同方法

    您将学习三种不同的合并字典的方法:

  • 使用字典的 update() 方法
  • 使用 Union 运算符
  • https://www.youtube.com/embed/sak3PhNekaw?feature=oembed

    如何用 Python 调整照片大小

    原文:https://www.blog.pythonlibrary.org/2017/10/12/how-to-resize-a-photo-with-python/

    有时你会发现自己想要调整照片的大小。我通常想这样做的照片,我想通过电子邮件或张贴在网站上,因为我的一些图像可以相当大。正常人用的是图像编辑器。我通常也这样做,但是为了好玩,我想我会研究如何用 Python 编程语言来做这件事。

    最快的方法是使用 pip 可以安装的枕头包。一旦你有了它,打开你最喜欢的代码编辑器,尝试下面的代码:

    from PIL import Image def resize_image(input_image_path, output_image_path, size): original_image = Image.open(input_image_path) width, height = original_image.size print('The original image size is {wide} wide x {height} ' 'high'.format(wide=width, height=height)) resized_image = original_image.resize(size) width, height = resized_image.size print('The resized image size is {wide} wide x {height} ' 'high'.format(wide=width, height=height)) resized_image.show() resized_image.save(output_image_path) if __name__ == '__main__': resize_image(input_image_path='caterpillar.jpg', output_image_path='caterpillar_small.jpg', size=(800, 400))

    这里我们从枕头包中导入图像类。接下来,我们有一个带 3 个参数的函数:我们要打开的文件的位置,我们要保存调整后的图像的位置,以及一个表示图像新大小的元组,其中元组分别是宽度和高度。接下来,我们打开我们的图像并打印出它的大小。然后我们用传入的 size 元组调用图像对象的 resize() 方法。最后,我们获取新的尺寸,将其打印出来,然后在保存调整后的照片之前显示图像。现在看起来是这样的:

    如您所见,resize()方法不做任何缩放。接下来我们将看看如何去做!

    大多数时候,除非你想写一个缩放方法,否则你不会想像我们在前面的例子中那样调整你的图像的大小。前一种方法的问题是,当调整大小时,它不能保持照片的纵横比。所以不用调整大小,你可以使用 thumbnail() 方法。让我们来看看:

    from PIL import Image def scale_image(input_image_path, output_image_path, width=None, height=None original_image = Image.open(input_image_path) w, h = original_image.size print('The original image size is {wide} wide x {height} ' 'high'.format(wide=w, height=h)) if width and height: max_size = (width, height) elif width: max_size = (width, h) elif height: max_size = (w, height) else: # No width or height specified raise RuntimeError('Width or height required!') original_image.thumbnail(max_size, Image.ANTIALIAS) original_image.save(output_image_path) scaled_image = Image.open(output_image_path) width, height = scaled_image.size print('The scaled image size is {wide} wide x {height} ' 'high'.format(wide=width, height=height)) if __name__ == '__main__': scale_image(input_image_path='caterpillar.jpg', output_image_path='caterpillar_scaled.jpg', width=800)

    这里我们允许程序员传入输入和输出路径以及我们的最大宽度和高度。然后我们使用一个条件来决定我们的最大尺寸应该是多少,然后我们在打开的图像对象上调用 thumbnail() 方法。我们也传入了的图像。抗锯齿标志,该标志将应用高质量下采样滤波器,从而产生更好的图像。最后,我们打开新保存的缩放图像,并打印出它的大小,以便与原始大小进行比较。如果你打开缩放后的图像,你会看到照片的纵横比保持不变。

    玩枕头包很有趣!在本文中,您了解了如何调整图像的大小,以及如何在保持照片纵横比的同时缩放照片。现在,您可以使用这些知识来创建一个函数,该函数可以迭代一个文件夹并创建该文件夹中所有照片的缩略图,或者您可以创建一个简单的照片查看应用程序,其中这种功能可能很方便。

  • stack overflow:Python/Pillow:如何缩放图像
  • 用 Python 将一张照片转换成黑白
  • 如何用 Python 旋转/镜像照片
  • 如何用 Python 裁剪照片
  • 如何使用 Python 和 Pillow 旋转和镜像图像(视频)

    原文:https://www.blog.pythonlibrary.org/2022/08/18/how-to-rotate-and-mirror-images-with-python-and-pillow-video/

    在本视频教程中,您将学习如何使用 Python 和 Pillow 包旋转和镜像图像。这也称为移调图像。

    https://www.youtube.com/embed/MwfBdEz1W8I?feature=oembed

    想了解有关使用 Python 处理图像的更多信息吗?

    看看我的书:枕头:用 Python 进行图像处理

  • Leanpub -电子书(epub、mobi 和 PDF)
  • Gumroad -电子书(epub、mobi 和 PDF)
  • 亚马逊 - Kindle 和平装书
  • 如何用 Python 旋转/镜像照片

    原文:https://www.blog.pythonlibrary.org/2017/10/05/how-to-rotate-mirror-photos-with-python/

    在我们上一篇文章中,我们学习了如何用 Pillow 软件包裁剪图像。在这篇文章中,我们将学习如何旋转和镜像我们的图像。

    使用 Python 和 Pillow 旋转图像非常简单。我们来看一些代码:

    from PIL import Image def rotate(image_path, degrees_to_rotate, saved_location): Rotate the given photo the amount of given degreesk, show it and save it @param image_path: The path to the image to edit @param degrees_to_rotate: The number of degrees to rotate the image @param saved_location: Path to save the cropped image image_obj = Image.open(image_path) rotated_image = image_obj.rotate(degrees_to_rotate) rotated_image.save(saved_location) rotated_image.show() if __name__ == '__main__': image = 'mantis.png' rotate(image, 90, 'rotated_mantis.jpg')

    这里我们只是从 PIL 导入图像模块,并创建一个 rotate() 函数。我们的自定义旋转函数采用以下参数:我们将要旋转的图像路径、我们想要旋转的角度以及我们想要保存结果的位置。实际代码非常简单。我们所做的就是打开图像,然后调用图像对象的 rotate() 方法,同时向它传递逆时针旋转的度数。然后我们保存结果并调用 image 对象的 show()方法来查看结果:

    在上面的例子中,我们将螳螂逆时针旋转了 90 度。

    现在让我们试着翻转或镜像我们的螳螂图像。下面是一个从左到右镜像图像的示例:

    from PIL import Image def flip_image(image_path, saved_location): Flip or mirror the image @param image_path: The path to the image to edit @param saved_location: Path to save the cropped image image_obj = Image.open(image_path) rotated_image = image_obj.transpose(Image.FLIP_LEFT_RIGHT) rotated_image.save(saved_location) rotated_image.show() if __name__ == '__main__': image = 'mantis.png' flip_image(image, 'flipped_mantis.jpg')

    这段代码与前面的例子非常相似。这段代码的核心是我们使用图像对象的 transpose() 方法,该方法采用以下常量之一:

  • PIL。图像。向左向右翻转
  • PIL。图像.翻转 _ 顶部 _ 底部
  • PIL。图像。转置
  • 您也可以在这里使用 Pillow 的 ROTATE 常量之一,但是我们只关注 transpose()方法的镜像方面。试着将这些常量中的一个交换到上面的代码中,看看会发生什么。

    现在你知道如何使用枕头包来旋转和翻转/镜像你的图像。Python 让这种事情变得很简单。你应该试一试,一定要查看 Pillow 的文档,看看你还能做些什么!

  • 图像模块上的枕头文档
  • 如何在 Python 中裁剪图像
  • 介绍 Python 图像库/ Pillow
  • 如何在编码时“连续”运行 Python 测试

    原文:https://www.blog.pythonlibrary.org/2017/03/14/how-to-run-python-tests-continuously-while-coding/

    上周,我做了一些测试驱动开发培训,无意中听到有人提到另一种编程语言,它有一个测试运行程序,你可以设置它来监视你的项目目录,并在文件改变时运行你的测试。我认为这是个好主意。我还认为我可以轻松地编写自己的 Python 脚本来做同样的事情。这是一个相当粗略的版本:

    import argparse import os import subprocess import time def get_args(): parser = argparse.ArgumentParser( description="A File Watcher that executes the specified tests" parser.add_argument('--tests', action='store', required=True, help='The path to the test file to run') parser.add_argument('--project', action='store', required=False, help='The folder where the project files are') return parser.parse_args() def watcher(test_path, project_path=None): if not project_path: project_path = os.path.dirname(test_path) f_dict = {} while True: files = os.listdir(project_path) for f in files: full_path = os.path.join(project_path, f) mod_time = os.stat(full_path).st_mtime if full_path not in f_dict: f_dict[full_path] = mod_time elif mod_time != f_dict[full_path]: # Run the tests cmd = ['python', test_path] subprocess.call(cmd) print('-' * 70) f_dict[full_path] = mod_time time.sleep(1) def main(): args = get_args() w = watcher(args.tests, args.project) if __name__ == '__main__': main()

    要运行这个脚本,您需要执行如下操作:

    python watcher.py --test ~/path/to/tests.py --project ~/project/path

    现在让我们花点时间来谈谈这个脚本。第一个函数使用 Python 的 argparse 模块让程序接受最多两个命令行参数:- test 和- project。第一个是 Python 测试脚本的路径,第二个是要测试的代码所在的文件夹。下一个函数, watcher ,将永远循环下去,从传入的文件夹中抓取所有文件,或者使用测试文件所在的文件夹。它将获取每个文件的修改时间,并将其保存到字典中。密钥设置为文件的完整路径,值为修改时间。接下来,我们检查修改时间是否已经更改。如果没有,我们睡一会儿,再检查一遍。如果它改变了,我们就运行测试。

    此时,您应该能够在您最喜欢的 Python 编辑器中编辑您的代码和测试,并在终端中观察您的测试运行。

    使用看门狗

    我四处寻找其他跨平台的监视目录的方法,发现了 看门狗 项目。自 2015 年(撰写本文时)以来,它一直没有更新,但我测试了一下,似乎对我来说效果不错。您可以使用 pip 安装看门狗:

    pip install watchdog

    现在我们已经安装了 watchdog,让我们创建一些代码来执行类似于上一个示例的操作:

    import argparse import os import subprocess import time from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler def get_args(): parser = argparse.ArgumentParser( description="A File Watcher that executes the specified tests" parser.add_argument('--tests', action="store", required=True, help='The path to the test file to run') parser.add_argument('--project', action='store', required=False, help='The folder where the project files are') return parser.parse_args() class FW(FileSystemEventHandler): def __init__(self, test_file_path): self.test_file_path = test_file_path def on_any_event(self, event): if os.path.exists(self.test_file_path): cmd = ['python', self.test_file_path] subprocess.call(cmd) print('-' * 70) if __name__ =='__main__': args = get_args() observer = Observer() path = args.tests watcher = FW(path) if not args.project: project_path = os.path.dirname(args.tests) else: project_path = args.project if os.path.exists(path) and os.path.isfile(path): observer.schedule(watcher, project_path, recursive=True) observer.start() while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join() else: print('There is something wrong with your test path')

    在这段代码中,我们保留了我们的 get_args() 函数,并添加了一个类。class 子类的看门狗的 FileSystemEventHandler 类。我们最终将测试文件路径传递给该类,并覆盖了 on_any_event() 方法。此方法在文件系统事件发生时触发。当那发生时,我们运行我们的测试。最后一点在代码的末尾,我们创建了一个 Observer() 对象,告诉它监视指定的项目路径,并在文件发生任何变化时调用我们的事件处理程序。

    此时,您应该能够在自己的代码中尝试这些想法了。也有一些特定于平台的方法来监视一个文件夹(比如 PyWin32 ),但是如果你像我一样在多个操作系统上运行,那么 watchdog 或者 rolling your own 可能是更好的选择。

  • 如何使用 Python 来观察文件的变化?
  • 观察目录的变化
  • 如何用 Python 发邮件(视频)

    原文:https://www.blog.pythonlibrary.org/2022/07/28/how-to-send-an-email-with-python-video/

    了解如何发送电子邮件(带附件!)使用 Python

    https://www.youtube.com/embed/2qvOqzK135Y?feature=oembed

    想了解更多?查看我的 Python 101 书籍:

  • Leanpub (电子书)
  • 亚马逊(平装)
  • 或者查阅我的其他书籍,学习如何创建 Excel 电子表格、编辑图像、使用 Jupyter Notebook、创建 GUI 等等:

  • Gumroad (电子书和视频)
  • 如何用 Python 发送电子邮件

    原文:https://www.blog.pythonlibrary.org/2010/05/14/how-to-send-email-with-python/

    在我工作的地方,我们运行许多用 Python 编写的登录脚本。当其中一个脚本出现错误时,我们想知道。因此,我们编写了一个简单的 Python 脚本,通过电子邮件将错误发送给我们。从那时起,我就需要想办法用一些更高级的脚本来发送附件。如果你是这个博客的长期读者,那么你可能还记得 wxPyMail ,这是一个简单的 wxPython 程序,可以发送电子邮件。在本文中,您将发现如何仅使用 Python 的标准库来发送电子邮件。我们将重点讨论 smtplib 和电子邮件模块。

    使用 smtplib 发送电子邮件

    用 smtplib 发邮件超级简单。你想看看有多简单吗?你当然知道!让我们来看看:

    import smtplib import string SUBJECT = "Test email from Python" TO = "[email protected]" FROM = "[email protected]" text = "blah blah blah" BODY = string.join(( "From: %s" % FROM, "To: %s" % TO, "Subject: %s" % SUBJECT , ), "\r\n") server = smtplib.SMTP(HOST) server.sendmail(FROM, [TO], BODY) server.quit()

    请注意,电子邮件的实际连接和发送只有两行代码。剩下的代码只是设置要发送的消息。在工作中,我们将所有这些都包装在一个可调用的函数中,并向它传递一些信息,比如错误是什么以及将错误发送给谁。如果需要登录,请在创建服务器变量后添加一行,执行以下操作:server.login(username,password)

    发送带有附件的电子邮件

    现在让我们看看如何发送带有附件的电子邮件。对于这个脚本,我们还将使用电子邮件模块。这里有一个简单的例子,基于我最近写的一些代码:

    import os import smtplib from email import Encoders from email.MIMEBase import MIMEBase from email.MIMEMultipart import MIMEMultipart from email.Utils import formatdate filePath = r'\\some\path\to\a\file' def sendEmail(TO = "[email protected]", FROM="[email protected]"): HOST = "mail.mydomain.com" msg = MIMEMultipart() msg["From"] = FROM msg["To"] = TO msg["Subject"] = "You've got mail!" msg['Date'] = formatdate(localtime=True) # attach a file part = MIMEBase('application', "octet-stream") part.set_payload( open(filePath,"rb").read() ) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(filePath)) msg.attach(part) server = smtplib.SMTP(HOST) # server.login(username, password) # optional failed = server.sendmail(FROM, TO, msg.as_string()) server.close() except Exception, e: errorMsg = "Unable to send email. Error: %s" % str(e) if __name__ == "__main__": sendEmail()

    这里发生了相当多的事情,所以让我们来看看新的内容。首先,我们从电子邮件模块导入所有我们需要的零碎信息。然后我们创建一个发送电子邮件的函数。接下来,我们创建一个 MIMEMultipart 对象。这个方便的东西可以保存我们的电子邮件。它使用一个类似 dict 的界面来添加字段,如收件人、发件人、主题等。您会注意到我们还有一个日期字段。这只是抓取你的电脑的当前日期,并将其转换为适当的 MIME 电子邮件格式。

    我们最感兴趣的是如何附加文件。这里我们创建了一个 MIMEBase 对象,并将其有效负载设置为我们想要附加的文件。注意,我们需要告诉它将文件作为二进制文件读取,即使文件是纯文本的。接下来,我们用 64 进制对数据流进行编码。最后两步是添加一个头,然后将 MIMEBase 对象附加到我们的 MIMEMultipart 对象。如果您有多个文件要附加,那么您可能希望将这一部分放入某种循环中,并对这些文件进行循环。事实上,我在前面提到的 wxPyMail 示例中就是这么做的。

    无论如何,一旦你完成了所有这些,你就可以做和上面的 smtplib 例子中一样的事情了。唯一的区别是我们更改了下面的行:

    server.sendmail(FROM, TO, msg.as_string())

    请注意 msg.as_string。我们需要将对象转换成字符串来完成这项工作。我们还将 sendmail 函数放在一个 try/except 语句中,以防发生不好的事情,我们的电子邮件无法发送。如果我们愿意,我们可以将 try/except 封装在一个 while 循环中,这样如果失败,我们可以重试发送 X 次电子邮件。

    我们已经介绍了如何发送一封简单的电子邮件以及如何发送一封带有附件的电子邮件。电子邮件模块内置了更多的功能,这里没有介绍,所以请务必阅读文档。祝编码愉快!

  • smtplib 模块
  • Python 的邮件模块
  • 如何用 Python 发送电子邮件

    原文:https://www.blog.pythonlibrary.org/2021/09/21/how-to-send-emails-with-python/

    Python 提供了几个非常好的模块,可以用来制作电子邮件。它们是电子邮件smtplib 模块。在这两个模块中,您将花一些时间学习如何实际使用这些模块,而不是复习各种方法。

    具体来说,您将涉及以下内容:

  • 电子邮件的基础
  • 如何一次发送到多个地址
  • 如何使用“收件人”、“抄送”和“密件抄送”行发送电子邮件
  • 如何使用电子邮件模块添加附件和正文
  • 我们开始吧!

    电子邮件基础-如何用 smtplib 发送电子邮件

    smtplib 模块使用起来非常直观。你将写一个简单的例子,展示如何发送电子邮件。

    打开您最喜欢的 Python IDE 或文本编辑器,创建一个新的 Python 文件。将以下代码添加到该文件并保存:

    import smtplib
    HOST = "mySMTP.server.com"
    SUBJECT = "Test email from Python"
    TO = "[email protected]"
    FROM = "[email protected]"
    text = "Python 3.4 rules them all!"
    BODY = "\r\n".join((
    "From: %s" % FROM,
    "To: %s" % TO,
    "Subject: %s" % SUBJECT ,
    server = smtplib.SMTP(HOST)
    server.sendmail(FROM, [TO], BODY)
    server.quit()
    

    这里您只导入了 smtplib 模块。该代码的三分之二用于设置电子邮件。大多数变量都是显而易见的,所以您将只关注奇怪的一个,即 BODY。

    在这里,您使用字符串的 join() 方法将前面的所有变量组合成一个字符串,其中每一行都以回车符("/r ")加新行("/n ")结束。如果你把正文打印出来,它会是这样的:

    'From: [email protected]\r\nTo: [email protected]\r\nSubject: Test email from Python\r\n\r\nblah blah blah'
    

    之后,建立一个到主机的服务器连接,然后调用 smtplib 模块的 sendmail 方法发送电子邮件。然后断开与服务器的连接。您会注意到这段代码中没有用户名或密码。如果您的服务器需要身份验证,那么您需要添加以下代码:

    server.login(username, password)
    

    这应该在创建服务器对象后立即添加。通常,您会希望将这段代码放入一个函数中,并使用其中的一些参数来调用它。您甚至可能希望将这些信息放入配置文件中。

    让我们将这段代码放入一个函数中。

    import smtplib
    def send_email(host, subject, to_addr, from_addr, body_text):
        Send an email
        BODY = "\r\n".join((
                "From: %s" % from_addr,
                "To: %s" % to_addr,
                "Subject: %s" % subject ,
                body_text
        server = smtplib.SMTP(host)
        server.sendmail(from_addr, [to_addr], BODY)
        server.quit()
    if __name__ == "__main__":
        host = "mySMTP.server.com"
        subject = "Test email from Python"
        to_addr = "[email protected]"
        from_addr = "[email protected]"
        body_text = "Python rules them all!"
        send_email(host, subject, to_addr, from_addr, body_text)
    

    现在,您可以通过查看函数本身来了解实际代码有多小。那是 13 行!如果你不把正文中的每一项都放在自己的行上,你可以把它变得更短,但是它没有可读性。现在,您将添加一个配置文件来保存服务器信息和 from 地址。

    你为什么要这么做?许多组织使用不同的电子邮件服务器来发送电子邮件,或者如果电子邮件服务器升级并且名称改变,那么你只需要改变配置文件而不是代码。如果你的公司被另一家公司收购并合并,同样的事情也适用于发件人地址。

    让我们看看配置文件(保存为 email.ini ):

    [smtp]
    server = some.server.com
    from_addr = [email protected]
    

    这是一个非常简单的配置文件。在其中,您有一个标记为 smtp 的部分,其中有两个项目:服务器和 from_addr 。您将使用 ConfigParser 来读取这个文件,并将它转换成一个 Python 字典。下面是代码的更新版本(保存为 smtp_config.py )

    import os
    import smtplib
    import sys
    from configparser import ConfigParser
    def send_email(subject, to_addr, body_text):
        Send an email
        base_path = os.path.dirname(os.path.abspath(__file__))
        config_path = os.path.join(base_path, "email.ini")
        if os.path.exists(config_path):
            cfg = ConfigParser()
            cfg.read(config_path)
        else:
            print("Config not found! Exiting!")
            sys.exit(1)
        host = cfg.get("smtp", "server")
        from_addr = cfg.get("smtp", "from_addr")
        BODY = "\r\n".join((
            "From: %s" % from_addr,
            "To: %s" % to_addr,
            "Subject: %s" % subject ,
            body_text
        server = smtplib.SMTP(host)
        server.sendmail(from_addr, [to_addr], BODY)
        server.quit()
    if __name__ == "__main__":
        subject = "Test email from Python"
        to_addr = "[email protected]"
        body_text = "Python rules them all!"
        send_email(subject, to_addr, body_text)
    

    您在这段代码中添加了一个小检查。你想首先获取脚本本身所在的路径,这就是 base_path 所代表的。接下来,将路径和文件名结合起来,得到配置文件的完全限定路径。然后检查该文件是否存在。

    如果存在,您创建一个 ConfigParser ,如果不存在,您打印一条消息并退出脚本。为了安全起见,您应该在 ConfigParser.read() 调用周围添加一个异常处理程序,尽管该文件可能存在,但可能已损坏,或者您可能没有权限打开它,这将引发一个异常。

    这将是一个你可以自己尝试的小项目。无论如何,假设一切顺利,并且成功创建了 ConfigParser 对象。现在,您可以使用常用的 ConfigParser 语法从 _addr 信息中提取主机和

    现在你已经准备好学习如何同时发送多封电子邮件了!

    一次发送多封电子邮件

    能够一次发送多封电子邮件是一个很好的功能。

    继续修改你的最后一个例子,这样你就可以发送多封电子邮件了!

    import os
    import smtplib
    import sys
    from configparser import ConfigParser
    def send_email(subject, body_text, emails):
        Send an email
        base_path = os.path.dirname(os.path.abspath(__file__))
        config_path = os.path.join(base_path, "email.ini")
        if os.path.exists(config_path):
            cfg = ConfigParser()
            cfg.read(config_path)
        else:
            print("Config not found! Exiting!")
            sys.exit(1)
        host = cfg.get("smtp", "server")
        from_addr = cfg.get("smtp", "from_addr")
        BODY = "\r\n".join((
                "From: %s" % from_addr,
                "To: %s" % ', '.join(emails),
                "Subject: %s" % subject ,
                body_text
        server = smtplib.SMTP(host)
        server.sendmail(from_addr, emails, BODY)
        server.quit()
    if __name__ == "__main__":
        emails = ["[email protected]", "[email protected]"]
        subject = "Test email from Python"
        body_text = "Python rules them all!"
        send_email(subject, body_text, emails)
    

    您会注意到,在这个例子中,您删除了 to_addr 参数,并添加了一个 emails 参数,这是一个电子邮件地址列表。为此,您需要在正文的 To:部分创建一个逗号分隔的字符串,并将电子邮件列表传递给 sendmail 方法。因此,您执行以下操作来创建一个简单的逗号分隔的字符串:','。加入(邮件)。很简单,是吧?

    使用“收件人”、“抄送”和“密件抄送”行发送电子邮件

    现在你只需要弄清楚如何使用“抄送”和“密件抄送”字段发送邮件。

    让我们创建一个支持该功能的新版本的代码!

    import os
    import smtplib
    import sys
    from configparser import ConfigParser
    def send_email(subject, body_text, to_emails, cc_emails, bcc_emails):
        Send an email
        base_path = os.path.dirname(os.path.abspath(__file__))
        config_path = os.path.join(base_path, "email.ini")
        if os.path.exists(config_path):
            cfg = ConfigParser()
            cfg.read(config_path)
        else:
            print("Config not found! Exiting!")
            sys.exit(1)
        host = cfg.get("smtp", "server")
        from_addr = cfg.get("smtp", "from_addr")
        BODY = "\r\n".join((
                "From: %s" % from_addr,
                "To: %s" % ', '.join(to_emails),
                "CC: %s" % ', '.join(cc_emails),
                "BCC: %s" % ', '.join(bcc_emails),
                "Subject: %s" % subject ,
                body_text
        emails = to_emails + cc_emails + bcc_emails
        server = smtplib.SMTP(host)
        server.sendmail(from_addr, emails, BODY)
        server.quit()
    if __name__ == "__main__":
        emails = ["[email protected]"]
        cc_emails = ["[email protected]"]
        bcc_emails = ["[email protected]"]
        subject = "Test email from Python"
        body_text = "Python rules them all!"
        send_email(subject, body_text, emails, cc_emails, bcc_emails)
    

    在这段代码中,你传入 3 个列表,每个列表有一个电子邮件地址。您创建的抄送密件抄送字段与之前完全相同,但是您还需要将 3 个列表合并成一个,这样您就可以将合并后的列表传递给 sendmail() 方法。

    在 StackOverflow 这样的论坛上有一些传言说,一些电子邮件客户端可能会以奇怪的方式处理密件抄送字段,从而允许收件人通过电子邮件标题看到密件抄送列表。我无法确认这种行为,但我知道 Gmail 成功地从邮件标题中删除了密件抄送信息。

    现在您已经准备好使用 Python 的电子邮件模块了!

    使用电子邮件模块添加附件/正文

    现在,您将利用从上一节中学到的知识,将它与 Python 电子邮件模块结合起来,以便发送附件。

    电子邮件模块使得添加附件变得极其容易。代码如下:

    import os
    import smtplib
    import sys
    from configparser import ConfigParser
    from email import encoders
    from email.mime.text import MIMEText
    from email.mime.base import MIMEBase
    from email.mime.multipart import MIMEMultipart
    from email.utils import formatdate
    def send_email_with_attachment(subject, body_text, to_emails,
                                   cc_emails, bcc_emails, file_to_attach):
        Send an email with an attachment
        base_path = os.path.dirname(os.path.abspath(__file__))
        config_path = os.path.join(base_path, "email.ini")
        header = 'Content-Disposition', 'attachment; filename="%s"' % file_to_attach
        # get the config
        if os.path.exists(config_path):
            cfg = ConfigParser()
            cfg.read(config_path)
        else:
            print("Config not found! Exiting!")
            sys.exit(1)
        # extract server and from_addr from config
        host = cfg.get("smtp", "server")
        from_addr = cfg.get("smtp", "from_addr")
        # create the message
        msg = MIMEMultipart()
        msg["From"] = from_addr
        msg["Subject"] = subject
        msg["Date"] = formatdate(localtime=True)
        if body_text:
            msg.attach( MIMEText(body_text) )
        msg["To"] = ', '.join(to_emails)
        msg["cc"] = ', '.join(cc_emails)
        attachment = MIMEBase('application', "octet-stream")
            with open(file_to_attach, "rb") as fh:
                data = fh.read()
            attachment.set_payload( data )
            encoders.encode_base64(attachment)
            attachment.add_header(*header)
            msg.attach(attachment)
        except IOError:
            msg = "Error opening attachment file %s" % file_to_attach
            print(msg)
            sys.exit(1)
        emails = to_emails + cc_emails
        server = smtplib.SMTP(host)
        server.sendmail(from_addr, emails, msg.as_string())
        server.quit()
    if __name__ == "__main__":
        emails = ["[email protected]", "[email protected]"]
        cc_emails = ["[email protected]"]
        bcc_emails = ["[email protected]"]
        subject = "Test email with attachment from Python"
        body_text = "This email contains an attachment!"
        path = "/path/to/some/file"
        send_email_with_attachment(subject, body_text, emails, 
                                   cc_emails, bcc_emails, path)
    

    在这里,您重命名了您的函数并添加了一个新参数, file_to_attach 。您还需要添加一个头并创建一个 MIMEMultipart 对象。在添加附件之前,可以随时创建标题。

    MIMEMultipart 对象( msg )添加元素,就像向字典中添加键一样。您会注意到,您必须使用 email 模块的 formatdate 方法来插入正确格式化的日期。

    要添加消息体,您需要创建一个 MIMEText 的实例。如果您注意的话,您会发现您没有添加密件抄送信息,但是您可以通过遵循上面代码中的约定很容易地这样做。

    接下来,添加附件。您将它包装在一个异常处理程序中,并使用带有语句的来提取文件,并将其放入您的 MIMEBase 对象中。最后,你把它添加到 msg 变量中,然后发送出去。注意,您必须在 sendmail ()方法中将 msg 转换成一个字符串。

    现在你知道如何用 Python 发送电子邮件了。对于那些喜欢小型项目的人来说,您应该回去在服务器周围添加额外的错误处理。 sendmail 部分代码,以防在这个过程中发生一些奇怪的事情。

    一个例子是 SMTPAuthenticationErrorSMTPConnectError 。您还可以在附加文件的过程中加强错误处理,以捕捉其他错误。最后,您可能希望获得这些不同的电子邮件列表,并创建一个已删除重复项的规范化列表。如果您正在从文件中读取电子邮件地址列表,这一点尤其重要。

    另外,请注意,您的发件人地址是假的。你可以使用 Python 和其他编程语言来欺骗电子邮件,但这是非常不礼貌的,而且可能是非法的,这取决于你住在哪里。你已经被警告了!

    明智地使用你的知识,享受 Python 带来的乐趣和收益!

    想学习更多 Python 基础知识?然后查看以下教程:

    Python 101: 使用 JSON 的介绍

    python 101-创建多个流程

    python 101-用 pdb 调试你的代码

    如何在 Windows 上为 Kivy 设置 Wing IDE

    原文:https://www.blog.pythonlibrary.org/2013/11/18/how-to-set-up-wing-ide-for-kivy-on-windows/

    我喜欢用 Wingware 的 IDE 用 Python 编码。我正在用 Kivy 开发一些示例应用程序,这是一个跨平台的 Python GUI 框架,也可以为移动设备创建 UI。无论如何,在 Wing 中设置 Kivy 有点令人困惑,所以这里有一个速成班:

  • Download Kivy
  • 拉开 Kivy 的拉链。在我的例子中,我在这里解压它:C:\kivy1.7.2\
  • 运行解压到的目录中的 kivy.bat。您应该会看到如下所示的内容
  • 现在我们准备打开机翼。一旦你打开了,开始一个新的项目。然后进入项目菜单,选择位于列表底部的项目属性选项。您应该会看到如下所示的内容:

    Python 可执行文件选项设置为你的 Kivy 的 Python,在我的例子中是:c:\ Kivy 1 . 7 . 2 \ Python \ Python . exe

    Python 路径设置为 C:\kivy1.7.2\kivy (或者修改以匹配提取 kivy 的位置)。

    此时,您应该能够在您的环境中导入 kivy,但是您将无法实际执行您的 kivy 脚本。要解决这个问题,你需要进入项目属性对话框的底部,将环境设置下拉菜单更改为添加到继承的环境。最后,您需要将上面看到的 kivy.bat 屏幕中的路径信息复制到环境设置下的文本框中。在我的例子中,它看起来像这样:

    PATH=C:\kivy1.7.2\;C:\kivy1.7.2\Python;C:\kivy1.7.2\Python\Scripts;C:\kivy1.7.2\gstreamer\bin;C:\kivy1.7.2\MinGW\bin;C:\Python26\Lib\site-packages\PyQt4;C:\Python27\Lib\site-packages\PyQt4;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;c:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Program Files (x86)\Intel\Services\IPT\;C:\Program Files (x86)\IBM\Client Access\Emulator;C:\Program Files (x86)\IBM\Client Access\Shared;C:\Program Files (x86)\IBM\Client Access\;C:\Python26;C:\Python26\Scripts;C:\Program Files\TortoiseSVN\bin;C:\Program Files\SlikSvn\bin;C:\Program Files (x86)\Calibre2\;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files (x86)\GNU\GnuPG\pub;C:\Windows\Microsoft.NET\Framework64\v4.0.30319;C:\PROGRA~1\IBM\SQLLIB\BIN;C:\PROGRA~1\IBM\SQLLIB\FUNCTION;C:\Program Files (x86)\Git\cmd;C:\Program Files (x86)\Mercurial;C:\MinGW\bin

    除了它应该都在一行上。否则 Wing 会抱怨每个变量必须在 var=value 对中。一旦你完成了所有这些,你就可以在 Wing 中运行一个 kivy 脚本。这避免了将 Python 文件拖到 kivy.bat 上来运行 kivy 程序的需要。

    如何截图并打印你的 wxPython 应用程序

    原文:https://www.blog.pythonlibrary.org/2010/04/16/how-to-take-a-screenshot-of-your-wxpython-app-and-print-it/

    你有没有想过让你的 wxPython 代码自己截图会很酷?嗯, Andrea Gavana 想出了一个很酷的方法来做到这一点,根据他在 wxPython 邮件列表上告诉我们的内容和我从其他来源了解到的内容,你很快就会知道如何不仅截取屏幕截图,而且如何将它发送到你的打印机!

    我们先来看看如何截图:

    import sys import wx import snapshotPrinter class MyForm(wx.Frame): #---------------------------------------------------------------------- def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial", size=(500,500)) # Add a panel so it looks the correct on all platforms panel = wx.Panel(self, wx.ID_ANY) screenshotBtn = wx.Button(panel, wx.ID_ANY, "Take Screenshot") screenshotBtn.Bind(wx.EVT_BUTTON, self.onTakeScreenShot) printBtn = wx.Button(panel, label="Print Screenshot") printBtn.Bind(wx.EVT_BUTTON, self.onPrint) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(screenshotBtn, 0, wx.ALL|wx.CENTER, 5) sizer.Add(printBtn, 0, wx.ALL|wx.CENTER, 5) panel.SetSizer(sizer) def onTakeScreenShot(self, event): """ Takes a screenshot of the screen at give pos & size (rect). """ print 'Taking screenshot...' rect = self.GetRect() # see http://aspn.activestate.com/ASPN/Mail/Message/wxpython-users/3575899 # created by Andrea Gavana # adjust widths for Linux (figured out by John Torres # http://article.gmane.org/gmane.comp.python.wxpython/67327) if sys.platform == 'linux2': client_x, client_y = self.ClientToScreen((0, 0)) border_width = client_x - rect.x title_bar_height = client_y - rect.y rect.width += (border_width * 2) rect.height += title_bar_height + border_width #Create a DC for the whole screen area dcScreen = wx.ScreenDC() #Create a Bitmap that will hold the screenshot image later on #Note that the Bitmap must have a size big enough to hold the screenshot #-1 means using the current default colour depth bmp = wx.EmptyBitmap(rect.width, rect.height) #Create a memory DC that will be used for actually taking the screenshot memDC = wx.MemoryDC() #Tell the memory DC to use our Bitmap #all drawing action on the memory DC will go to the Bitmap now memDC.SelectObject(bmp) #Blit (in this case copy) the actual screen on the memory DC #and thus the Bitmap memDC.Blit( 0, #Copy to this X coordinate 0, #Copy to this Y coordinate rect.width, #Copy this width rect.height, #Copy this height dcScreen, #From where do we copy? rect.x, #What's the X offset in the original DC? rect.y #What's the Y offset in the original DC? #Select the Bitmap out of the memory DC by selecting a new #uninitialized Bitmap memDC.SelectObject(wx.NullBitmap) img = bmp.ConvertToImage() fileName = "myImage.png" img.SaveFile(fileName, wx.BITMAP_TYPE_PNG) print '...saving as png!' #---------------------------------------------------------------------- def onPrint(self, event): Send screenshot to the printer printer = snapshotPrinter.SnapshotPrinter() printer.sendToPrinter() # Run the program if __name__ == "__main__": app = wx.App(False) frame = MyForm() frame.Show() app.MainLoop()

    这段代码创建了一个相当大框架,其中有两个按钮。是的,很无聊,但这是演示,不是艺术展。我们最关心的部分是 onTakeScreenShot 方法。如果你去第一个评论链接,你会找到安德里亚·加瓦那的这个剧本的原始版本。我们添加了一个来自 John Torres 的条件,使得这个脚本在 Linux 上表现得更好,因为它最初是为 Windows 编写的。注释讲述了代码的故事,所以请花点时间阅读它们,当您完成后,我们可以继续讨论如何将结果发送到打印机。

    快照打印机脚本

    ####################################################################### # snapshotPrinter.py # Created: 12/26/2007 by mld # Description: Displays screenshot image using html and then allows # the user to print it. ####################################################################### import os import wx from wx.html import HtmlEasyPrinting, HtmlWindow class SnapshotPrinter(wx.Frame): #---------------------------------------------------------------------- def __init__(self, title='Snapshot Printer'): wx.Frame.__init__(self, None, wx.ID_ANY, title, size=(650,400)) self.panel = wx.Panel(self, wx.ID_ANY) self.printer = HtmlEasyPrinting(name='Printing', parentWindow=None) self.html = HtmlWindow(self.panel) self.html.SetRelatedFrame(self, self.GetTitle()) if not os.path.exists('screenshot.htm'): self.createHtml() self.html.LoadPage('screenshot.htm') pageSetupBtn = wx.Button(self.panel, wx.ID_ANY, 'Page Setup') printBtn = wx.Button(self.panel, wx.ID_ANY, 'Print') cancelBtn = wx.Button(self.panel, wx.ID_ANY, 'Cancel') self.Bind(wx.EVT_BUTTON, self.onSetup, pageSetupBtn) self.Bind(wx.EVT_BUTTON, self.onPrint, printBtn) self.Bind(wx.EVT_BUTTON, self.onCancel, cancelBtn) sizer = wx.BoxSizer(wx.VERTICAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.html, 1, wx.GROW) btnSizer.Add(pageSetupBtn, 0, wx.ALL, 5) btnSizer.Add(printBtn, 0, wx.ALL, 5) btnSizer.Add(cancelBtn, 0, wx.ALL, 5) sizer.Add(btnSizer) self.panel.SetSizer(sizer) self.panel.SetAutoLayout(True) #---------------------------------------------------------------------- def createHtml(self): Creates an html file in the home directory of the application that contains the information to display the snapshot print 'creating html...' html = '\n\n![](https://github.com/OpenDocCN/geekdoc-python-zh/raw/master/pythonlibrary/img/ec9778b1600f04331bfd57657fbc23b1.png)\n\n' f = file('screenshot.htm', 'w') f.write(html) f.close() #---------------------------------------------------------------------- def onSetup(self, event): self.printer.PageSetup() #---------------------------------------------------------------------- def onPrint(self, event): self.sendToPrinter() #---------------------------------------------------------------------- def sendToPrinter(self): """""" self.printer.GetPrintData().SetPaperId(wx.PAPER_LETTER) self.printer.PrintFile(self.html.GetOpenedPage()) #---------------------------------------------------------------------- def onCancel(self, event): self.Close() class wxHTML(HtmlWindow): #---------------------------------------------------------------------- def __init__(self, parent, id): html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE) if __name__ == '__main__': app = wx.App(False) frame = SnapshotPrinter() frame.Show() app.MainLoop()

    这个小脚本使用 HtmlWindow 小部件和 HtmlEasyPrinting 方法向打印机发送内容。基本上,您可以创建一些非常简单的 HTML 代码(参见 createHtml 方法),然后使用 HtmlWindow 查看它。接下来,您使用 HtmlEasyPrinting 将其发送到打印机。它实际上会显示打印机对话框,让您选择要将文档发送到哪台打印机。

    我希望这篇文章对您的编程有所帮助。希望能在评论里听到你的声音!

    如何用 timeit 为小块 Python 代码计时

    原文:https://www.blog.pythonlibrary.org/2014/01/30/how-to-time-small-pieces-of-python-code-with-timeit/

    有时候当你在编码的时候,你想知道一个特定的函数运行需要多长时间。这个主题称为性能分析或性能调优。Python 的标准库中内置了几个分析器,但是对于小段代码,使用 Python 的 timeit 模块会更容易。因此, timeit 将是本教程的重点。 timeit 模块使用特定于平台的方法来获得最准确的运行时间。基本上, timeit 模块将进行一次设置,运行代码 n 次,并返回运行所用的时间。通常它会输出一个“3 分中最好”的分数。奇怪的是,默认运行代码的次数是 1,000,000 次循环。 timeit 在 Linux / Mac 上用 time.time()计时,在 Windows 上用 time.clock()计时,以获得最准确的读数,这是大多数人不会想到的。

    您可以从命令行或通过导入来运行 timeit 模块。我们将查看这两个用例。

    在控制台中计时

    在命令行上使用 timeit 模块非常简单。这里有几个例子:

    python -m timeit -s "[ord(x) for x in 'abcdfghi']" 100000000 loops, best of 3: 0.0115 usec per loop python -m timeit -s "[chr(int(x)) for x in '123456789']" 100000000 loops, best of 3: 0.0119 usec per loop

    这是怎么回事?当你在命令行上调用 Python 并给它传递“-m”选项时,你是在告诉它查找一个模块并把它作为主程序使用。“-s”告诉 timeit 模块运行一次设置。然后,它将代码运行 n 次循环,并返回 3 次运行的最佳平均值。对于这些愚蠢的例子,你不会看到太大的区别。让我们快速看一下 timeit's help,这样我们可以了解更多关于它是如何工作的:

    C:\Users\mdriscoll>python -m timeit -h Tool for measuring execution time of small code snippets. This module avoids a number of common traps for measuring execution times. See also Tim Peters' introduction to the Algorithms chapter in the Python Cookbook, published by O'Reilly. Library usage: see the Timer class. Command line usage: python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [--] [statement] Options: -n/--number N: how many times to execute 'statement' (default: see below) -r/--repeat N: how many times to repeat the timer (default 3) -s/--setup S: statement to be executed once initially (default 'pass') -t/--time: use time.time() (default on Unix) -c/--clock: use time.clock() (default on Windows) -v/--verbose: print raw timing results; repeat for more digits precision -h/--help: print this usage message and exit --: separate options from statement, use when statement starts with - statement: statement to be timed (default 'pass') A multi-line statement may be given by specifying each line as a separate argument; indented lines are possible by enclosing an argument in quotes and using leading spaces. Multiple -s options are treated similarly. If -n is not given, a suitable number of loops is calculated by trying successive powers of 10 until the total time is at least 0.2 seconds. The difference in default timer function is because on Windows, clock() has microsecond granularity but time()'s granularity is 1/60th of a second; on Unix, clock() has 1/100th of a second granularity and time() is much more precise. On either platform, the default timer functions measure wall clock time, not the CPU time. This means that other processes running on the same computer may interfere with the timing. The best thing to do when accurate timing is necessary is to repeat the timing a few times and use the best time. The -r option is good for this; the default of 3 repetitions is probably enough in most cases. On Unix, you can use clock() to measure CPU time. Note: there is a certain baseline overhead associated with executing a pass statement. The code here doesn't try to hide it, but you should be aware of it. The baseline overhead can be measured by invoking the program without arguments. The baseline overhead differs between Python versions! Also, to fairly compare older Python versions to Python 2.3, you may want to use python -O for the older versions to avoid timing SET_LINENO instructions.

    这告诉使用所有我们可以通过的奇妙的标志,以及它们做什么。它也告诉我们一些关于 timeit 如何在幕后运作的事情。让我们写一个简单的函数,看看我们能否从命令行计时:

    # simple_func.py def my_function(): 1 / 0 except ZeroDivisionError:

    这个函数所做的只是导致一个被忽略的错误。是的,这是一个愚蠢的例子。为了让 timeit 在命令行上运行这段代码,我们需要将代码导入到它的名称空间中,所以请确保您已经将当前的工作目录更改为该脚本所在的文件夹。然后运行以下命令:

    python -m timeit "import simple_func; simple_func.my_function()" 1000000 loops, best of 3: 1.77 usec per loop

    这里导入函数,然后调用它。注意,我们用分号分隔导入和函数调用,Python 代码用引号括起来。现在我们准备学习如何在实际的 Python 脚本中使用 timeit

    导入 timeit 进行测试

    在代码中使用 timeit 模块也很容易。我们将使用之前相同的愚蠢脚本,并在下面向您展示如何操作:

    def my_function(): 1 / 0 except ZeroDivisionError: if __name__ == "__main__": import timeit setup = "from __main__ import my_function" print timeit.timeit("my_function()", setup=setup)

    在这里,我们检查脚本是否正在直接运行(即没有导入)。如果是,那么我们导入 timeit ,创建一个设置字符串将函数导入到 timeit 的名称空间,然后我们调用 timeit.timeit 。您会注意到,我们用引号将对函数的调用传递出去,然后是设置字符串。这真的就是全部了!

    现在你知道如何使用 timeit 模块了。它非常擅长计时简单的代码片段。您通常会将它用于您怀疑运行时间过长的代码。如果您想要更详细地了解代码中正在发生的事情,那么您可能希望切换到分析器。开心快乐编码!

  • 关于 timeit 的 Python 文档
  • py motw-Time it "对小部分 Python 代码的执行进行计时。
  • 在 timeit 上深入研究 Python 部分
  • 关于 timeit 的梦想代码论坛教程
  • 如何在演示之外使用 wxPython 演示代码

    原文:https://www.blog.pythonlibrary.org/2018/01/23/how-to-use-wxpython-demo-code-outside-the-demo/

    有时,有人会问他们如何在演示之外运行来自 wxPython 的演示代码。换句话说,他们想知道如何从演示中提取代码并在自己的程序中运行。我想我很久以前在 wxPython wiki 上写过这个主题,但是我想我也应该在这里写这个主题。

    如何处理日志

    我经常看到的第一个问题是,演示代码中充满了对某种日志的调用。它总是写入该日志,以帮助开发人员了解不同的事件是如何触发的,或者不同的方法是如何调用的。这一切都很好,但这使得从演示中复制代码变得很困难。让我们从 wx 中取出代码。ListBox 演示作为一个例子,看看我们是否可以让它在演示之外工作。下面是演示代码:

    import wx #---------------------------------------------------------------------- # BEGIN Demo Code class FindPrefixListBox(wx.ListBox): def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=[], style=0, validator=wx.DefaultValidator): wx.ListBox.__init__(self, parent, id, pos, size, choices, style, validator) self.typedText = '' self.log = parent.log self.Bind(wx.EVT_KEY_DOWN, self.OnKey) def FindPrefix(self, prefix): self.log.WriteText('Looking for prefix: %s\n' % prefix) if prefix: prefix = prefix.lower() length = len(prefix) # Changed in 2.5 because ListBox.Number() is no longer supported. # ListBox.GetCount() is now the appropriate way to go. for x in range(self.GetCount()): text = self.GetString(x) text = text.lower() if text[:length] == prefix: self.log.WriteText('Prefix %s is found.\n' % prefix) return x self.log.WriteText('Prefix %s is not found.\n' % prefix) return -1 def OnKey(self, evt): key = evt.GetKeyCode() if key >= 32 and key <= 127: self.typedText = self.typedText + chr(key) item = self.FindPrefix(self.typedText) if item != -1: self.SetSelection(item) elif key == wx.WXK_BACK: # backspace removes one character and backs up self.typedText = self.typedText[:-1] if not self.typedText: self.SetSelection(0) else: item = self.FindPrefix(self.typedText) if item != -1: self.SetSelection(item) else: self.typedText = '' evt.Skip() def OnKeyDown(self, evt): #--------------------------------------------------------------------------- class TestListBox(wx.Panel): def __init__(self, parent, log): self.log = log wx.Panel.__init__(self, parent, -1) sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen'] wx.StaticText(self, -1, "This example uses the wx.ListBox control.", (45, 10)) wx.StaticText(self, -1, "Select one:", (15, 50)) self.lb1 = wx.ListBox(self, 60, (100, 50), (90, 120), sampleList, wx.LB_SINGLE) self.Bind(wx.EVT_LISTBOX, self.EvtListBox, self.lb1) self.Bind(wx.EVT_LISTBOX_DCLICK, self.EvtListBoxDClick, self.lb1) self.lb1.Bind(wx.EVT_RIGHT_UP, self.EvtRightButton) self.lb1.SetSelection(3) self.lb1.Append("with data", "This one has data"); self.lb1.SetClientData(2, "This one has data"); wx.StaticText(self, -1, "Select many:", (220, 50)) self.lb2 = wx.ListBox(self, 70, (320, 50), (90, 120), sampleList, wx.LB_EXTENDED) self.Bind(wx.EVT_LISTBOX, self.EvtMultiListBox, self.lb2) self.lb2.Bind(wx.EVT_RIGHT_UP, self.EvtRightButton) self.lb2.SetSelection(0) sampleList = sampleList + ['test a', 'test aa', 'test aab', 'test ab', 'test abc', 'test abcc', 'test abcd' ] sampleList.sort() wx.StaticText(self, -1, "Find Prefix:", (15, 250)) fp = FindPrefixListBox(self, -1, (100, 250), (90, 120), sampleList, wx.LB_SINGLE) fp.SetSelection(0) def EvtListBox(self, event): self.log.WriteText('EvtListBox: %s, %s, %s\n' % (event.GetString(), event.IsSelection(), event.GetSelection() # event.GetClientData() lb = event.GetEventObject() # data = lb.GetClientData(lb.GetSelection()) # if data is not None: # self.log.WriteText('\tdata: %s\n' % data) def EvtListBoxDClick(self, event): self.log.WriteText('EvtListBoxDClick: %s\n' % self.lb1.GetSelection()) self.lb1.Delete(self.lb1.GetSelection()) def EvtMultiListBox(self, event): self.log.WriteText('EvtMultiListBox: %s\n' % str(self.lb2.GetSelections())) def EvtRightButton(self, event): self.log.WriteText('EvtRightButton: %s\n' % event.GetPosition()) if event.GetEventObject().GetId() == 70: selections = list(self.lb2.GetSelections()) selections.reverse() for index in selections: self.lb2.Delete(index) #---------------------------------------------------------------------- # END Demo Code #----------------------------------------------------------------------

    我不打算解释演示代码本身。相反,当我想尝试在演示之外运行它时,我将把重点放在这段代码出现的问题上。在演示的最后有一个 runTest 函数,我没有复制它,因为如果你在演示之外复制它,代码不会做任何事情。你看,演示代码有某种包装来使它工作。如果你想使用演示代码,你需要添加你自己的“包装器”。

    这段代码呈现的主要问题是许多方法都调用了 self.log.WriteText 。您不能从代码中看出 log 对象是什么,但是您知道它有一个 WriteText 方法。在演示中,您会注意到,当其中一个方法触发时,WriteText 调用似乎会写入演示底部的文本控件。所以日志必须是一个文本控件!

    有许多不同的方法可以解决日志问题。以下是我最喜欢的三个:

  • 移除对 self.log.WriteText 的所有调用
  • 创建我自己的文本控件并将其传入
  • 用 WriteText 方法创建一个简单的类
  • 我在很多场合都选择了第一种,因为这是一种简单的开始方式。但是对于教程来说,这有点无聊,所以我们将选择第三个选项,用 WriteText 方法创建一个类!将以下代码添加到包含上述代码的同一文件中:

    #---------------------------------------------------------------------- # Start Your own code here class FakeLog: The log in the demo is a text control, so just create a class with an overridden WriteText function def WriteText(self, string): print(string) # Create a frame that can wrap your demo code (works in most cases) class MyFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title='Listbox demo', size=(800,600)) log = FakeLog() panel = TestListBox(self, log=log) self.Show() if __name__ == '__main__': app = wx.App(False) frame = MyFrame() app.MainLoop()

    这里我们只是用 WriteText 方法创建了一个 FakeLog ,它接受一个字符串作为唯一的参数。该方法所做的就是将字符串打印到 stdout。然后我们创建 wx 的一个子类。框架,初始化我们的假日志和演示代码,并显示我们的框架。现在我们有了一个不在演示中的演示代码!如果你愿意,你可以在 Github 上获得完整的代码。

    其他演示问题

    还有一些其他的演示没有遵循与列表框演示完全相同的 API。例如,如果你尝试使用我在上面为 wx 创建的类。按钮演示,你会发现它的 log 对象调用的是 write()方法而不是 WriteText()方法。在这种情况下,解决方案是显而易见的,因为我们只需要向我们的假日志记录类添加第二个方法:

    class FakeLog: The log in the demo is a text control, so just create a class with an overridden WriteText function def WriteText(self, string): print(string) def write(self, string): print(string)

    现在我们的演示运行代码更加灵活了。然而,当我让我的一个读者测试这段代码时,他们注意到了一个关于 wx 的问题。ListCtrl 演示。问题是它导入了一个名为“images”的模块。实际上有几个演示引用了这个模块。你只需要从演示中复制 images.py ,并把它放在你正在编写的脚本所在的位置,这样你就可以导入它了。

    注意:我收到一份报告,说 wxPython 4 最新测试版中包含的 images.py 文件对他们不适用,他们不得不从旧版本的演示中获取一份副本。我自己没有遇到过这个问题,但请记住这一点。

    现在,您应该有了让 wxPython 演示中的大多数演示在您自己的代码中工作所需的工具。去抓些代码来试试吧!编码快乐!

    如何用 Python 给你的照片加水印

    原文:https://www.blog.pythonlibrary.org/2017/10/17/how-to-watermark-your-photos-with-python/

    当你在网上查找照片时,你会注意到有些照片带有水印。水印通常是覆盖在照片上的一些文本或徽标,用于标识照片的拍摄者或照片的所有者。一些专业人士建议在社交媒体上分享照片之前给照片添加水印,以防止其他人将你的照片用作自己的照片,并从你的作品中获利。当然,水印可以很容易地被移除,所以这并不像过去作为数字版权工具那样有用。

    反正枕头包提供了给照片添加水印所需的工具!如果你还没有安装枕头,你需要做的第一件事是:

    pip install pillow
    

    一旦安装完毕,我们就可以继续了!

    添加文本水印

    我们将从给照片添加一些文字开始。让我们用这张我在俄勒冈州拍摄的耶奎纳灯塔的照片:

    现在我们将添加一些文字到图像中。在这种情况下,让我们添加我的域名:www.mousevspython.com

    from PIL import Image
    from PIL import ImageDraw
    from PIL import ImageFont
    def watermark_text(input_image_path,
                       output_image_path,
                       text, pos):
        photo = Image.open(input_image_path)
        # make the image editable
        drawing = ImageDraw.Draw(photo)
        black = (3, 8, 12)
        font = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40)
        drawing.text(pos, text, fill=black, font=font)
        photo.show()
        photo.save(output_image_path)
    if __name__ == '__main__':
        img = 'lighthouse.jpg'
        watermark_text(img, 'lighthouse_watermarked.jpg',
                       text='www.mousevspython.com',
                       pos=(0, 0))
    

    这里我们从 PIL 导入几个类: ImageImageDrawImageFont 。然后我们创建一个函数, watermark_text ,它有四个参数:输入图像页面、输出图像路径、要添加到图像中的文本以及放置文本的位置坐标。

    接下来,我们打开我们的形象。然后,我们基本上通过使用 ImageDraw 重新绘制图像来制作图像的副本。绘制方法。这使得我们可以更容易地向其中添加文本。然后我们使用 ImageFont.truetype 创建一个字体。该字体是 Pillow 库中包含的一种字体。我们也将字体大小设置为 40 磅。最后我们显示结果并保存到磁盘。结果如下:

    现在让我们继续添加图像,而不仅仅是文本!

    用图像加水印

    大多数专业摄影师最终都会在他们的照片上打上商标。有时这包括他们网站的风格化“照片”版本。在 Pillow 中将一张照片添加到另一张照片也相当容易。让我们来看看怎么做吧!

    在这个例子中,我们将使用我的一个标志作为水印图像。

    from PIL import Image
    def watermark_photo(input_image_path,
                        output_image_path,
                        watermark_image_path,
                        position):
        base_image = Image.open(input_image_path)
        watermark = Image.open(watermark_image_path)
        # add watermark to your image
        base_image.paste(watermark, position)
        base_image.show()
        base_image.save(output_image_path)
    if __name__ == '__main__':
        img = 'lighthouse.jpg'
        watermark_with_photo(img, 'lighthouse_watermarked2.jpg',
                             'watermark.png', position=(0,0))
    

    这里我们创建了一个与上一节中的函数非常相似的函数,但是我们没有传入文本,而是传入水印的文件路径。在该函数中,我们打开了我们想要水印的图像以及水印图像本身。然后,我们获取要添加水印的图像并调用它的 paste() 方法,同时传入我们想要粘贴的内容(即水印)和我们想要粘贴的位置。最后,我们显示图像并保存它。结果如下:

    嗯,这并没有按照我预想的方式进行。正如你所看到的,有一个黑色的背景遮挡了很多照片,因为当我们粘贴它时,我们没有考虑到透明度。

    用透明度给图像加水印

    让我们创建一个新的函数,可以使用透明度,所以我们从水印中删除所有的黑色。我在 StackOverflow 上找到了这个问题的解决方案,所以我在这个例子中使用了它并稍微修改了一下

    from PIL import Image
    def watermark_with_transparency(input_image_path,
                                    output_image_path,
                                    watermark_image_path,
                                    position):
        base_image = Image.open(input_image_path)
        watermark = Image.open(watermark_image_path)
        width, height = base_image.size
        transparent = Image.new('RGBA', (width, height), (0,0,0,0))
        transparent.paste(base_image, (0,0))
        transparent.paste(watermark, position, mask=watermark)
        transparent.show()
        transparent.save(output_image_path)
    if __name__ == '__main__':
        img = 'lighthouse.jpg'
        watermark_with_transparency(img, 'lighthouse_watermarked3.jpg',
                                    'watermark.png', position=(0,0))
    

    在这段代码中,我们接受了与上一个例子中相同的所有参数。这一次,我们不仅打开了两幅图像,而且还获取了想要添加水印的图像的宽度和高度。然后,我们创建一个新的图像使用相同的宽度和高度的图像,我们是水印。你会注意到,我们创建的这个图像是 RGBA,这意味着它有红色,绿色和蓝色的阿尔法。接下来,我们粘贴在图像中,我们想水印从左上角开始,这是(0,0)。然后,我们使用传入的位置粘贴我们的水印,我们还用水印本身来屏蔽水印。最后我们显示并保存图像。

    生成的图像如下所示:

    很酷,是吧?

    在这篇文章中,我们介绍了两种不同的给照片添加水印的方法。在第一个例子中,我们所做的只是将您选择的文本添加到图像中。第二个例子演示了一种添加图像水印的方法,但是它没有考虑 alpha(透明度)。我们用第三个例子纠正了这个问题。我希望这些例子对你有所帮助。编码快乐!

  • StackOverflow: 如何将一张带有透明度的 PNG 图片粘贴到另一张没有白色像素的 PIL 图片上?
  • 如何用 Python 调整照片大小
  • 用 Python 将一张照片转换成黑白
  • 如何用 Python 旋转/镜像照片
  • 如何用 Python 裁剪照片
  • Python Kickstarter 的图像处理即将结束

    原文:https://www.blog.pythonlibrary.org/2021/01/25/image-processing-with-python-kickstarter-ending-soon/

    我的新书《枕头:用 Python 处理图像》的 Kickstarter 将在 8 天后结束。你应该去看看,学习如何用 Python 编辑照片!

    你将在本书中了解到以下主题:

  • 第 1 章-枕头基础知识
  • 第 2 章-颜色
  • 第 3 章-获取图像元数据(ExifTags / TiffTags)
  • 第 4 章-图像过滤器
  • 第 5 章-裁剪、旋转和调整图像大小
  • 第 6 章-增强图像(ImageEnhance)
  • 第 7 章-组合图像
  • 第 8 章-用枕头画画(ImageDraw)
  • 第 9 章-绘图文本
  • 第 10 章-图像印章
  • 还有更多!
  • 上周末,我实现了我的第一个延伸目标,并将为这本书增加两个新的章节。查看 Kickstarter 了解详情!

    改进 MediaLocker: wxPython、SQLAlchemy 和 MVC

    原文:https://www.blog.pythonlibrary.org/2011/11/30/improving-medialocker-wxpython-sqlalchemy-and-mvc/

    这个博客在本月早些时候发表了一篇关于 wxPython、SQLAlchemy、CRUD 和 MVC 的文章。我们在那篇文章中创建的程序被称为“MediaLocker”,不管它是否被明确地这样表述。无论如何,从那以后,我收到了一些关于改进程序的评论。一条来自 SQLAlchemy 本身的创意者之一 Michael Bayer,另一条来自 Werner Bruhin,一个经常出现在 wxPython 邮件列表中帮助新用户的好人。因此,我按照他们的建议着手创建代码的改进版本。沃纳随后对其进行了进一步的改进。所以在这篇文章中,我们将着眼于改进代码,首先是我的例子,然后是他的例子。尽管说得够多了;让我们进入故事的实质吧!

    让 MediaLocker 变得更好

    Michael Bayer 和 Werner Bruhin 都认为我应该只连接数据库一次,因为这是一个相当“昂贵”的操作。如果同时存在多个会话,这可能是一个问题,但即使在我的原始代码中,我也确保关闭会话,这样就不会发生这种情况。当我编写最初的版本时,我考虑过将会话创建分离出来,但最终采用了我认为更简单的方法。为了解决这个棘手的问题,我修改了代码,这样我就可以传递会话对象,而不是不断地调用控制器的 connectToDatabase 函数。你可以阅读更多关于会议在这里。请看来自 mediaLocker.py 的代码片段:

    class BookPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) if not os.path.exists("devdata.db"): controller.setupDatabase() self.session = controller.connectToDatabase() self.bookResults = controller.getAllRecords(self.session) except: self.bookResults = []

    注意,我们前面有一个小的条件,如果数据库还不存在,它将创建数据库。接下来,我在主 GUI 中创建会话对象,作为 panel 子类的属性。然后我把它传到我需要的地方。上面可以看到一个例子,我将会话对象传递给控制器的 getAllRecords 方法。

    另一个大的变化是从 model.py 中删除了 ObjectListView 模型,而只使用 SQLAlchemy 表类:

    ######################################################################## class Book(DeclarativeBase): """""" __tablename__ = "book" id = Column(Integer, primary_key=True) author_id = Column(Integer, ForeignKey("person.id")) title = Column(Unicode) isbn = Column(Unicode) publisher = Column(Unicode) person = relation("Person", backref="books", cascade_backrefs=False) @property def author(self): return "%s %s" % (self.person.first_name, self.person.last_name)

    除了使用 SQLAlchemy 构造之外,这实际上与原始类基本相同。我还需要添加一个特殊的属性来返回作者的全名,以便在我们的小部件中显示,所以我们使用了 Python 的内置函数: property ,它返回一个 property 属性。如果只看代码的话更容易理解。如您所见,我们将属性作为装饰器应用于作者方法。

    沃纳的补充大多是在模型中增加更明确的进口。模型的最大变化如下:

    import sys if not hasattr(sys, 'frozen'): # needed when having multiple versions of SA installed import pkg_resources pkg_resources.require("sqlalchemy") # get latest version import sqlalchemy as sa import sqlalchemy.orm as sao import sqlalchemy.ext.declarative as sad from sqlalchemy.ext.hybrid import hybrid_property maker = sao.sessionmaker(autoflush=True, autocommit=False) DBSession = sao.scoped_session(maker) class Base(object): """Extend the base class - Provides a nicer representation when a class instance is printed. Found on the SA wiki, not included with TG def __repr__(self): return "%s(%s)" % ( (self.__class__.__name__), ', '.join(["%s=%r" % (key, getattr(self, key)) for key in sorted(self.__dict__.keys()) if not key.startswith('_')])) DeclarativeBase = sad.declarative_base(cls=Base) metadata = DeclarativeBase.metadata def init_model(engine): """Call me before using any of the tables or classes in the model.""" DBSession.configure(bind=engine)

    前几行是为在机器上安装了 SetupTools / easy_install 的人准备的。如果用户安装了多个版本的 SQLALchemy,它将强制用户使用最新的版本。大多数其他导入都被缩短了,以使各种类和属性的来源变得非常明显。老实说,我对 hybrid_property 并不熟悉,所以下面是它的 docstring 所说的:

    一个装饰器,允许用实例级和类级行为定义 Python 描述符。

    你可以在这里阅读更多:http://www.sqlalchemy.org/docs/orm/extensions/hybrid.html

    Werner 还在基类中添加了一个小的 repr 方法,使它在打印时返回一个更好的类实例表示,这对于调试来说很方便。最后,他添加了一个名为 init_model 的函数来初始化模型。

    现在您应该知道,Werner 和我已经决定将 MediaLocker 做成一个支持 wxPython 数据库的应用程序的例子。自从我上面提到的简单编辑之后,他已经在这上面做了很多工作。我们将很快就此发布官方声明。与此同时,我希望这有助于打开你的眼界,找到一些有趣的方法来增强一个项目,并使它变得干净一点。我的计划是给这个程序增加很多新的特性,并且除了我所有的其他文章之外,在这个博客上记录这些特性。

  • wxasa 2 . zip
  • wxSa2.tar
  • Black 简介——不妥协的 Python 代码格式化程序

    原文:https://www.blog.pythonlibrary.org/2019/07/16/intro-to-black-the-uncompromising-python-code-formatter/

    有几个 Python 代码检查器可用。例如,许多开发人员喜欢使用 PylintFlake8 来检查他们代码中的错误。这些工具使用静态代码分析来检查代码中的错误或命名问题。Flake8 还会检查你的代码,看看你是否遵守了 Python 的风格指南 PEP8

    然而,有一个新的工具你可以使用,叫做黑色。Black 是一个 Python 代码格式化程序。它会根据黑色代码的风格重新格式化你的整个文件,非常接近 PEP8。

    安装黑色很容易。您可以使用 pip 来实现这一点:

    pip install black
    

    你也可以按照这些指令配置流行的文本编辑器和 ide 来使用黑色。

    既然黑装了,那就试一试吧!

    Black 要求你有一些代码来运行它。让我们创建一个有许多参数的简单函数,然后在该脚本上运行 Black。

    这里有一个例子:

    def long_func(x, param_one=None, param_two=[], param_three={}, param_four=None, param_five="", param_six=123456):
        print("This function has several params")
    

    现在,在您的终端中,尝试对您的代码文件运行black,如下所示:
    black long_func.py

    当您运行这个命令时,您应该看到下面的输出:
    reformatted long_func.py All done! 1 file reformatted.

    这意味着您的文件已被重新格式化,以遵循黑色标准。

    让我们打开文件,看看它是什么样子的:

    def long_func(
        param_one=None,
        param_two=[],
        param_three={},
        param_four=None,
        param_five="",
        param_six=123456,
        print("This function has several params")
    

    如您所见,Black 已将每个参数放在各自的行上。

    检查文件格式

    如果您不希望 Black 更改您的文件,但您想知道 Black 是否认为某个文件应该更改,您可以使用以下命令标志之一:

  • --check -检查文件是否应该重新格式化,但不实际修改文件
  • --diff -写出 Black 对文件的不同处理,但不修改文件
  • 我喜欢用这些来测试我的文件,看看 Black 会如何重新格式化我的代码。我没有用黑色很长时间,所以这让我看看我是否喜欢黑色将要做的事情,而不实际做任何事情。

    我喜欢黑色。我认为这真的很有用,尤其是在一个组织中实施某种 Python 风格的时候。请注意,黑色默认为 88 个字符,但您可以使用-l更改

    或者--line-length

    如果需要的话。在项目的页面上还列出了一些其他有用的选项。如果有机会,我觉得你应该给布莱克一个尝试!

  • PyLint: 分析 Python 代码
  • py flakes "Python 程序的被动检查器
  • Python 101: 第 32 集—静态代码分析
  • 使用 doctest 测试 Python 简介(视频)

    原文:https://www.blog.pythonlibrary.org/2022/04/05/intro-to-testing-python-with-doctest-video/

    这个视频教程教你使用 Python 的 doctest 模块测试代码的基本知识。

    这个视频基于我的文章用 doctest 进行 Python 测试。

    https://www.youtube.com/embed/JheIJurFvHs?feature=oembed

    想学习更多 Python?在 Leanpub、T2、Gumroad 或 T4 亚马逊网站上查看我的一些 Python 书籍。

    Python 社区正在变得有毒吗?

    原文:https://www.blog.pythonlibrary.org/2020/08/04/is-the-python-community-becoming-toxic/

    Python 社区太神奇了。我在 15 年前开始学习 Python,社区几乎总是非常支持我解决问题。然而,过去几年似乎发生了转变。我不确定这只是因为 Python 变得如此受欢迎,还是因为一些更基本的东西,比如人们对事物变得更加敏感。不管是什么,这个社区似乎正在远离它曾经的样子。

    我第一次开始思考这个问题是在 Brett Cannon 的 PyCon 主题演讲中,他讲述了他在开源社区的经历,以及我们应该如何善待彼此。太多的人认为他们在请求功能或错误修复时会很粗鲁。但他也提到,维护者也需要有良好的态度,不要赶走潜在的新贡献者。

    这个主题演讲之后的几个月,Python 语言的创始人 Guido Van Rossum 突然从 Python 负责人的位置上退了下来。当时给出的理由是围绕 PEP 572 有太多的恶语相向和争斗,以至于他提前下台了。

    今年,我们看到 PyTest 团队的许多成员退出了这个项目。另外, Python 核心开发人员之一因不同意带有政治色彩的提交消息而被禁止

    虽然 Reddit 和 StackOverflow 仍然很受欢迎,但根据我的经验,我发现很难进入它们。Reddit Python 社区虽然非常庞大和多样化,但充满了巨魔,而且版主似乎不遵守 Reddit 自己的规则。就我个人而言,仅仅在上面发布文章就有问题,而我认识的其他人则因为他们的项目被认为不够“Pythonic 化”而受到骚扰。例如,PySimpleGUI 项目在那里被反复妖魔化。

    我认为我们可以做得更好。Python 仍然是我最喜欢的语言,它的社区仍然很有趣。我认为我们应该注意我们社区发生的事情,并有意识地努力对彼此更友好。当你写错误报告或者请求一个特性的时候要小心。这些项目大多是志愿者在业余时间免费运营的。

    不过,这些项目的核心开发人员也需要善良。我记得有一次我试图报告一个 bug,收到的回复是一条非常简洁的消息,说这是重复的,或者他们已经知道了这个问题。即使有经验的开发人员也不总是知道如何搜索合适的关键字,尤其是如果他们是该软件包或技术的新用户。

    我只是想花一点时间来揭示这个话题,并鼓励我的读者在写作或说话之前思考。电话那头有一个真实的人可能今天过得很糟糕。不要让事情变得更糟。其实可以的话,做的更好!

    2012 年 1 月 Pyowa 总结

    原文:https://www.blog.pythonlibrary.org/2012/01/07/january-2012-pyowa-wrap-up/

    上周四(5 日),我参加了几年前我创建的爱荷华 Python 用户团体 Pyowa。我们请来了信安金融集团的 Scott Peterson,他和我们聊了聊图书馆小工具,这是一个基于 Django 的很酷的网站,他创建这个网站是为了跟踪他的家人在图书馆借了什么书。现在他有很多用户使用他的网站。它不仅能跟踪你借的书,还能自动续借,并让你知道你的书是否过期了。

    不过,他大部分时间都在谈论网站背后的后台内容。比如他为什么选择亚马逊网络服务,他如何使用木偶流浪者织物来管理他的服务器设置并备份它们。

    第二个演讲是我自己做的,我谈到了我的 MediaLocker 项目,这是一个开源的 wxPython 应用程序,应该可以帮助你跟踪你的媒体库。我的大部分时间都花在讲述项目背后的故事和展示演示上。然后我回答了一些问题。

    总的来说,我认为我们开了一个非常好的会议,有 10 个人出席。下个月,2 月 2 号,我们会带来大人物。我们已经安排了道格·海尔曼和 T2·史蒂夫·霍尔登通过 Skype 与我们交谈。

    Doug Hellman 是 Python Standard Library By Example 的作者,是 Racemi,Inc .的高级开发人员,也是 Python 软件基金会的交流总监。他从 Python 版本开始编程,并在地图绘制、医学出版、银行和数据中心自动化的多个平台上工作过。Hellmann 以前是 Python 杂志的专栏作家和主编,自 2007 年以来,他一直在博客上发表流行的 Python 模块

    史蒂夫·霍尔登是 Python 软件基金会主席,也是《Python Web 编程》一书的作者。他拥有 Python 咨询业务,从事 Python 培训。

    jsonpickle:将 Python pickles 变成 JSON

    原文:https://www.blog.pythonlibrary.org/2014/08/13/jsonpickle-turning-python-pickles-into-json/

    前几天,我在 StackOverflow 上看到一个有趣的问题,作者问是否有办法将 Python 字典序列化为人类可读的格式。给出的答案是使用一个名为 jsonpickle 的包,它将复杂的 Python 对象序列化到 JSON 和从 JSON 序列化。本文将向您简要介绍如何使用这个项目。

    要正确开始,您需要下载并安装 jsonpickle。通常,您可以使用 pip 来完成这项任务:

    pip install jsonpickle

    Python 2.6 或更高版本没有依赖性。对于旧版本的 Python,您需要安装一个 JSON 包,比如 simplejson 或 demjson。

    使用 jsonpickle

    让我们从创建一个简单的基于汽车的类开始。然后我们将使用 jsonpickle 序列化该类的一个实例,并对其进行反序列化。

    import jsonpickle ######################################################################## class Car(object): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" self.wheels = 4 self.doors = 5 #---------------------------------------------------------------------- def drive(self): """""" print "Driving the speed limit" if __name__ == "__main__": my_car = Car() serialized = jsonpickle.encode(my_car) print serialized my_car_obj = jsonpickle.decode(serialized) print my_car_obj.drive()

    如果您运行此代码,您应该会看到类似下面的输出:

    {"py/object": "__main__.Car", "wheels": 4, "doors": 5} Driving the speed limit

    这非常有效。序列化的对象在打印出来时非常容易阅读。重构序列化对象也非常简单。

    jsonpickle 包允许开发人员通过其 load_backendset_preferred_backend 方法选择他们想要使用的 JSON 后端来编码和解码 JSON。如果愿意,您还可以自定义序列化处理程序。总的来说,我相信对于需要能够容易地阅读他们的序列化输出的开发人员来说,这可能是一个方便的项目。

  • jsonpickle API 引用
  • 2011 年 6 月 Pyowa 总结

    原文:https://www.blog.pythonlibrary.org/2011/06/03/june-2011-pyowa-wrapup/

    昨天,也就是 6 月 2 日星期四,我们在西得梅因的 IMT 集团大楼举行了每月一次的聚会。提供茶点。有汽水和小凯撒比萨。

    我们进行了两次愉快的谈话。第一个演讲由 Scott 主讲,他谈到了使用 Python 在梁永能标签打印机上打印标签和使用 Python 在 IPP 打印的主题。梁永能打印是使用 PyWin32 库完成的。Scott 自己写了一个模块,包装了一些梁永能的 COM 对象。基本上,他可以将使用梁永能软件创建的预先创建的标签文件以及打印标签的字符串传递给他的模块。在他演讲的后半部分,他向我们讲述了他对 pkipplib 模块的使用,该模块允许他在任何使用 IPP 或 CUPS 的打印机上打印,CUPS 是 Linux 中常见的打印系统。你可以阅读模块的文档了解更多信息。从它的声音来看,你可以从任何地方通过 HTTPS 打印到打印机,假设你的防火墙和打印机配置正确。

    最后一个演讲是关于 Pisa (又名 xhtml2pdf?)马特给的。这允许开发人员通过编写 HTML 然后通过 Pisa 运行它来创建 pdf。该模块可以使用 CSS 来帮助样式的报告,它支持页眉,页脚和分页符。总的来说,它看起来很酷。

    我们的下一次 Pyowa 会议是在 2011 年 7 月 7 日。如果你想谈谈你最近用 Python 做的一些事情,只需给我发电子邮件:mike at pythonlibrary dot org 或者加入邮件列表或者留下评论。你也可以随时出来加入乐趣。我们也允许闪电对话!

    2010 年 6 月 Pyowa 总结

    原文:https://www.blog.pythonlibrary.org/2010/06/04/june-pyowa-2010-wrap-up/

    我们昨晚在爱荷华州的艾姆斯开了六月派沃会议。有九个人出席,这对我们组来说是相当大的一个人数。我想我们只在另外一个场合管理过这么多人。感谢每一个传播消息并邀请他们朋友的人。

    在会议上,我演示了一个我已经工作了大约一个月的 wxPython 音乐播放器。它使用跨平台的 mplayer 作为后端,wxPython 作为前端。现在,它允许用户将一个 MP3 文件夹加载到一个自定义列表控件(技术上是一个 ObjectListView 小部件实例)中,并通过选择一首曲目后按下播放按钮或双击曲目来逐个播放它们。该播放器还显示封面(如果有的话),有一个音量控制和播放滑块。

    在我开始演示之前,有人问我如何使用 py2exe 创建可执行文件,所以我用 GUI2Exe 做了一个即兴演示。当我试图构建 exe 时,我重新发现 py2exe 不喜欢 egg 文件,所以我必须解压缩这些文件,以便它可以找到项目所需的模块。一旦完成,程序就可以很好地编译了。

    下一次,我们将在西得梅因的 IMT 集团大楼见面。将提供比萨饼和汽水,所以饿着肚子来吧!会谈将是关于 Django,TurboGears 和(可能)SWIG。那将发生在 7 月 1 日。我希望你能成功!

    Jupyter 笔记本 101 预购

    原文:https://www.blog.pythonlibrary.org/2018/08/28/jupyter-notebook-101-pre-order/

    我最新的书,Jupyter Notebook 101 T1,现在已经可以在 T2 Leanpub 上预订了。

    这本书计划于 2018 年 11 月前完成。如果你购买这本书,你会得到 PDF,ePub 和 mobi 格式。

    以 5 美元的价格买下它,因为它是我 9 月 1 日结束的秋季销售的一部分!

    以下是您可以使用的特殊链接:

  • http://leanpub.com/jupyternotebook101/c/fall18
  • 朱庇特笔记本 101 预览章节

    原文:https://www.blog.pythonlibrary.org/2018/07/25/jupyter-notebook-101-preview-chapters/

    我目前正在写一本名为 Jupyter Notebook 101 的新书,计划在 2018 年 11 月发行。我整理了一份 PDF 文件,展示了这本书前几章的草稿以及一个附录。你可以在这里查看 PDF 文件:

  • jupyternotebook101-preview
  • 如果你想预订这本书或者只是想了解更多,你可以在 Kickstarter 上预订。

    Jupyter 笔记本 101 发布!

    原文:https://www.blog.pythonlibrary.org/2018/11/13/jupyter-notebook-101-released/

    我最新的一本书,Jupyter 笔记本 101 现在正式发行。

    您可以在以下零售商处购买:

  • 亚马逊 (Kindle 或平装)
  • Leanpub (mobi、epub 和 PDF)在以 9.99 美元的价格出售,直到 11 月底
  • Gumroad (mobi、epub 和 PDF)
  • 你也可以从 Leanpub 下载这本书的样本。在 Leanpub 上只需花 9.99 美元就能在限定时间内买到!

    Jupyter Notebook 101 将教你如何有效地创建和使用笔记本。您可以使用 Jupyter Notebook 来帮助您学习编码、创建演示文稿和制作精美的文档。

    Jupyter 笔记本被科学界用来以一种易于复制的方式展示研究。

    你将在 Jupyter 笔记本 101 中学到以下内容:

  • 如何创建和编辑笔记本
  • 如何添加样式、图像、图表等
  • 如何配置笔记本
  • 如何将您的笔记本导出为其他格式
  • 笔记本扩展
  • 使用笔记本进行演示
  • 笔记本小工具
  • 还有更多!
  • 朱庇特笔记本 101:目录

    原文:https://www.blog.pythonlibrary.org/2018/07/31/jupyter-notebook-101-table-of-contents/

    我的新书 Jupyter Notebook 101Kickstarter 活动已经进行了一半,我觉得分享我目前的暂定目录会很有趣:

  • 第 1 章:创建笔记本
  • 第 2 章:富文本(降价、图片等)
  • 第 3 章:配置笔记本电脑
  • 第 4 章:分发笔记本
  • 第 5 章:笔记本扩展
  • 第 6 章:笔记本部件
  • 第 7 章:将笔记本转换成其他格式
  • 第 8 章:用笔记本创建演示文稿
  • 附录 A:魔法命令
  • 目录的内容或顺序可能会改变。不过,我会尝试以某种形式涵盖所有这些主题。如果有时间的话,我还会研究一些其他的主题,比如对笔记本进行单元测试。我的一些支持者还要求提供跨 Python 版本管理 Jupyter、使用 Conda 和如果你可以将笔记本用作程序的章节。我也会研究这些,以确定它们是否在本书的范围内,以及我是否有时间添加它们。

    朱庇特笔记本 101:写作更新

    原文:https://www.blog.pythonlibrary.org/2018/09/18/jupyter-notebook-101-writing-update/

    我通常不会在写书的过程中在我的博客上写我的书,但我知道一些读者可能会奇怪为什么我没有像往常一样定期写博客。原因通常是因为我很喜欢为一本书写章节,如果这本书的章节不能翻译成好的博客文章,那么博客本身就不会有很多新内容。

    无论如何,正如你可能知道的,我目前正在写一本叫做 Jupyter Notebook 101 的书,我目前计划在 11 月发行。我已经完成了计划的 11 章中的 7 章,尽管我计划在完成后浏览整本书并检查错误。我希望能早点完成其他章节,这样我也可以写一些额外的章节,但是我们会看看写作进展如何。从好的方面来说,后面的章节将会成为很好的博客素材,所以你可以期待在不久的将来在这个博客上看到一些关于 Jupyter 笔记本的有趣文章。

    如果你对这本书感兴趣,你可以从 Leanpub 下载一个样本。

    Jupyter 笔记本调试

    原文:https://www.blog.pythonlibrary.org/2018/10/17/jupyter-notebook-debugging/

    调试是一个重要的概念。调试的概念是试图找出你的代码有什么问题,或者只是试图理解代码。有很多次我会遇到不熟悉的代码,我需要在调试器中一步一步地调试它,以掌握它是如何工作的。大多数 Python IDEs 都内置了很好的调试器。例如,我个人喜欢 Wing IDE。其他人喜欢 PyCharm 或 PyDev。但是如果你想调试 Jupyter 笔记本里的代码呢?这是怎么回事?

    在这一章中,我们将看看调试笔记本的几种不同的方法。第一种是通过使用 Python 自己的 pdb 模块。

    使用 pdb

    pdb 模块是 Python 的调试器模块。就像 C++有 gdb 一样,Python 有 pdb。

    让我们首先打开一个新的笔记本,添加一个包含以下代码的单元格:

    def bad_function(var): return var + 0 bad_function("Mike")

    如果您运行这段代码,您应该会得到如下所示的输出:

    --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in <module>() 2 return var + 0 ----> 4 bad_function("Mike") <ipython-input-1-2f23ed1cac1e>in bad_function(var) 1 def bad_function(var): ----> 2 return var + 0 4 bad_function("Mike") TypeError: cannot concatenate 'str' and 'int' objects

    这意味着你不能把一个字符串和一个整数连接起来。如果你不知道一个函数接受什么类型,这是一个很常见的问题。您会发现在处理复杂的函数和类时尤其如此,除非它们碰巧使用了类型提示。弄清楚发生了什么的一种方法是使用 pdb 的 set_trace() 函数添加一个断点:

    def bad_function(var): import pdb pdb.set_trace() return var + 0 bad_function("Mike")

    现在,当您运行单元时,您将在输出中得到一个提示,您可以使用该提示来检查变量并实际运行代码。如果你碰巧有 Python 3.7 ,那么你可以通过使用新的内置断点来简化上面的例子,就像这样:

    def bad_function(var): breakpoint() return var + 0 bad_function("Mike")

    这段代码在功能上等同于前面的例子,但是使用了新的断点函数。当您运行这段代码时,它的行为应该与上一节中的代码相同。

    你可以在这里阅读更多关于如何使用 pdb 的信息。

    您可以在 Jupyter 笔记本中使用任何 pdb 命令。以下是一些例子:

  • w(此处)-打印堆栈跟踪
  • d(own) -将当前帧下移 X 层。默认为 1。
  • u(p) -将当前帧上移 X 层。默认为 1。
  • b(break)-使用lineno参数,在当前文件/上下文中行号处设置一个断点
  • s(tep) -执行当前行并停在下一行
  • c(继续)-继续执行
  • 请注意,这些是单字母命令:w、d、u 和 b 是命令。您可以使用这些命令以及上面列出的文档中列出的其他命令在笔记本中交互式调试您的代码。

    IPython 还有一个名为 ipdb 的调试器。然而,它不能直接与 Jupyter 笔记本电脑一起使用。您需要使用类似 Jupyter 控制台的东西连接到内核,并从那里运行它来使用它。如果你想走这条路,你可以在这里阅读更多关于使用 Jupyter 控制台的信息。

    然而,我们可以使用一个名为IPython . core . debugger . set _ trace的 IPython 调试器。让我们用下面的代码创建一个单元格:

    from IPython.core.debugger import set_trace def bad_function(var): set_trace() return var + 0 bad_function("Mike")

    现在,您可以运行这个单元并获得 ipdb 调试器。下面是我的机器上的输出:

    IPython 调试器使用与 Python 调试器相同的命令。主要区别在于它提供了语法高亮显示,并且最初是设计用于 IPython 控制台的。

    还有另一种方法可以打开 ipdb 调试器,那就是使用 %pdb 魔法。以下是您可以在笔记本单元格中尝试的一些示例代码:

    def bad_function(var): return var + 0 bad_function("Mike")

    当您运行这段代码时,您应该会看到“typeerror”trace back,然后 ipdb 提示符会出现在输出中,您可以像以前一样使用它。

    %%debug 呢?

    还有另一种方法可以在笔记本中打开调试器。您可以使用`%%debug '来调试整个单元,如下所示:

    %%debug def bad_function(var): return var + 0 bad_function("Mike")

    这将在您运行单元时立即启动调试会话。这意味着您可能希望使用 pdb 支持的一些命令来单步执行代码,并根据需要检查函数或变量。

    请注意,如果您想调试一行代码,也可以使用“%debug”。

    在这一章中,我们学习了几种不同的方法,可以用来调试 Jupyter 笔记本中的代码。我个人更喜欢使用 Python 的 pdb 模块,但是您可以使用 IPython.core.debugger 来获得相同的功能,如果您喜欢语法突出显示,它可能会更好。

    还有一个更新的“可视化调试器”包,名为 PixieDebugger,来自于pixedust包:

    我自己没用过。一些评论家说这是惊人的,其他人说这是相当错误的。我将让您来决定是否要将它添加到您的工具集中。

    就我而言,我认为使用 pdb 或 IPython 的调试器工作得很好,应该也适合你。

  • StackOverflow: 在 IPython Noteobook 中调试的正确方法是什么?
  • 你一直想要的 Jupyter 笔记本的可视化 Python 调试器
  • 调试 Jupyter 笔记本- 大卫·哈曼
  • Jupyter 笔记本扩展基础

    原文:https://www.blog.pythonlibrary.org/2018/10/02/jupyter-notebook-extension-basics/

    有几种方法可以扩展 Jupyter 笔记本的功能。以下是其中的四个:

  • IPython 内核扩展
  • 笔记本扩展
  • 笔记本服务器扩展
  • 出于本文的目的,我将重点关注第三项,笔记本扩展。但是,让我们花一点时间来谈谈其他三个,以便您了解它们会如何影响您的笔记本电脑。

    内核基本上是运行时使用的语言。默认是通过 IPython 内核的 Python。您可以扩展您的 Jupyter 笔记本以使用除 Python 之外的其他语言。有关更多信息,请访问以下 URL:

  • https://jupyter . readthedocs . io/en/latest/projects/kernels . html
  • 由于每个内核都有不同的安装说明,所以我不会在本文中介绍其他内核的安装。应该使用上面的 URL,因为它有关于这个主题的最新信息的超链接。

    如果你愿意,你也可以实现你自己的内核。这里有一个关于这个话题的很好的入门:

  • https://jupyter-client . readthedocs . io/en/latest/kernels . html
  • IPython 内核扩展

    IPython 内核扩展只是一个 Python 模块,可用于修改交互式 shell 环境。在 Jupyter 的例子中,这些扩展将修改代码单元的行为。您可以使用这种类型的扩展来注册新的 magics、定义变量和修改用户的名称空间。您可以使用以下三个魔法来管理 IPython 扩展:

  • %加载 _ 扩展
  • %重载 _ 扩展
  • %卸载 _ 外部
  • 参见 IPython 文档了解这些魔法的全部细节。

    笔记本服务器扩展

    Jupyter 笔记本也有“服务器扩展”的概念。服务器扩展是一个 Python 模块,在笔记本的 web 服务器应用程序启动时加载。当前加载这种类型的扩展的方法是通过 Jupyter 的配置系统,我们在第 3 章中讨论过。您需要在配置文件中或通过命令行界面指定要加载的扩展。

    如果您在 Jupyter Notebook 运行时添加了新的扩展,您将需要重新启动笔记本进程来激活新的扩展。

    笔记本扩展

    本章我们最关心的扩展类型是笔记本扩展。笔记本扩展(或 nbextensions)是 JavaScript 模块,可以加载到笔记本前端的大多数视图中。他们可以访问页面的 DOM 和 Jupyter JavaScript API,后者允许扩展修改用户体验和界面。这种类型的扩展是笔记本前端独有的。

    让我们了解一下如何安装笔记本扩展。假设您已经下载/ pip 安装了包含扩展的包,那么手动安装 Jupyter 笔记本扩展的方法看起来就像这样:

    jupyter nbextension install EXTENSION jupyter nbextension enable EXTENSION

    请注意,您可以用您打算安装的扩展的名称替换扩展

    管理笔记本扩展的另一种方法是使用 Jupyter NbExtensions 配置器,这种方法似乎获得了很多支持。你可以在这里查看项目

    这个包不是 Jupyter 项目的一部分,但是它非常有帮助。您可以使用 pip 或 conda 来安装配置器。以下是使用 pip 的方法:

    pip install jupyter_nbextensions_configurator

    如果您使用 conda 作为您的 Python 包管理器,那么您将像这样安装配置器:

    conda install -c conda-forge jupyter_nbextensions_configurator

    配置器是 Jupyter 服务器扩展,必须启用。在启动 Jupyter Notebook 之前,您需要在终端中运行以下命令(或者您可以重新启动服务器):

    jupyter nbextensions_configurator enable --user

    当我运行这个命令时,我得到了以下输出:

    Enabling: jupyter_nbextensions_configurator - Writing config: /Users/michael/.jupyter - Validating... jupyter_nbextensions_configurator 0.4.0 OK Enabling notebook nbextension nbextensions_configurator/config_menu/main... Enabling tree nbextension nbextensions_configurator/tree_tab/main...

    启动 Jupyter Notebook 后,只需点击 Nbextensions 选项卡,您应该会看到如下内容:

    由于我们没有下载和安装任何扩展,配置器看起来有点贫瘠,现在真的不能为我们做那么多。让我们得到一些扩展来尝试!

    如果您要搜索 Jupyter 笔记本扩展,您会很快找到* * Jupyter _ contrib _ nb extensions * *。它是由 Jupyter 社区提供的笔记本扩展的集合。您可以通过以下任一链接了解此软件包中包含的扩展的更多信息:

  • https://github . com/ipython-contrib/jupyter _ contrib _ nb extensions
  • https://jupyter-contrib-nb extensions . readthedocs . io/en/latest/index . html
  • 要安装这套扩展,您可以再次使用 pip 或 conda。以下是您将需要的 pip 命令:

    pip install jupyter_contrib_nbextensions

    以下是 conda 命令:

    conda install -c conda-forge jupyter_contrib_nbextensions

    一旦你下载并安装了这个包,你将需要使用一个 Jupyter 来安装 javascript 和 css 文件到正确的位置,以便笔记本可以访问它们。下面是您应该运行的命令:

    jupyter contrib nbextension install --user

    现在您已经安装了新的扩展,您可以使用我们之前安装的配置器工具来轻松启用或禁用它们:

    正如你在上面的截图中看到的,现在有很多扩展可以使用。配置器对于确定您已经安装并启用了哪些扩展非常方便。您也可以分别使用 jupyter nbextension 启用扩展jupyter nbextension 禁用扩展在终端中手动启用和禁用笔记本扩展,但我个人觉得配置器更容易使用。

    在本文中,我们了解了 Jupyter 可以使用的不同类型的扩展。我们最关心的是 Jupyter 笔记本扩展。然后,我们继续学习安装扩展的基础知识。我们还学习了如何使用终端以及通过 Jupyter NbExtensions 配置器包来启用和禁用扩展。

  • 使用 Jupyter 笔记本创建演示文稿
  • Jupyter 贡献了扩展
  • Kivy 101:如何使用盒子布局

    原文:https://www.blog.pythonlibrary.org/2013/11/25/kivy-101-how-to-use-boxlayouts/

    最近我开始学习 Kivy,一个 Python 自然用户界面(NUI)工具包。据我所知,Kivy 是 pyMT 的精神继承者,你可以在这里阅读更多关于 T2 的内容。在这篇文章中,我们将学习 Kivy 如何处理布局管理。虽然您可以使用 x/y 坐标来定位小部件,但是在我使用过的每个 GUI 工具包中,使用工具包提供的某种布局管理几乎总是更好。这允许小部件在用户改变窗口大小时适当地调整大小和移动。在基维,这些东西布局。如果你用过 wxPython,它们类似于 wxPython 的 sizers。

    我还应该注意到,Kivy 可以用两种不同的方式进行布局。第一种方法是只使用 Python 代码进行布局。第二种方式是混合使用 Python 和 Kv 语言。这是为了促进模型-视图-控制器的工作方式。它看起来有点像 CSS,让我想起了 wxPython 和 XRC。我们将在本文中研究如何使用这两种方法。虽然 Kivy 支持多种类型的布局,但本文将只关注 BoxLayout 。我们将展示如何嵌套 BoxLayouts。

    Kivy, Python and BoxLayout

    使用 Python 在 Kivy 中创建一个 BoxLayout 实际上非常简单和直观。我们将从一个代码示例开始,然后按照代码进行解释。我们开始吧!

    import kivy import random from kivy.app import App from kivy.uix.button import Button from kivy.uix.boxlayout import BoxLayout red = [1,0,0,1] green = [0,1,0,1] blue = [0,0,1,1] purple = [1,0,1,1] ######################################################################## class HBoxLayoutExample(App): Horizontally oriented BoxLayout example class #---------------------------------------------------------------------- def build(self): Horizontal BoxLayout example layout = BoxLayout(padding=10) colors = [red, green, blue, purple] for i in range(5): btn = Button(text="Button #%s" % (i+1), background_color=random.choice(colors) layout.add_widget(btn) return layout ######################################################################## class VBoxLayoutExample(App): Vertical oriented BoxLayout example class #---------------------------------------------------------------------- def setOrientation(self, orient): """""" self.orient = orient #---------------------------------------------------------------------- def build(self): """""" layout = BoxLayout(padding=10, orientation=self.orient) for i in range(5): btn = Button(text="Button #%s" % (i+1) ) layout.add_widget(btn) return layout #---------------------------------------------------------------------- if __name__ == "__main__": app = HBoxLayoutExample() #app = VBoxLayoutExample() #app.setOrientation(orient="vertical") app.run()

    这里我们创建了一个垂直方向的 BoxLayout 类和一个水平方向的 BoxLayout 类。每个类包含 5 个随机背景颜色的按钮。颜色遵循 RGBA,但可以有介于 0 和 1 之间的单个值。奇怪的是,如果你使用大于 1 的数字,颜色会变得更亮。当我创建上面的截图时,我碰巧用了 255 而不是 1,所以如果你碰巧运行这段代码并看到一组更柔和的颜色,这就是原因。

    为了使例子非常简单,我们只导入 Kivy 的 App、Button 和 BoxLayout 类。BoxLayout 类接受几个参数,但我们将重点关注以下 3 个参数:方向、填充和间距。因为 BoxLayout 是 Layout 和 Widget 的子类,所以它继承了这里没有涉及的许多其他方法和关键字参数。但是回到我们目前关心的论点。填充参数告诉 Kivy 在布局和它的孩子之间应该有多少间距,而间距参数告诉它在孩子之间应该有多少间距。

    为了创建按钮,我们使用了一个简单的循环来遍历一个小范围的数字。每次迭代都会创建一个具有随机背景颜色的按钮,并将该按钮添加到布局实例中。然后我们在最后返回布局。

    VBoxLayoutExample 类中的垂直 BoxLayout 示例略有不同,因为我认为能够以编程方式设置方向会很有趣。除了我添加了一个 setOrientation 方法之外,代码基本相同。注意,如果再次调用 setOrientation,将没有任何效果。正如我的一位评论者友好地指出的那样,你需要将 orientation 绑定到 App orient 属性,或者使用 Kv 语言来实现这一点。

    如果您在脚本末尾注释掉对 HBoxLayoutExample 的调用,并取消注释掉其他两行,那么您应该会看到类似这样的结果:

    请注意,当您不设置背景颜色时,Kivy 默认为深灰色。Kivy 并不试图看起来像一个本地应用程序。这对于你来说可能是也可能不是什么大不了的事情,这取决于你想要完成什么样的项目,但是这一点应该注意。现在我们准备学习嵌套!

    嵌套框布局

    Kivy 也很容易将 BoxLayouts 嵌套在一起。每当你创建一个需要嵌套尺寸的复杂界面的应用程序时,你应该花些时间用铅笔和纸勾画出布局。然后,您可以用不同的方式在小部件周围画出方框,以帮助您可视化您需要的布局以及如何将它们嵌套在一起。我发现这对于 wxPython 很有帮助,并且我认为它适用于任何其他没有 WYSIWYG 编辑器的 GUI 工具包。顺便说一下,BoxLayouts 非常强大。如果你知道你在做什么,你就可以使用巧妙的嵌套来创建任何接口。

    说够了,我们来看一些代码!

    import kivy import random from kivy.app import App from kivy.uix.button import Button from kivy.uix.boxlayout import BoxLayout red = [1,0,0,1] green = [0,1,0,1] blue = [0,0,1,1] purple = [1,0,1,1] ######################################################################## class NestedLayoutExample(App): An example of nesting three horizontally oriented BoxLayouts inside of one vertically oriented BoxLayout #---------------------------------------------------------------------- def build(self): Horizontal BoxLayout example main_layout = BoxLayout(padding=10, orientation="vertical") colors = [red, green, blue, purple] for i in range(3): h_layout = BoxLayout(padding=10) for i in range(5): btn = Button(text="Button #%s" % (i+1), background_color=random.choice(colors) h_layout.add_widget(btn) main_layout.add_widget(h_layout) return main_layout #---------------------------------------------------------------------- if __name__ == "__main__": app = NestedLayoutExample() app.run()

    这个例子和上一个很像。不过,问题出在细节上。这里我们有一个嵌套的 for 循环,它创建了 3 个 BoxLayouts,每个 box layouts 包含 5 个按钮。然后,在外部循环的每次迭代结束时,将每个布局插入到顶级布局中。如果你错过了它,请向上滚动,看看结果如何。诀窍是创建一个顶层或主布局,并向其添加其他布局。现在让我们把注意力转向学习如何用 Kv 语言做这些事情。

    Kv+Python 和 BoxLayout

    学习一门新语言几乎总是有点痛苦。幸运的是,Kv 语言实际上非常接近 Python,包括 Python 使用缩进级别来表示一段代码何时开始和结束的要求。你可能想花几分钟在 Kivy 网站上阅读 Kv 语言。你准备好了,我们可以继续。首先,我们将从 Python 代码开始:

    # kvboxlayout.py from kivy.app import App from kivy.uix.boxlayout import BoxLayout ######################################################################## class KVMyHBoxLayout(BoxLayout): ######################################################################## class KVBoxLayoutApp(App): """""" #---------------------------------------------------------------------- def build(self): """""" return KVMyHBoxLayout() #---------------------------------------------------------------------- if __name__ == "__main__": app = KVBoxLayoutApp() app.run()

    这段代码比我们前面的例子简单得多,但也相当神秘。首先,我们创建一个 BoxLayout 的空子类。然后我们创建我们的 App 类,它有一个 build 方法,该方法只返回空的 BoxLayout 类的一个实例。这是怎么回事?我们必须查看 Kv 文件才能找到答案!

    color: .8,.9,0,1 font_size: 32 <boxlayout>: orientation: 'horizontal' MyButton: text: "Btn1" background_color: 1,0,0,1 MyButton: text: "Btn2" background_color: 0,1,0,1 MyButton: text: "Btn3" background_color: 0,0,1,1 MyButton: text: "Btn4" background_color: 1,0,1,1 MyButton: text: "Btn5" background_color: 1,0,0,1</boxlayout>

    当您保存上面的代码时,您必须将其命名为与 App 类相同的名称,但是用. kv 代替. py,并且使用小写字母。这意味着这个 Kv 文件的名称需要是 kvboxlayout.kv 。您会注意到,您还需要去掉类名的 App 部分,这样 KVBoxLayoutApp 就变成了 kvboxlayout。是的,有点混乱。如果您没有正确遵循命名约定,文件将会运行,但是您将会看到一个空白的黑色窗口。

    总之,首先在 Kv 文件中,我们有一个以<mybutton>:开头的部分。这告诉 Kivy,我们正在对 Button 类进行子类化,并将我们的子类叫做 MyButton 。然后我们缩进所需的四个空格,并设置按钮的标签颜色和字体大小。接下来,我们创建一个 BoxLayout 部分。注意,我们这次没有创建子类。然后我们告诉它应该是什么方向,并添加 5 个 MyButton 实例,每个实例都有自己的标签和颜色。

    Kivy 的一位核心开发人员指出,通过以这种方式创建 BoxLayout,我正在为所有用途重新定义 BoxLayout。这是而不是一件好事,即使它确实使例子更简单。因此,在下一个例子中,我们将停止这样做,而是用正确的方法来做!

    带 Kv 的嵌套盒布局

    在 Kv 中嵌套 BoxLayouts 一开始有点混乱,但是一旦你掌握了它,你会发现它真的很容易。我们将从 Python 代码开始,看看它是如何工作的,然后看看 Kv 代码。

    from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.widget import Widget ######################################################################## class HBoxWidget(Widget): ######################################################################## class VBoxWidget(Widget): ######################################################################## class KVNestedBoxLayoutApp(App): """""" #---------------------------------------------------------------------- def build(self): """""" return VBoxWidget() #---------------------------------------------------------------------- if __name__ == "__main__": app = KVNestedBoxLayoutApp() app.run()

    这一次,我们需要创建两个通用的小部件类:HBoxWidget 和 VBoxWidget。这些实际上是虚拟类,在 Kv 代码中变成了 BoxLayouts。说到这里,我们现在来看看。注意,您需要将 Kv 文件命名为 kvnestedboxlayout.kv ,您会注意到,它是 KVNestedBoxLayoutApp 的小写版本。

    color: .8,.9,0,1 font_size: 32 <hboxwidget>: BoxLayout: size: root.size pos: root.pos orientation: 'horizontal' MyButton: text: "Btn1" background_color: 1,1,1,1 MyButton: text: "Btn2" background_color: 0,1,0,1 MyButton: text: "Btn3" background_color: 0,0,1,1 MyButton: text: "Btn4" background_color: 1,0,1,1 MyButton: text: "Btn2" background_color: 1,0,0,1 <vboxwidget>: BoxLayout: size: root.size pos: root.pos id: foo_bar orientation: 'vertical' HBoxWidget: HBoxWidget:

    按钮代码和以前一样。接下来我们有了 HBoxWidget,我们将其定义为一个包含 5 个按钮的水平 BoxLayout。然后我们创建一个垂直 BoxLayout 的 VBoxWidget 的实例,但是这个布局包含 HBoxWidget 的两个实例。您会注意到,在 Python 代码的 build 方法中,我们返回 VBoxWidget,所以这就是操作所在。如果您删除这两个 HBoxWidget 调用,结果将是一个空的黑色窗口。

    在 Kivy 中使用 Kv 文件还有另外一种方法。它是通过 kivy.lang.Builder.load_file(或 load_string) API 实现的,这使您能够加载 Kv 文件,而无需记住以某种特殊的方式命名 Kv 文件。你可以在他们的网站上读到这个 API,并在 github 上的 Kivy 示例中看到一个应用实例。使用这种方法的唯一警告是,您需要小心不要两次加载同一个文件,否则您的 UI 可能会出错。

    这只是触及了 Kivy 布局系统的表面。还有 6 种其他布局类型可用。然而,我想你会发现本文中的例子会让你开始成功地创建你自己的酷 Kivy 应用程序。如果你需要帮助学习 Kivy,他们的网站上有一套很好的文档。他们在 freenode 上还有一个谷歌群和一个 T2 频道。

  • Kivy 的布局入门
  • Kivy 的编程指南也涵盖了布局
  • github 上一个简单的嵌套布局示例
  • Kivy 的 Kv 语言页
  • github 上的其他 Kivy 示例
  • 下载源代码

  • kivy_box_layouts.tar
  • kivy_box_layouts.zip
  • Kivy App Contest 2014

    原文:https://www.blog.pythonlibrary.org/2014/03/17/kivy-app-contest-2014/

    Kivy 是一个开源 Python 库,用于快速开发利用创新用户界面的应用程序,如多点触摸应用程序。Kivy 组织正在组织第二次应用程序开发竞赛。!这对新用户和有经验的用户来说是一个展示技能和争夺奖品的好机会。参赛作品将根据一系列标准进行评判,新的和有经验的程序员都可以使用,所以不要害怕投入进去!欲了解更多信息,请访问http://kivy.org/#contest

    了解如何使用 Python 记录日志(视频)

    原文:https://www.blog.pythonlibrary.org/2020/05/12/learn-how-to-log-with-python-video/

    在此截屏中了解如何使用 Python 的日志模块:

    https://www.youtube.com/embed/e4n8OLn_Yek?feature=oembed

    您将了解以下内容:

  • 日志记录级别
  • 日志处理程序
  • 日志格式化程序
  • 记录到多个位置
  • 还有更多!
  • 通过解决问题学习编码电子书竞赛

    原文:https://www.blog.pythonlibrary.org/2021/07/13/learn-to-code-by-solving-problems-ebook-contest/

    没有淀粉出版社与 Mouse vs Python 合作,为你带来一个电子书竞赛,题目是通过解决问题学习编码:丹尼尔·津加罗的 Python 编程初级读本

    将有 5 名获奖者。要想加入,你只需要在推特上发布这篇文章,并标记 @driscollis@nostarch

    从现在起到 2021 年 11 月 20 日午夜 CST 你将可以参加这场比赛。获胜者将在 Twitter 上宣布并贴上标签,这样他们就知道他们赢了。然后,您需要联系@driscollis 领取奖品。

    wxPython Book Kickstarter 上线不到两天

    原文:https://www.blog.pythonlibrary.org/2019/02/11/less-than-2-days-to-go-on-wxpython-book-kickstarter/

    我的新书《用 wxPython 创建 GUI 应用程序》进展顺利。我只是想让我的读者知道, Kickstarter for it 在不到两天的时间里就要结束了。

    如果你想以比今年 5 月晚些时候发布时更低的价格获得一份副本,Kickstarter 是一个不错的选择。你可以在上周的帖子中查看当前的目录。

    感谢您的支持!

    让用户更改 wx。wxPython 中 ComboBox 的内容

    原文:https://www.blog.pythonlibrary.org/2020/01/08/letting-users-change-a-wx-comboboxs-contents-in-wxpython/

    这个星期我遇到一个人,他想知道是否有一种方法允许用户编辑一个 wx 的内容。组合框。通过编辑内容,我的意思是更改 ComboBox 包含的预先存在的选项的名称,而不是向小部件添加新的项目。

    当编辑组合框中所选项的内容时,小部件不会自动保存这些编辑。因此,如果您编辑了某个内容,然后在组合框中选择了不同的选项,被编辑的内容将恢复到之前的状态,您所做的更改将会丢失。

    让我们看看如何创建一个允许这种功能的组合框!

    用 wxPython 创建 GUI 应用程序

    立即在 Leanpub亚马逊购买 |

    更改组合框

    尝试新事物的第一步是写一些代码。您需要创建一个 wx 的实例。ComboBox 并向其传递一个选择列表,同时设置默认选择。当然,您不能孤立地创建一个小部件。小部件必须在父小部件内。在 wxPython 中,您几乎总是希望父对象是一个 wx。面板位于 wx 的内部。画面

    让我们编写一些代码,看看这一切是如何安排的:

    import wx class MainPanel(wx.Panel): def __init__(self, parent): super().__init__(parent) self.cb_value = 'One' self.combo_contents = ['One', 'Two', 'Three'] self.cb = wx.ComboBox(self, choices=self.combo_contents, value=self.cb_value, size=(100, -1)) self.cb.Bind(wx.EVT_TEXT, self.on_text_change) self.cb.Bind(wx.EVT_COMBOBOX, self.on_selection) def on_text_change(self, event): current_value = self.cb.GetValue() if current_value != self.cb_value and current_value not in self.combo_contents: # Value has been edited index = self.combo_contents.index(self.cb_value) self.combo_contents.pop(index) self.combo_contents.insert(index, current_value) self.cb.SetItems(self.combo_contents) self.cb.SetValue(current_value) self.cb_value = current_value def on_selection(self, event): self.cb_value = self.cb.GetValue() class MainFrame(wx.Frame): def __init__(self): super().__init__(None, title='ComboBox Changing Demo') panel = MainPanel(self) self.Show() if __name__ == "__main__": app = wx.App(False) frame = MainFrame() app.MainLoop()

    您感兴趣的代码的主要部分在 MainPanel 类中。在这里创建小部件,设置它的选择列表和几个其他参数。接下来,您需要将 ComboBox 绑定到两个事件:

  • wx。EVT _ 文本 -用于文本改变事件
  • wx。EVT _ 组合框 -用于改变项目选择事件
  • 第一个事件, wx。EVT _ 文本,当你通过输入改变小部件中的文本时触发,当你改变选择时也触发。另一个事件仅在您更改选择时触发。 wx。EVT_TEXT 事件首先触发,因此它优先于 wx。EVT _ 组合框

    当您更改文本时, on_text_change() 被调用。在这里,您将检查 ComboBox 的当前值是否与您期望的值相匹配。您还要检查当前值是否与当前设置的选择列表相匹配。这允许您查看用户是否更改了文本。如果有,那么您需要获取选择列表中当前所选项的索引。

    然后使用列表的 pop() 方法删除旧字符串,并使用 insert() 方法添加新字符串。现在您需要调用小部件的 SetItems() 方法来更新它的选择列表。然后,将它的值设置为新的字符串,并更新 cb_value 实例变量,这样就可以检查它以后是否会再次改变。

    on_selection() 法短而甜。它所做的只是将 cb_value 更新为当前的选择。

    试试这段代码,看看它是如何工作的!

    增加了允许用户更新 wx 的能力。ComboBox 的内容并不特别难。你甚至可以子类化 wx。ComboBox 并创建一个版本,让它一直为你做这件事。另一个有趣的增强是让小部件从配置文件或 JSON 文件中加载它的选择。然后你可以更新 on_text_change() 将你的更改保存到磁盘,然后你的应用程序可以保存这些选择,并在你下次启动应用程序时重新加载它们。

    开心快乐编码!

    提升您的 Python 销售水平

    原文:https://www.blog.pythonlibrary.org/2021/12/23/level-up-your-python-sale/

    我正在进行我的 Python 书籍的销售,在这里你可以从我在 gum road 上的任何一本书上减去 10 美元。你所需要做的就是在退房时使用这个优惠代码: tenoff 。本次销售将持续到2022 年 1 月 3 日

    这段代码适用于我所有的书,包括我最新的书!

    为了让这变得更容易,下面是我已经申请了优惠券的书的链接:

  • Python 101:第二版
  • Python 201: Intermedia Python
  • Jupyter Notebook 101
  • ReportLab: PDF Processing with Python
  • Creating GUI Applications with wxPython
  • Pillow: Image Processing with Python
  • Automating Excel with Python
  • 节日快乐!

    在 Qt for Python 中加载 UI 文件

    原文:https://www.blog.pythonlibrary.org/2018/05/30/loading-ui-files-in-qt-for-python/

    Qt for Python(即 PySide2)最近发布了,这让我有兴趣尝试用它来加载 UI 文件。如果你不知道,PyQt 和 PySide / PySide2 可以使用 Qt Creator 应用程序创建使用拖放界面的用户界面。这实际上与您使用 Visual Studio 创建界面的方式非常相似。Qt 创建者/设计者将生成一个带有*的 XML 文件。然后可以在 PySide2 应用程序(或 PyQt)中加载的 ui 扩展。

    创建用户界面

    对于这个例子,我打开 Qt Creator,进入“文件”->“新建文件或项目”。然后我选择了“Qt Widgets 应用”选项。见下面截图:

    然后我打开了 Qt Creator 给我做的 mainwindow.ui 。你可以双击它或者点击程序左边的设计按钮。这里有一个截图可能会有所帮助:

    我在我的 UI 中添加了三个小部件:

  • QLabel
  • QLineEdit
  • 当我保存文件时,我在我的 UI 文件中得到以下内容:

    <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x> <y>0</y> <width>400</width> <height>300</height></rect></property> <property name="windowTitle"><string>MainWindow</string></property> <widget class="QWidget" name="centralWidget"><widget class="QPushButton" name="pushButton"><property name="geometry"><rect><x>160</x> <y>210</y> <width>80</width> <height>25</height></rect></property> <property name="text"><string>OK</string></property></widget> <widget class="QLineEdit" name="lineEdit"><property name="geometry"><rect><x>130</x> <y>30</y> <width>113</width> <height>25</height></rect></property></widget> <widget class="QLabel" name="label"><property name="geometry"><rect><x>20</x> <y>30</y> <width>111</width> <height>17</height></rect></property> <property name="text"><string>Favorite Language:</string></property></widget></widget> <widget class="QMenuBar" name="menuBar"><property name="geometry"><rect><x>0</x> <y>0</y> <width>400</width> <height>22</height></rect></property> <widget class="QMenu" name="menuTest"><property name="title"><string>Test</string></property></widget></widget> <widget class="QToolBar" name="mainToolBar"><attribute name="toolBarArea"><enum>TopToolBarArea</enum></attribute> <attribute name="toolBarBreak"><bool>false</bool></attribute></widget> <layoutdefault spacing="6" margin="11"></layoutdefault></widget>

    现在我们只需要学习如何在 Qt for Python 中加载这个文件。

    在 Qt for Python 中加载 UI 文件

    我发现有几种不同的方法可以用来在 Qt for Python (PySide2)中加载 UI 文件。第一个是从 Qt 为 Python 的 wiki 大量引用的:

    import sys from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication from PySide2.QtCore import QFile if __name__ == "__main__": app = QApplication(sys.argv) file = QFile("mainwindow.ui") file.open(QFile.ReadOnly) loader = QUiLoader() window = loader.load(file) window.show() sys.exit(app.exec_())

    虽然这可以工作,但它并没有真正向您展示如何连接事件或从用户界面中获得任何有用的东西。坦白地说,我认为这是一个愚蠢的例子。因此,我在其他网站上查找了一些其他例子,并最终将以下内容整合在一起:

    import sys from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication, QPushButton, QLineEdit from PySide2.QtCore import QFile, QObject class Form(QObject): def __init__(self, ui_file, parent=None): super(Form, self).__init__(parent) ui_file = QFile(ui_file) ui_file.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(ui_file) ui_file.close() self.line = self.window.findChild(QLineEdit, 'lineEdit') btn = self.window.findChild(QPushButton, 'pushButton') btn.clicked.connect(self.ok_handler) self.window.show() def ok_handler(self): language = 'None' if not self.line.text() else self.line.text() print('Favorite language: {}'.format(language)) if __name__ == '__main__': app = QApplication(sys.argv) form = Form('mainwindow.ui') sys.exit(app.exec_())

    在这个例子中,我们创建一个表单对象,并使用 QUiLoaderQFile 加载 UI 文件。然后我们对从 QUiLoader 返回的对象使用 findChild 方法来提取我们感兴趣的小部件对象。对于这个例子,我提取了 QLineEdit 小部件,这样我就可以得到用户输入的内容,还提取了 QPushButton 小部件,这样我就可以捕捉按钮被点击的事件。最后,我将 click 事件连接到一个事件处理程序(或插槽)。

    至此,您应该对如何使用 Qt 的 Creator / Designer 应用程序创建用户界面以及如何将它生成的 UI 文件加载到您的 Python 应用程序中有了大致的了解。这是相当直截了当的,但不是很好的记录。您也可以跳过创建 UI 文件,手动编写所有代码。不管您选择哪种方法,这似乎都是一个相当容易上手的工具包,尽管我希望文档/教程能尽快增加细节。

  • Python Ui 文件的 Qtwiki 页面
  • PySide 食谱
  • StackOverflow - 加载 QtDesigner 的。PySide 中的 ui 文件
  • PyQt4 在 Qt Designer 上的页面
  • 用 Python 锁定窗口

    原文:https://www.blog.pythonlibrary.org/2010/02/06/lock-down-windows-with-python/

    大约四年前,我的任务是将一个 Kixtart 脚本转换成 Python。这个特殊的脚本被用来锁定 Windows XP 机器,以便它们可以被用作信息亭。显然,你不需要 Python 来做这些。任何可以访问 Windows 注册表的编程语言都可以做到这一点,或者您可以只使用组策略。但是这是一个 Python 博客,所以这就是你在这篇文章中将要得到的!

    本教程需要的只是标准的 Python 发行版和 PyWin32 包。我们将使用的模块是 _winreg子进程,它们内置在标准发行版和 PyWin32 的 win32apiwin32con 中。

    我们将把代码分成两半来看。前半部分将使用 _winreg 模块:

    import subprocess, win32con from win32api import SetFileAttributes from _winreg import * # Note: 1 locks the machine, 0 opens the machine. UserPolicySetting = 1 # Connect to the correct Windows Registry key and path, then open the key reg = ConnectRegistry(None, HKEY_CURRENT_USER) regpath = r"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer" key = OpenKey(reg, regpath, 0, KEY_WRITE) # Edit registry key by adding new values (Lock-down the PC) SetValueEx(key, "NoRecentDocsMenu", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoRun", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoFavoritesMenu", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoFind", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoSetFolders", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoSetTaskbar", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoSetActiveDesktop", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoWindowsUpdate", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoSMHelp", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoCloseDragDropBands", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoActiveDesktopChanges", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoMovingBands", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoViewContextMenu", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoChangeStartMenu", 0, REG_DWORD, UserPolicySetting) SetValueEx(key, "NoTrayContextMenu", 0, REG_DWORD, UserPolicySetting) CloseKey(key)

    首先,我们导入我们需要的模块。然后,我们连接到 Windows 注册表,打开以下注册表项进行写入:

    HKEY _ 当前用户\软件\微软\ Windows \当前版本\策略\资源管理器

    警告:在继续之前,请注意,如果操作不当,篡改 Windows 注册表可能会对您的电脑造成损害。如果你不知道你在做什么,在做任何事情之前备份你的注册表或者使用一个你可以恢复的虚拟机(比如 VirtualBox 或者 VMWare)。上面的脚本将使你的电脑除了 kiosk 之外几乎不能用。

    无论如何,打开密钥后,我们设置了十几个隐藏运行选项、收藏夹、最近和开始菜单中的查找的设置。我们还禁用了桌面上的右键点击、Windows Update 以及对各种菜单的所有更改(等等)。这都是由我们的用户策略设置变量控制的。如果它被设置为 1(即布尔真),它将锁定所有这些值;如果是零,那么它会再次启用所有设置。最后,我们调用关闭键来应用设置。

    我们应该在这里停一会儿,并考虑这是一些真正丑陋的代码(正如在下面的评论中指出的)。我写这篇文章的时候,我只有一个月的编程经验,我是从一个 Kixtart 脚本移植过来的,这个脚本看起来和这篇一样差,甚至更差。让我们试着让它更干净:

    from _winreg import * UserPolicySetting = 1 # Connect to the correct Windows Registry key and path, then open the key reg = ConnectRegistry(None, HKEY_CURRENT_USER) regpath = r"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer" key = OpenKey(reg, regpath, 0, KEY_WRITE) sub_keys = ["NoRecentDocsMenu", "NoRun", "NoFavoritesMenu", "NoFind", "NoSetFolders", "NoSetTaskbar", "NoSetActiveDesktop", "NoWindowsUpdate", "NoSMHelp", "NoCloseDragDropBands", "NoActiveDesktopChanges", "NoMovingBands", "NoViewContextMenu", "NoChangeStartMenu", "NoTrayContextMenu"] # Edit registry key by adding new values (Lock-down the PC) for sub_key in sub_keys: SetValueEx(key, sub_key, 0, REG_DWORD, UserPolicySetting) CloseKey(key)

    这里的主要区别是,我将所有的 sub_key 名称放入一个 Python 列表中,然后我们可以对其进行迭代,并将每个名称设置为正确的值。现在,如果我们在这些代码行中有多处不同,比如混合了 REG_DWORD 和 REG_SZ,那么我们需要做一些不同的事情。例如,我们需要迭代元组列表,或者创建一个函数来传递信息。如果你想要最大的灵活性,你可以创建一个类,除了错误处理和键的打开和关闭之外,还能为你做这些。不过,我将把它留给读者作为练习。

    我们脚本的另一半将隐藏各种图标和文件夹:

    # Sets the "Hidden" attribute for specified files/folders. if UserPolicySetting == 1: SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Set Program Access and Defaults.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Windows Catalog.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Open Office Document.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\New Office Document.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) # NOTE: Two backslashes are required before the last directory only subprocess.Popen('attrib +h "C:\Documents and Settings\All Users\Start Menu\Programs\\vnc"') subprocess.Popen('attrib +h "C:\Documents and Settings\All Users\Start Menu\Programs\\Outlook Express"') subprocess.Popen('attrib +h "C:\Documents and Settings\All Users\Start Menu\Programs\\Java Web Start"') subprocess.Popen('attrib +h "C:\Documents and Settings\All Users\Start Menu\Programs\\Microsoft Office"') subprocess.Popen('attrib +h "C:\Documents and Settings\All Users\Start Menu\Programs\\Microsoft SQL Server"') SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Programs\Adobe Reader 6.0.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Programs\Windows Media Player.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Programs\Windows Movie Maker.lnk", win32con.FILE_ATTRIBUTE_HIDDEN) else: SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Set Program Access and Defaults.lnk", win32con.FILE_ATTRIBUTE_NORMAL) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Windows Catalog.lnk", win32con.FILE_ATTRIBUTE_NORMAL) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Open Office Document.lnk", win32con.FILE_ATTRIBUTE_NORMAL) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\New Office Document.lnk", win32con.FILE_ATTRIBUTE_NORMAL) subprocess.Popen('attrib -h "C:\Documents and Settings\All Users\Start Menu\Programs\\vnc"') subprocess.Popen('attrib -h "C:\Documents and Settings\All Users\Start Menu\Programs\\Outlook Express"') subprocess.Popen('attrib -h "C:\Documents and Settings\All Users\Start Menu\Programs\\Java Web Start"') subprocess.Popen('attrib -h "C:\Documents and Settings\All Users\Start Menu\Programs\\Microsoft Office"') subprocess.Popen('attrib -h "C:\Documents and Settings\All Users\Start Menu\Programs\\Microsoft SQL Server"') SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Programs\Adobe Reader 6.0.lnk", win32con.FILE_ATTRIBUTE_NORMAL) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Programs\Windows Media Player.lnk", win32con.FILE_ATTRIBUTE_NORMAL) SetFileAttributes("C:\Documents and Settings\All Users\Start Menu\Programs\Windows Movie Maker.lnk", win32con.FILE_ATTRIBUTE_NORMAL)

    该代码片段隐藏了以下内容

  • 通常出现在“开始”菜单中的指向 Microsoft Office 文档的各种链接
  • Windows 目录和设置程序访问和默认值快捷方式
  • “开始”菜单的“程序”子菜单中我们不希望用户访问的各种文件夹,如 VNC、Office、Microsoft SQL Connector 等。
  • 程序子菜单中的其他链接
  • 这是通过 win32api 的 SetFileAttributes 和 win32con 的快捷方式文件属性的组合来实现的。使用调用 Windows attrib 命令的子进程来切换文件夹的隐藏状态。

    不幸的是,这是另一个重复代码的例子。让我们花点时间来尝试重构它。看起来我们设置的所有内容都在“开始”菜单或它的“程序”子文件夹中。我们可以像前面的例子一样,把这些路径放入一个循环中。我们还可以使用标志来告诉我们何时隐藏或显示文件夹。我们将把整个东西放入一个函数中,这样也更容易重用。让我们看看这是什么样子:

    import os import subprocess import win32con from win32api import SetFileAttributes def toggleStartItems(flag=True): items = ["Set Program Access and Defaults.lnk", "Windows Catalog.lnk", "Open Office Document.lnk", "New Office Document.lnk", "Programs\Adobe Reader 6.0.lnk", "Programs\Windows Media Player.lnk", "Programs\Windows Movie Maker.lnk", "Programs\\vnc", "Programs\\Outlook Express", "Programs\\Java Web Start", "Programs\\Microsoft Office", "Programs\\Microsoft SQL Server"] path = r'C:\Documents and Settings\All Users\Start Menu' if flag: toggle = "+h" else: toggle = "-h" for item in items: p = os.path.join(path, item) if os.path.isdir(p): subprocess.Popen('attrib %s "%s"' % (toggle, p)) elif flag: SetFileAttributes(p, win32con.FILE_ATTRIBUTE_HIDDEN) else: SetFileAttributes(p, win32con.FILE_ATTRIBUTE_NORMAL)

    现在,看起来是不是好多了?它还使添加和删除项目变得更加容易。这使得将来的维护更简单,麻烦也更少。

    现在你知道如何用 Windows 和 Python 创建你自己的 kiosk 了。我希望这篇文章对你有所帮助。

    注意:这些脚本是在 Windows XP 上使用 Python 2.4+测试的

  • 官方 _winreg 文档
  • 【PyWin32 官方文档
  • 使用 Python 记录当前运行的进程

    原文:https://www.blog.pythonlibrary.org/2014/10/21/logging-currently-running-processes-with-python/

    我查看了我的一些旧代码,注意到这个旧脚本,其中我每 5 分钟创建一个所有运行进程的日志。我相信我最初编写代码是为了帮助我诊断正在消耗内存或占用 CPU 的流氓进程。我正在使用 psutil 项目来获取我需要的信息,所以如果你想继续,你也需要下载并安装它。

    代码如下:

    import os import psutil import time #---------------------------------------------------------------------- def create_process_logs(log_dir): Create a log of all the currently running processes if not os.path.exists(log_dir): os.mkdir(log_dir) except: separator = "-" * 80 col_format = "%7s %7s %12s %12s %30s" data_format = "%7.4f %7.2f %12s %12s %30s" while 1: procs = psutil.get_process_list() procs = sorted(procs, key=lambda proc: proc.name) log_path = os.path.join(log_dir, "procLog%i.log" % int(time.time())) f = open(log_path, 'w') f.write(separator + "\n") f.write(time.ctime() + "\n") f.write(col_format % ("%CPU", "%MEM", "VMS", "RSS", "NAME")) f.write("\n") for proc in procs: cpu_percent = proc.get_cpu_percent() mem_percent = proc.get_memory_percent() rss, vms = proc.get_memory_info() rss = str(rss) vms = str(vms) name = proc.name f.write(data_format % (cpu_percent, mem_percent, vms, rss, name)) f.write("\n\n") f.close() print "Finished log update!" time.sleep(300) print "writing new log data!" if __name__ == "__main__": log_dir = r"c:\users\USERNAME\documents" create_process_logs(log_dir)

    让我们把它分解一下。这里我们传入一个日志目录,检查它是否存在,如果不存在就创建它。接下来,我们设置几个包含日志文件格式的变量。然后我们开始一个无限循环,使用 psutil 获取所有当前正在运行的进程。我们还按名称对流程进行分类。接下来,我们打开一个唯一命名的日志文件,写出每个进程的 CPU 和内存使用情况,以及它的虚拟机、RSS 和可执行文件的名称。然后,我们关闭文件,等待 5 分钟,然后再从头开始。

    回想起来,将这些信息写入 SQLite 这样的数据库可能会更好,这样数据就可以被搜索和图形化。与此同时,希望你能在这里找到一些有用的信息,可以用于你自己的项目。

    Lucid 编程播客——撰写关于 Python 的书籍

    原文:https://www.blog.pythonlibrary.org/2019/09/04/lucid-programming-podcast-writing-books-about-python/

    我最近在 Vincent Russo 的 Lucid Programming 播客上接受了关于撰写 Python 书籍的采访。

    您可以在这里收听音频:

    https://www.youtube.com/embed/AM-1Uz6O3OM?feature=oembed

    如果你想知道更多关于我是如何写书的,你可能会喜欢我写的这篇关于这个话题的文章。我还写了一篇关于印第出版的利弊的文章。

    上周,我很荣幸参加了盈利的 Python 播客

    我参加过的其他播客:

  • 上周,我很荣幸参加了盈利的 Python 播客
  • 谈论 Python 第 156 集: Python 的历史和观点
  • 播客。init - Mike Driscoll 和他的 Python 生涯——第 169 集
  • 使用 Python Kickstarter 的机器视觉

    原文:https://www.blog.pythonlibrary.org/2015/01/28/machine-vision-with-python-kickstarter/

    昨天我发布了关于 PyImageSearch 大师计算机视觉 Kickstarter,然后我遇到了另一个半相关的 Kickstarter 。这是一个机器视觉与 Python 使用 OpenMV 凸轮。它使用 MicroPython (微控制器的 Python)来控制电路板上的摄像头。该项目可通过 I2C、串行或 SPI 协议与 Arduino、mbed 或其它微控制器配合使用。我认为树莓派属于后一种或多种类型。

    他们还没有达到目标,但是他们还有差不多一个月的时间来筹集资金。你可以在这里查看我们的项目。

    在 Python 包索引(PyPI)上发现恶意库

    原文:https://www.blog.pythonlibrary.org/2017/09/15/malicious-libraries-found-on-python-package-index-pypi/

    在 Python 包索引(PyPI)上发现了恶意代码,这是共享 Python 包的最流行的位置。这是斯洛伐克国家安全办公室报告的,然后被其他地方的哔哔声计算机接收到(即 Reddit )。攻击载体使用了域名仿冒,这基本上是有人上传了一个流行包的名称拼写错误的包,例如 lmxl 而不是 lxml

    你可以在这里看到斯洛伐克国家安全办公室的原始报告:http://www.nbu.gov.sk/skcsirt-sa-20170909-pypi/

    去年八月,我在这篇博客文章中看到了关于这个向量的讨论,很多人似乎对此并不重视。有趣的是,现在人们对这个问题越来越感兴趣。

    这也让我想起了关于一家名为 Kite 的初创公司的争议,该公司基本上将广告软件/间谍软件插入到插件中,如 Atom、autocomplete-python 等。

    用 Python 打包需要一些帮助。我喜欢现在比 10 年前好得多,但仍有许多问题。

    使用 Python 和 pyPdf 操作 Pdf

    原文:https://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/

    有一个方便的第三方模块叫做 pyPdf ,你可以用它来合并 Pdf 文档,旋转页面,分割和裁剪页面,以及解密/加密 PDF 文档。在本文中,我们将看看其中的一些函数,然后用 wxPython 创建一个简单的 GUI,它将允许我们合并几个 pdf。

    pyPdf 之旅

    要充分利用 pyPdf,您需要了解它的两个主要功能:PdfFileReader 和 PdfFileWriter。它们是我用得最多的。让我们看看他们能做些什么:

    # Merge two PDFs from pyPdf import PdfFileReader, PdfFileWriter output = PdfFileWriter() pdfOne = PdfFileReader(file( "some\path\to\a\PDf", "rb")) pdfTwo = PdfFileReader(file("some\other\path\to\a\PDf", "rb")) output.addPage(pdfOne.getPage(0)) output.addPage(pdfTwo.getPage(0)) outputStream = file(r"output.pdf", "wb") output.write(outputStream) outputStream.close()

    上面的代码将打开两个 PDF,从每一个中取出第一页,并通过合并这两页创建第三个 PDF。注意页面是从零开始的,所以零是第一页,一是第二页,以此类推。我使用这种脚本从 PDF 中提取一个或多个页面,或者将一系列 PDF 连接在一起。例如,有时我的用户会收到一堆扫描的文档,文档的每一页都以单独的 PDF 结束。他们需要将所有的单页合并成一个 PDF,pyPdf 允许我非常简单地做到这一点。

    在我的日常体验中,pyPdf 提供给我的旋转功能的应用并不多,但也许你有很多横向而不是纵向扫描文档的用户,你最终需要做很多旋转。幸运的是,这是相当无痛的:

    from pyPdf import PdfFileWriter, PdfFileReader output = PdfFileWriter() input1 = PdfFileReader(file("document1.pdf", "rb")) output.addPage(input1.getPage(1).rotateClockwise(90)) # output.addPage(input1.getPage(2).rotateCounterClockwise(90)) outputStream = file("output.pdf", "wb") output.write(outputStream) outputStream.close()

    上面的代码摘自 pyPdf 文档,在本例中被缩短了。如你所见,要调用的方法是 rotateClockwiserotateCounterClockwise 。确保将翻页的度数传递给该方法。

    现在,让我们来看看我们可以从 PDF 中获得什么信息:

    >>> from pyPdf import PdfFileReader >>> p = r'E:\My Documents\My Dropbox\ebooks\helloWorld book.pdf' >>> pdf = PdfFileReader(file(p, 'rb')) >>> pdf.documentInfo {'/CreationDate': u'D:20090323080712Z', '/Author': u'Warren Sande', '/Producer': u'Acrobat Distiller 8.0.0 (Windows)', '/Creator': u'FrameMaker 8.0', '/ModDate': u"D:20090401124817-04'00'", '/Title': u'Hello World!'} >>> pdf.getNumPages() >>> info = pdf.getDocumentInfo() >>> info.author u'Warren Sande' >>> info.creator u'FrameMaker 8.0' >>> info.producer u'Acrobat Distiller 8.0.0 (Windows)' >>> info.title u'Hello World!'

    如您所见,我们可以使用 pyPdf 收集相当多的有用数据。现在让我们创建一个简单的 GUI 来使合并两个 pdf 更加容易!

    创建 wxPython PDF 合并应用程序

    我昨天想出了这个剧本。它使用 Tim Golden 的 winshell 模块,让我在 Windows 上轻松访问用户的桌面。如果你在 Linux 或 Mac 上,那么你会想为你的平台改变这部分代码。我想使用 wxPython 的 StandardPaths 模块,但是它没有获取我可以看到的桌面的功能。总之,说够了。我们来看一些代码!

    import os import pyPdf import winshell import wx class MyFileDropTarget(wx.FileDropTarget): def __init__(self, window): wx.FileDropTarget.__init__(self) self.window = window def OnDropFiles(self, x, y, filenames): self.window.SetInsertionPointEnd() for file in filenames: self.window.WriteText(file) ######################################################################## class JoinerPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent=parent) self.currentPath = winshell.desktop() lblSize = (70,-1) pdfLblOne = wx.StaticText(self, label="PDF One:", size=lblSize) self.pdfOne = wx.TextCtrl(self) dt = MyFileDropTarget(self.pdfOne) self.pdfOne.SetDropTarget(dt) pdfOneBtn = wx.Button(self, label="Browse", name="pdfOneBtn") pdfOneBtn.Bind(wx.EVT_BUTTON, self.onBrowse) pdfLblTwo = wx.StaticText(self, label="PDF Two:", size=lblSize) self.pdfTwo = wx.TextCtrl(self) dt = MyFileDropTarget(self.pdfTwo) self.pdfTwo.SetDropTarget(dt) pdfTwoBtn = wx.Button(self, label="Browse", name="pdfTwoBtn") pdfTwoBtn.Bind(wx.EVT_BUTTON, self.onBrowse) outputLbl = wx.StaticText(self, label="Output name:", size=lblSize) self.outputPdf = wx.TextCtrl(self) widgets = [(pdfLblOne, self.pdfOne, pdfOneBtn), (pdfLblTwo, self.pdfTwo, pdfTwoBtn), (outputLbl, self.outputPdf)] joinBtn = wx.Button(self, label="Join PDFs") joinBtn.Bind(wx.EVT_BUTTON, self.onJoinPdfs) self.mainSizer = wx.BoxSizer(wx.VERTICAL) for widget in widgets: self.buildRows(widget) self.mainSizer.Add(joinBtn, 0, wx.ALL|wx.CENTER, 5) self.SetSizer(self.mainSizer) #---------------------------------------------------------------------- def buildRows(self, widgets): """""" sizer = wx.BoxSizer(wx.HORIZONTAL) for widget in widgets: if isinstance(widget, wx.StaticText): sizer.Add(widget, 0, wx.ALL|wx.CENTER, 5) elif isinstance(widget, wx.TextCtrl): sizer.Add(widget, 1, wx.ALL|wx.EXPAND, 5) else: sizer.Add(widget, 0, wx.ALL, 5) self.mainSizer.Add(sizer, 0, wx.EXPAND) #---------------------------------------------------------------------- def onBrowse(self, event): Browse for PDFs widget = event.GetEventObject() name = widget.GetName() wildcard = "PDF (*.pdf)|*.pdf" dlg = wx.FileDialog( self, message="Choose a file", defaultDir=self.currentPath, defaultFile="", wildcard=wildcard, style=wx.OPEN | wx.CHANGE_DIR if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() if name == "pdfOneBtn": self.pdfOne.SetValue(path) else: self.pdfTwo.SetValue(path) self.currentPath = os.path.dirname(path) dlg.Destroy() #---------------------------------------------------------------------- def onJoinPdfs(self, event): Join the two PDFs together and save the result to the desktop pdfOne = self.pdfOne.GetValue() pdfTwo = self.pdfTwo.GetValue() if not os.path.exists(pdfOne): msg = "The PDF at %s does not exist!" % pdfOne dlg = wx.MessageDialog(None, msg, 'Error', wx.OK|wx.ICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy() return if not os.path.exists(pdfTwo): msg = "The PDF at %s does not exist!" % pdfTwo dlg = wx.MessageDialog(None, msg, 'Error', wx.OK|wx.ICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy() return outputPath = os.path.join(winshell.desktop(), self.outputPdf.GetValue()) + ".pdf" output = pyPdf.PdfFileWriter() pdfOne = pyPdf.PdfFileReader(file(pdfOne, "rb")) for page in range(pdfOne.getNumPages()): output.addPage(pdfOne.getPage(page)) pdfTwo = pyPdf.PdfFileReader(file(pdfTwo, "rb")) for page in range(pdfTwo.getNumPages()): output.addPage(pdfTwo.getPage(page)) outputStream = file(outputPath, "wb") output.write(outputStream) outputStream.close() msg = "PDF was save to " + outputPath dlg = wx.MessageDialog(None, msg, 'PDF Created', wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() self.pdfOne.SetValue("") self.pdfTwo.SetValue("") self.outputPdf.SetValue("") ######################################################################## class JoinerFrame(wx.Frame): #---------------------------------------------------------------------- def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, "PDF Joiner", size=(550, 200)) panel = JoinerPanel(self) #---------------------------------------------------------------------- # Run the program if __name__ == "__main__": app = wx.App(False) frame = JoinerFrame() frame.Show() app.MainLoop()

    你会注意到框架和面板有愚蠢的名字。请随意更改它们。这毕竟是 Python 啊!MyFileDropTarget 类用于在前两个文本控件上启用拖放功能。如果用户愿意,他们可以将 PDF 拖到其中一个文本控件上,路径就会神奇地被插入。否则,他们可以使用浏览按钮来查找他们选择的 PDF。一旦他们选择了他们的 PDF,他们需要输入输出 PDF 的名称,这个名称在第三个文本控件中。你甚至不需要添加“.pdf”扩展名,因为这个应用程序将为您做这件事。

    最后一步是按下“加入 pdf”按钮。这会将第二个 PDF 添加到第一个 PDF 的末尾,如果创建成功,会显示一个对话框。为了正确运行,我们需要循环每个 PDF 的所有页面,并按顺序将它们添加到输出中。

    用某种拖放界面来增强这个应用程序会很有趣,用户可以看到 PDF 页面,并通过拖动它们来重新排列它们。或者只是能够从每个 PDF 文件中指定几页来添加,而不是将它们完整地连接起来。不过,我将把这些作为练习留给读者。

    我希望你觉得这篇文章很有趣,它会激发你的创造力。如果你用这些想法写了一些很酷的东西,一定要发表评论让我能看到!

    在 Windows 上映射驱动器

    原文:https://www.blog.pythonlibrary.org/2008/05/12/mapping-drives-on-windows/

    我必须帮助从 Kixtart 翻译到 Python 的第一批脚本之一是我们的地图驱动脚本。在其中,我们将根据用户所在的组和/或自定义注册表条目来映射驱动器。以下是 Kixtart 中每个类别的部分示例:

    IF READVALUE("HKEY_LOCAL_MACHINE\SOFTWARE\MyOrg", "Office")= "officeName" $Drive="g:" $Path="\\serverName\" + @userid Call "@lserver\\folderName" ENDIF

    IF in group(" Dept XYZ ")
    $ Drive = " g:" $ Path = " \ \ serverName \ "+@ userid Call " @ lserver \ \ folderName "
    ENDIF

    现在,您会注意到这个脚本正在调用另一个名为“ConnectDrive”的脚本来进行实际的映射。基本上它包含了错误处理和下面几行:

    :ConnectDrive

    使用\(Drive /DELETE 使用\)Drive $Path

    现在让我们来看看我在 Python 中用什么来代替 Kixtart 代码。首先,我们需要获得用户所在的组。您会注意到下面有两种方法可以使用 PyWin32 包的不同部分来获得我们需要的组信息。

    from win32com.client import GetObject as _GetObject user = _GetObject("WinNT://%s/%s,user" % (pdcName, userid)) fullName = user.FullName myGroups = _GetGroups(user) except: from win32net import NetUserGetGroups,NetUserGetInfo myGroups = [] groups = NetUserGetGroups(pdcName,userid) userInfo = NetUserGetInfo(pdcName,userid,2) fullName = userInfo['full_name'] for g in groups: myGroups.append(g[0]) except: fullname = "Unknown" myGroups = []

    然后我们可以进行驱动器映射。请注意,我尝试取消任何已经映射到我想要映射到的驱动器号的映射。我这样做是因为我们有用户将插入 USB 驱动器,接管我的脚本映射的驱动器。有时这行得通,有时行不通。

    import subprocess import win32wnet from win32netcon import RESOURCETYPE_DISK as DISK drive_mappings = [] if "Dept XYZ" in myGroups: drive_mappings.append(('V:', '\\\\ServerName\\folderName')) for mapping in drive_mappings: # Try to disconnect anything that was previously mapped to that drive letter win32wnet.WNetCancelConnection2(mapping[0],1,0) except Exception, err: print 'Error mapping drive!' win32wnet.WNetAddConnection2(DISK, mapping[0], mapping[1]) except Exception, err: if 'already in use' in err[2]: # change the drive letter since it's being mis-assigned subprocess.call(r'diskpart /s \\%s\path\to\log\change_g.txt' % pdcName) # try mapping again win32wnet.WNetAddConnection2(DISK, mapping[0], mapping[1])

    这就是全部了。它最终比 Kixtart 更复杂一点,但是我认为我的代码可读性更好,我不必搜索多个文件来理解它。

    matplotlib——用 Python 创建图形的介绍

    原文:https://www.blog.pythonlibrary.org/2021/09/07/matplotlib-an-intro-to-creating-graphs-with-python/

    数据可视化是与他人共享数据的一种重要方法。有些人把可视化称为绘图、图表或图形。这些名字在本文中是同义的。

    Python 有许多第三方包来实现数据可视化。事实上,有这么多,它可以有些不知所措。其中最古老也是最受欢迎的是 Matplotlib 。Matplotlib 以在 Python 中创建静态、动画和交互式可视化而闻名。

    您可以使用 Matplotlib 创建许多不同类型的绘图和图表。它还可以与其他数据科学和数学库很好地集成,如 NumPypandas 。您还会发现 Matplotlib 可以与 Python 的大多数 GUI 工具包兼容,如 Tkinter、wxPython 和 PyQt。因为 Matplotlib 如此出名,所以它将是本文所涉及的图形包。

    您将了解以下主题:

  • 用 PyPlot 创建简单的折线图
  • 创建条形图
  • 向地块添加标题
  • 显示多个图形
  • 让我们开始用 Matplotlib 绘图吧!

    安装 Matplotlib

    您需要安装 Matplotlib 才能使用它。幸运的是,使用pip很容易做到:

    python -m pip install matplotlib 
    

    这将安装 Matplotlib 以及它需要的任何依赖项。现在你已经准备好开始绘图了!

    用 PyPlot 创建简单的折线图

    创建图表(或绘图)是使用绘图包的主要目的。Matplotlib 有一个名为pyplot的子模块,您将使用它来创建一个图表。首先,创建一个名为line_plot.py的新文件,并添加以下代码:

    # line_plot.py
    import matplotlib.pyplot as plt
    def line_plot(numbers):
        plt.plot(numbers)
        plt.ylabel('Random numbers')
        plt.show()
    if __name__ == '__main__':
        numbers = [2, 4, 1, 6]
        line_plot(numbers)
    

    在这里,您将matplotlib.pyplot作为plt导入。然后创建一个line_plot(),它接受一个 Python 数字列表。要绘制数字,您可以使用plot()功能。您还可以向 y 轴添加一个标签。最后,你调用show()来显示情节。

    您现在应该会看到一个如下所示的窗口:

    现在你知道如何使用 Matplotlib 创建一个简单的折线图了!现在,您将在下一节中了解如何制作条形图。

    创建条形图

    使用 Matplotlib 创建条形图与创建折线图非常相似。只需要一些额外的参数。继续创建一个名为bar_chart.py的新文件,并在其中输入以下代码:

    # bar_chart.py
    import matplotlib.pyplot as plt
    def bar_chart(numbers, labels, pos):
        plt.bar(pos, numbers, color='blue')
        plt.xticks(ticks=pos, labels=labels)
        plt.show()
    if __name__ == '__main__':
        numbers = [2, 1, 4, 6]
        labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
        pos = list(range(4))
        bar_chart(numbers, labels, pos)
    

    当您使用bar()创建一个条形图时,您会传入一个 x 轴的值列表。然后你传入一个酒吧的高度列表。您还可以选择设置条形的颜色。在这种情况下,您将它们设置为“蓝色”。接下来,设置xticks(),它是应该出现在 x 轴上的刻度线。您还可以传入对应于刻度的标签列表。

    继续运行这段代码,您应该会看到下图:

    也可以用 Matplotlib 做一个水平条形图。你需要做的就是把bar()改成barh()。创建一个名为bar_chartsh.py的新文件,并添加以下代码:

    # bar_charth.py
    import matplotlib.pyplot as plt
    def bar_charth(numbers, labels, pos):
        plt.barh(pos, numbers, color='blue')
        plt.yticks(ticks=pos, labels=labels)
        plt.show()
    if __name__ == '__main__':
        numbers = [2, 1, 4, 6]
        labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
        pos = list(range(4))
        bar_charth(numbers, labels, pos)
    

    这里还有一个偷偷摸摸的变化。你能发现它吗?变化在于,由于现在它是一个水平条形图,您将希望设置yticks()而不是xticks(),否则它看起来不会很正确。

    一旦一切准备就绪,运行代码,您将看到以下内容:

    这看起来很棒,而且根本不需要太多代码!现在让我们看看如何用 Matplotlib 创建一个饼图。

    饼状图有点与众不同。要创建一个饼图,您将使用 Matplotlib 的subplots()函数,该函数返回一个Figure和一个Axes对象。要查看它是如何工作的,创建一个名为pie_chart_plain.py的新文件,并将以下代码放入其中:

    # pie_chart_plain.py
    import matplotlib.pyplot as plt
    def pie_chart():
        numbers = [40, 35, 15, 10]
        labels = ['Python', 'Ruby', 'C++', 'PHP']
        fig1, ax1 = plt.subplots()
        ax1.pie(numbers, labels=labels)
        plt.show()
    if __name__ == '__main__':
        pie_chart()
    

    在这段代码中,您创建了subplots(),然后使用了Axes对象的pie()方法。您像以前一样传入一个数字列表,以及一个标签列表。然后当您运行代码时,您将看到您的饼图:

    对于这么短的代码来说,这已经很不错了。但是你可以让你的饼图看起来更好。创建一个名为pie_chart_fancy.py的新文件,并添加以下代码,看看如何操作:

    # pie_chart_fancy.py
    import matplotlib.pyplot as plt
    def pie_chart():
        numbers = [40, 35, 15, 10]
        labels = ['Python', 'Ruby', 'C++', 'PHP']
        # Explode the first slice (Python)
        explode = (0.1, 0, 0, 0)
        fig1, ax1 = plt.subplots()
        ax1.pie(numbers, explode=explode, labels=labels,
                shadow=True, startangle=90,
                autopct='%1.1f%%')
        ax1.axis('equal')
        plt.show()
    if __name__ == '__main__':
        pie_chart()
    

    对于本例,您使用