原文:PythonLibrary Blog

协议:CC BY-NC-SA 4.0

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()
        try:
            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 数据库的应用程序的例子。自从我上面提到的简单编辑之后,他已经在这上面做了很多工作。我们将很快就此发布官方声明。与此同时,我希望这有助于打开你的眼界,找到一些有趣的方法来增强一个项目,并使它变得干净一点。我的计划是给这个程序增加很多新的特性,并且除了我所有的其他文章之外,在这个博客上记录这些特性。

源代码

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(
    x,
    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

如果需要的话。在项目的页面上还列出了一些其他有用的选项。如果有机会,我觉得你应该给布莱克一个尝试!


相关阅读

使用 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。如果愿意,您还可以自定义序列化处理程序。总的来说,我相信对于需要能够容易地阅读他们的序列化输出的开发人员来说,这可能是一个方便的项目。


相关阅读

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 日结束的秋季销售的一部分!

以下是您可以使用的特殊链接:

朱庇特笔记本 101 预览章节

原文:https://www.blog.pythonlibrary.org/2018/07/25/jupyter-notebook-101-preview-chapters/

我目前正在写一本名为 Jupyter Notebook 101 的新书,计划在 2018 年 11 月发行。我整理了一份 PDF 文件,展示了这本书前几章的草稿以及一个附录。你可以在这里查看 PDF 文件:

如果你想预订这本书或者只是想了解更多,你可以在 Kickstarter 上预订。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Jupyter 笔记本 101 发布!

原文:https://www.blog.pythonlibrary.org/2018/11/13/jupyter-notebook-101-released/

我最新的一本书,Jupyter 笔记本 101 现在正式发行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您可以在以下零售商处购买:

你也可以从 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
      3 
----> 4 bad_function("Mike")

 <ipython-input-1-2f23ed1cac1e>in bad_function(var)
      1 def bad_function(var):
----> 2         return var + 0
      3 
      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§ -将当前帧上移 X 层。默认为 1。
  • b(break)-使用lineno参数,在当前文件/上下文中行号处设置一个断点
  • s(tep) -执行当前行并停在下一行
  • c(继续)-继续执行

请注意,这些是单字母命令:w、d、u 和 b 是命令。您可以使用这些命令以及上面列出的文档中列出的其他命令在笔记本中交互式调试您的代码。


ipdb

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 魔法。以下是您可以在笔记本单元格中尝试的一些示例代码:


%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 的调试器工作得很好,应该也适合你。


相关阅读

Jupyter 笔记本扩展基础

原文:https://www.blog.pythonlibrary.org/2018/10/02/jupyter-notebook-extension-basics/

有几种方法可以扩展 Jupyter 笔记本的功能。以下是其中的四个:

  • 核心
  • IPython 内核扩展
  • 笔记本扩展
  • 笔记本服务器扩展

出于本文的目的,我将重点关注第三项,笔记本扩展。但是,让我们花一点时间来谈谈其他三个,以便您了解它们会如何影响您的笔记本电脑。

核心

内核基本上是运行时使用的语言。默认是通过 IPython 内核的 Python。您可以扩展您的 Jupyter 笔记本以使用除 Python 之外的其他语言。有关更多信息,请访问以下 URL:

由于每个内核都有不同的安装说明,所以我不会在本文中介绍其他内核的安装。应该使用上面的 URL,因为它有关于这个主题的最新信息的超链接。

如果你愿意,你也可以实现你自己的内核。这里有一个关于这个话题的很好的入门:

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 社区提供的笔记本扩展的集合。您可以通过以下任一链接了解此软件包中包含的扩展的更多信息:

要安装这套扩展,您可以再次使用 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 配置器包来启用和禁用扩展。


相关阅读

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):
    pass

########################################################################
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):
    pass

########################################################################
class VBoxWidget(Widget):
    pass

########################################################################
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 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 日

这段代码适用于我所有的书,包括我最新的书!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了让这变得更容易,下面是我已经申请了优惠券的书的链接:

节日快乐!

在 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
  • q 按钮

当我保存文件时,我在我的 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 锁定窗口

原文: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+测试的

延伸阅读

使用 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):
        try:
            os.mkdir(log_dir)
        except:
            pass

    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 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()
432
>>> 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 "
ELSE
ENDIF

现在,您会注意到这个脚本正在调用另一个名为“ConnectDrive”的脚本来进行实际的映射。基本上它包含了错误处理和下面几行:

:ConnectDrive

使用 D r i v e / D E L E T E 使用 Drive /DELETE 使用 Drive/DELETE使用Drive $Path

现在让我们来看看我在 Python 中用什么来代替 Kixtart 代码。首先,我们需要获得用户所在的组。您会注意到下面有两种方法可以使用 PyWin32 包的不同部分来获得我们需要的组信息。


from win32com.client import GetObject as _GetObject 

try:
    user = _GetObject("WinNT://%s/%s,user" % (pdcName, userid))
    fullName = user.FullName
    myGroups = _GetGroups(user)
except:
    try:
        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:
        # 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!'

    try:
        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()

对于本例,您使用explode参数来告诉饼图“爆炸”或从饼图中移除一个切片。在这种情况下,您删除第一个切片,它对应于“Python”。您还可以向饼图添加一个shadow。您可以通过设置startangle来告诉您的饼图逆时针旋转一定的角度。如果您想显示切片百分比,可以使用autopct,它将使用 Python 的字符串插值语法。

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这不是很棒吗?你的饼图现在看起来更加完美了!现在是时候学习如何给其他图表添加标签了!

添加标签

当您绘制数据时,您通常会想要标注轴。您可以使用xlabel()功能标记 x 轴,使用相应的ylabel()功能标记 y 轴。要了解这是如何工作的,创建一个名为bar_chart_labels.py的文件,并向其中添加以下代码:

# bar_chart_labels.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.xlabel('Vehicle Types')
    plt.ylabel('Number of Vehicles')
    plt.show()

if __name__ == '__main__':
    numbers = [2, 1, 4, 6]
    labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
    pos = list(range(4))
    bar_chart(numbers, labels, pos)

这里你同时调用了xlabel()ylabel()并将它们设置为不同的字符串。这将分别在图表的下方和左侧添加一些说明性文本。结果如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来很不错。你的图表更容易理解,但它缺少一个标题。您将在下一节学习如何做到这一点!

向地块添加标题

用 Matplotlib 给你的图表添加标题非常简单。事实上,你需要做的就是使用title()函数来添加一个。要了解如何操作,创建一个名为bar_chart_title.py的新文件,并向其中添加以下代码:

# bar_chart_title.py

import matplotlib.pyplot as plt

def bar_chart(numbers, labels, pos):
    plt.bar(pos, [4, 5, 6, 3], color='green')
    plt.bar(pos, numbers, color='blue')
    plt.xticks(ticks=pos, labels=labels)
    plt.title('Gas Used in Various Vehicles')
    plt.xlabel('Vehicle Types')
    plt.ylabel('Number of Vehicles')
    plt.show()

if __name__ == '__main__':
    numbers = [2, 1, 4, 6]
    labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
    pos = list(range(4))
    bar_chart(numbers, labels, pos)

这里的主要变化在第 9 行,在那里调用title()并传入一个字符串。默认情况下,这会设置图形的标题,并使其沿顶部居中。您可以通过将loc参数设置为“left”或“right”来稍微更改位置,但是您不能指定标题位于顶部以外的任何位置。还有一个fontdict参数,可以用来控制标题字体的外观。

您还可以向图表中添加一个新的条形图。这有助于您了解堆积条形图的外观,并为下一节做好准备。

你的图表现在看起来是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这张图看起来更好,但它仍然缺少一些东西。哦!你需要一个传奇!让我们看看下一步该怎么做。

创造传奇

向 Matplotlib 图添加图例也很简单。您将使用legend()功能添加一个。创建一个名为bar_chart_legend.py的新文件。然后,向其中添加以下代码:

# bar_chart_legend.py

import matplotlib.pyplot as plt

def bar_chart(numbers, labels, pos):
    plt.bar(pos, [4, 5, 6, 3], color='green')
    plt.bar(pos, numbers, color='blue')
    plt.xticks(ticks=pos, labels=labels)
    plt.xlabel('Vehicle Types')
    plt.ylabel('Number of Vehicles')
    plt.legend(['First Label', 'Second Label'], loc='upper left')
    plt.show()

if __name__ == '__main__':
    numbers = [2, 1, 4, 6]
    labels = ['Electric', 'Solar', 'Diesel', 'Unleaded']
    pos = list(range(4))
    bar_chart(numbers, labels, pos)

在这里,您在图表的show()前添加一个legend()。创建图例时,可以通过传入字符串列表来设置标签。列表应与图形中的地块数量相匹配。您也可以使用loc参数设置图例的位置。

当您运行这段代码时,您将看到您的图形更新成这样:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在你的图拥有了你期望在图中拥有的所有正常组件。至此,您已经看到了许多使用 Matplotlib 可以完成的任务。最后一个要学习的主题是如何用 Matplotlib 将多个图形相加。

显示多个图形

Matplotlib 允许您在显示之前创建几个图。这使您可以同时处理多个数据集。有几种不同的方法可以做到这一点。您将看到一种最简单的方法。

创建一个名为multiple_figures.py的新文件,并添加以下代码:

# multiple_figures.py

import matplotlib.pyplot as plt

def line_plot(numbers, numbers2):
    first_plot = plt.figure(1)
    plt.plot(numbers)

    second_plot = plt.figure(2)
    plt.plot(numbers2)
    plt.show()

if __name__ == '__main__':
    numbers = [2, 4, 1, 6]
    more_numbers = [5, 1, 10, 3]
    line_plot(numbers, more_numbers)

这里您创建了两个线形图。在绘图之前,您调用figure(),这将为调用它之后的绘图创建一个顶级容器。因此,第一个图被添加到图 1,第二个图被添加到图 2。当您在最后调用show()时,Matplotlib 将打开两个窗口,分别显示每个图形。

运行代码,您将在机器上看到以下两个窗口:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Matplotlib 还支持在单个窗口中添加两个或多个图。要了解这是如何工作的,创建另一个新文件,并将其命名为multiple_plots.py。为了使事情更有趣,您将在本例中使用 NumPy 来创建这两个图。

**注意:**如果您还没有安装 NumPy,那么您需要安装它来运行这个例子。

此示例基于 Matplotlib 文档中的一个示例:

# multiple_plots.py

import matplotlib.pyplot as plt
import numpy as np

def multiple_plots():
    # Some example data to display
    x = np.linspace(0, 2 * np.pi, 400)
    y = np.sin(x ** 2)

    fig, axs = plt.subplots(2)
    fig.suptitle('Vertically stacked subplots')
    axs[0].plot(x, y)
    axs[1].plot(x, -y)
    plt.show()

if __name__ == '__main__':
    multiple_plots()

这里你创建了两个独立的正弦波图。为了让它们都出现在同一个窗口中,您可以调用subplots(),这是一个方便的实用程序,可以在一次调用中创建多个图形。然后您可以使用它返回的Axes对象来绘制您用 NumPy 创建的数据。

结果看起来像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果您不想使用 NumPy,您可以绘制上一个示例中的两组数字。事实上,你应该试试。继续创建一个名为multiple_plots2.py的新文件,并添加以下代码:

# multiple_plots2.py

import matplotlib.pyplot as plt

def multiple_plots():
    numbers = [2, 4, 1, 6]
    more_numbers = [5, 1, 10, 3]
    fig, axs = plt.subplots(2)
    fig.suptitle('Vertically stacked subplots')
    axs[0].plot(numbers)
    axs[1].plot(more_numbers)
    plt.show()

if __name__ == '__main__':
    multiple_plots()

在这段代码中,您完全删除了 NumPy 代码,并添加了前面示例中的两个数字列表。然后使用Axes对象绘制它们。

这导致了以下堆积图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

至此,您应该已经很好地掌握了如何使用 Matplotlib 创建多个图形和堆叠图。

包扎

Matplotlib 是一个很棒的包,可以用来创建各种简洁的图形。令人惊讶的是,从数据中创建一个有用的绘图只需要编写几行代码。在本文中,您了解了以下主题:

  • 用 PyPlot 创建简单的折线图
  • 创建条形图
  • 创建饼图
  • 添加标签
  • 向地块添加标题
  • 创造传奇
  • 显示多个图形

Matplotlib 非常强大,有很多这里没有涉及的特性。您可以使用 Matplotlib 创建许多其他类型的可视化。有一个更新的包叫做 Seaborn ,它构建在 Matplotlib 之上,使它的图形看起来更好。还有许多其他完全独立的 Python 绘图包。您会发现 Python 支持您能想到的几乎任何类型的图,可能还有许多您不知道的图。

相关阅读

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

2010 年 5 月 Pyowa 总结

原文:https://www.blog.pythonlibrary.org/2010/05/07/may-2010-pyowa-wrap-up/

昨晚,我们举行了 2010 年 5 月的 Pyowa 会议。这是爱荷华州唯一的 Python 用户组,我们欢迎任何用 Python 编程的人(或对学习 Python 感兴趣的人)加入我们的组。在这次会议上,我们做了三个很好的报告。第一个是由吉姆,他的主题是网络抓取。他使用 Mechanizelxml 的组合来抓取埃姆斯市的网站,以便在他自己的一个网站上存档。

Mechanize 允许 Jim 模拟浏览器并浏览网站。它可以填写表格,用你提供的凭证登录,等等。然后,他使用 lxml 解析他想要的页面,如果他需要下载什么,他只需结合 wget 使用 os.system 。也提到了美汤库,但是 Jim 没有使用它。我们的另一位成员说,他们的组织确实使用了一段时间美丽的汤,并对结果感到满意。

我们接下来的两个演示是由一个叫凯文的人做的。他谈到了 Mercurial 分布式版本控制系统和 Trac ,一个基于网络的问题跟踪器。Kevin 向我们展示了如何建立一个 Mercurial 存储库,添加文件,分支,更新,合并等等。他使用 virtualenv 完成了所有这些,这是一种分离项目的简便方法。完成 Mercurial 讲座后,Kevin 向我们展示了如何使用他的 Mercurial 存储库设置 Trac、添加票证、在 Mercurial 中提交票证修复程序,以及 Trac 中包含的各种管理工具。Kevin 还强调了一些他喜欢的 Trac 和 Mercurial 插件。

如果你愿意参加我们的下一次会议,它将在同一个地点举行,6 月 3 日,也就是星期四,在爱荷华州的埃姆斯公共图书馆。如果您想分享您使用 Python 或其众多项目中的一个的经验,那将非常好!请给我发电子邮件,地址是 python library . org 的 mike,这样我们可以给你安排时间。观看我们的网站获取最新信息。

用 Union 运算符合并字典

原文:https://www.blog.pythonlibrary.org/2021/09/18/merging-dictionaries-with-the-union-operator/

作为一名开发人员,有时您可能需要将两个或更多的字典合并成一个主字典。在 Python 编程语言中,有许多不同的方式来合并字典。

在本教程中,你将看到一些合并字典的老方法,然后再看看在 Python 3.9 中添加的最新方法。

以下是您将了解的方法:

  • 使用 dict.update()
  • 与**合并
  • 用 Union 运算符合并

您将使用 update() 方法开始您的旅程!

使用 dict.update()

Python 的字典有很多不同的方法。这些方法中的一种可以用来将两个字典合并在一起。这个方法叫做 update()

这里有一个例子:

>>> first_dictionary = {"name": "Mike", "occupation": "Python Teacher"}
>>> second_dictionary = {"location": "Iowa", "hobby": "photography"}
>>> first_dictionary.update(second_dictionary)
>>> first_dictionary
{'name': 'Mike', 'occupation': 'Python Teacher', 'location': 'Iowa', 'hobby': 'photography'}

这工作完美!这个方法的唯一问题是它修改了其中一个字典。如果您想要创建第三个字典,而不修改其中一个输入字典,那么您将需要查看本文中的其他合并方法。

您现在已经准备好学习使用**!

与**合并

当你使用双星号时,它有时被称为“打开”、“展开”或“打开”字典。Python 中使用了 ****** ,函数中也使用了 kwargs

下面是如何使用**来合并两个字典:

>>> first_dictionary = {"name": "Mike", "occupation": "Python Teacher"}
>>> second_dictionary = {"location": "Iowa", "hobby": "photography"}
>>> merged_dictionary = {**first_dictionary, **second_dictionary}
>>> merged_dictionary
{'name': 'Mike', 'occupation': 'Python Teacher', 'location': 'Iowa', 'hobby': 'photography'}

这种语法看起来有点奇怪,但它非常有效!

现在,您已经准备好了解合并两个词典的最新方法了!

用 Union 运算符合并

Python 3.9 开始,可以使用 Python 的 union 操作符 | 来合并字典。你可以在 PEP 584 中了解所有的实质细节。

下面是如何使用 union 运算符合并两个字典:

>>> first_dictionary = {"name": "Mike", "occupation": "Python Teacher"} 
>>> second_dictionary = {"location": "Iowa", "hobby": "photography"}
>>> merged_dictionary = first_dictionary | second_dictionary
>>> merged_dictionary
{'name': 'Mike', 'occupation': 'Python Teacher', 'location': 'Iowa', 'hobby': 'photography'}

这是将两本词典合二为一的最短方法。

包扎

您现在知道了三种不同的方法,可以用来将多个字典合并成一个。如果你有 Python 3.9 或更高版本的权限,你应该使用 union 操作符,因为这可能是看起来最干净的合并字典的方法。然而,如果你被困在一个旧版本的 Python 上,你不必绝望,因为你现在有另外两个方法可以工作!

Logo

GitCode AI社区是一款由 GitCode 团队打造的智能助手,AI大模型社区、提供国内外头部大模型及数据集服务。

更多推荐