python编程-从入门到实践,python从入门到项目实践pdf

  python编程:从入门到实践,python从入门到项目实践pdf

  Yyds干货库存

  教程最糟糕的部分总是它们的简单,不是吗?你很少会发现一个文件有多个文件,也很少会发现一个文件有多个目录。

  我发现构建Python项目是语言教学中最被忽视的部分之一。更糟糕的是,许多开发人员会犯错误,并在一堆常见错误中磕磕绊绊,直到他们找到至少可以工作的东西。

  好消息是:你不必成为他们中的一员!

  在超简单Python教程系列的这一部分中,我们将探索import语句、模块、包,以及如何毫不费力地将所有东西组合在一起。我们甚至会谈到VCS、PEP和Python的禅宗。系好安全带!

  在我们深入研究实际的项目结构之前,让我们首先了解它是如何集成到我们的版本控制系统[VCS] …从你需要VCS这个事实开始!有几个原因。

  跟踪您所做的每个更改,找出您何时更改了错误的代码,能够查看旧版本的代码,备份您的代码,并与其他人协作。你有很多选择。Git是最明显的,尤其是当你不知道还可以用什么的时候。您可以在GitHub、GitLab、Bitbucket或Gitote等平台上免费托管您的Git存储库。如果你想要Git之外的东西,还有很多其他的选择,包括Mercurial,Bazaar,Subversion(虽然如果你用了最后一个,可能会被同行认为是原始人。)

  在本指南的其余部分,我将假设您使用Git,因为这是我的专有用法。

  创建存储库并将本地副本克隆到您的计算机后,您就可以开始设置项目了。至少,您需要创建以下内容:

  README.md:对项目及其目标的描述。LICENSE.md:你的项目的许可,如果它是开源的。Gitignore:一个特殊的文件,它告诉git要忽略哪些文件和目录。(如果您使用的是另一个VCS,此文件会有不同的名称。)目录和项目名称。没错.我们的Python代码文件实际上属于一个单独的子目录!这是非常重要的,因为我们的库的根目录将会堆满构建文件、包脚本、虚拟环境和所有其他实际上不属于源代码的东西。

  举个例子,我们称我们虚构的项目为awesomething。

  PEP 8和命名Python style主要由一组名为Python Enhancement Proposals的文档管理,缩写为PEP。当然,并不是所有的pep实际上都被采纳了,这就是为什么他们被称为“提案”。可以在Python官网浏览主要的PEP索引。这个指数官方称为PEP 0。

  目前,我们主要关注PEP 8,它是由Python语言的创造者吉多范罗苏姆于2001年首次编写的。该文档正式概述了所有Python开发人员通常应该遵循的编码风格。以此为准!学习它,遵循它,并鼓励其他人也这样做。

  (旁注:人教版8指出,风格规律总有例外。它是指南,而不是命令。)

  现在,我们主要关注标题为“包和模块名”的部分.

  该模块应该有一个全小写的短名称。为了提高可读性,可以在模块名中使用下划线。Python包也应该有全小写的短名称,尽管不鼓励使用下划线。

  我们将在后面学习模块和包的确切含义,但是现在,请知道模块是用文件名命名的,而包是用它们的目录名命名的。

  换句话说,文件名应该全部小写。如果这样可以提高可读性,请使用下划线。同样,目录名也应该全部小写,如果可以避免,也不会加下划线。换句话说.

  正确:awesome thing/data/load _ settings . py错误:awesome thing/data/load settings . py虽然命名确实冗长,但这是PEP的规范,可以让你的代码更加规范。

  软件包和模块它会让人觉得虎头蛇尾,但这些承诺的定义如下:

  任何Python(。py)文件就是一个模块,一个目录下的一堆模块就是一个包。

  你必须对目录做另一件事,使它成为一个包,也就是把调用的文件粘贴到里面__init__.py,你实际上不必在那个文件里放任何东西,但它必须在那里。

  也可以用其他很酷的东西__init__。py,但这超出了本指南的范围。

  如果你确实忘记了__init__。py你的包,它会做一些比fail更奇怪的事情,因为它使它成为一个隐式命名空间包。你可以用这种特殊类型的包做一些漂亮的事情,但我不会在这里讨论它。像往常一样,你可以通过阅读官方文件了解更多信息。

  所以,如果我们看看我们的项目结构,awesomething实际上是一个包,它可以包含其他包。因此,我们可以调用awesomething,我们的顶层包,以及它的子包下的所有包。一旦我们开始进口,这将是非常重要的。

  来看看我的项目界面截图,省略,看看我们是怎么构建的。

  省略-git

  许可证. md

  省略

   app.py

   常见

   classproperty.py

   常数. py

   游戏_enums.py

   __init__。巴拉圭

   数据

   数据加载器. py

   游戏_回合_设置. py

   __init__。巴拉圭

   记分牌. py

   设置. py

   游戏

   内容_loader.py

   游戏_item.py

   游戏_回合. py

   __init__。巴拉圭

   timer.py

   __init__。巴拉圭

   __main__。巴拉圭

   资源

   测试

   __init__。巴拉圭

   测试_游戏_项目. py

   测试_游戏_回合_设置. py

   测试_记分牌. py

   测试_设置. py

   测试_test.py

   测试_timer.py

  皮林特里克

  自述. md

   .被增加

  你会看到我有一个名为Missession的顶层包,它包含四个子包:common、data、game和tests。我也有目录资源,但是只包含游戏音频,图片等。(为简洁起见,此处省略)。Resources不是包,因为它不包含__init__.py。

  我的顶层包中还有一个特殊的文件:__main__.py,这是我们直接通过执行我们的顶层包时运行的文件python -m省略。我们将讨论__main__的内容。py以后。

  import如何工作如果您以前编写过任何有意义的Python代码,那么您几乎肯定熟悉import语句。例如.

  进口re

  知道当我们导入一个模块时,我们实际上正在运行它是很有帮助的。这意味着导入模块中的任何语句也在运行。

  例如,re.py它有几个自己的导入语句。我们说导入re,并不是说它们可以用于我们从re导入的文件,而是说这些文件必须存在。如果(出于某种不太可能的原因)enum.py在您的环境中被删除,并且您运行import re,它将失败并出现错误。

  回溯(最近一次呼叫):

  文件怪异. py ,第1行,在

  进口re

  文件 re.py ,第122行,在

  导入枚举

  ModuleNotFoundError:没有名为“enum”的模块

  看到这里,你可能会有点困惑。有人问我为什么找不到外部模块(本例中为re)。有些人还想知道为什么要导入内部模块(这里是enum),因为他们在代码中并不直接需要它。答案很简单:我们导入了re,re导入了enum。

  当然,上面的场景是虚构的:正常情况下,import re永远不会失败,因为这两个模块都是Python核心库的一部分。

  导入的方式其实有很多,但是大部分应该很少用,如果有的话。

  对于下面的所有示例,我们将假设我们有一个名为smart_door.py的文件:

  # smart_door.py

  定义关闭():

  print( ahhhhhhhhhhhhhh。)

  def open():

  print(谢谢你让一个简单的门变得很快乐。)

  例如,我们将使用smart_door.py在Python交互式shell中运行本节的其余代码。

  如果我们想运行这个函数open(),我们必须首先导入模块smart_door。最简单的方法是.

  导入smart_door

  smart_door.open()

  智能门关闭()

  我们实际上会说这个smart_door是和的命名空间。Python开发者真的很喜欢名称空间,因为他们让函数和这样的源码一目了然。打开()关闭()

  (顺便说一下,不要将名称空间与隐式名称空间包混淆。它们是两码事。)

  Zen Python,又称PEP 20,定义了Python语言的原理。最后一行有一句话解决了这个问题:

  名称空间是一个非常棒的想法——让我们多做一些吧!

  然而,在某些时候,名称空间可能会变得很麻烦,尤其是对于嵌套包。Foo.bar.baz.whatever.doThing()就是丑。幸运的是,我们有办法避免每次调用函数时都使用名称空间。

  如果我们希望能够使用这个open()函数,而不必总是以它的模块名作为前缀,我们可以这样做。

  从smart_door导入打开

  打开()

  但请注意,在最后一种情况下,两个close () smart_door.close()都不行,因为我们没有直接导入函数。要使用它,我们必须将代码改为.

  从smart_door导入打开、关闭

  打开()

  关闭()

  在之前那个可怕的嵌套包噩梦中,我们现在可以说from foo . bar . baz . whatever import doThing,然后直接使用doThing()。或者,如果我们想要一个小的名称空间,我们可以说from foo.bar.baz import whatever,然后说whatever.doThing()。

  这个进口系统非常灵活。

  然而,过不了多久,你可能会发现有人说,“但是我的模块里有上百个函数,我想把它们都用上!”这也是很多开发者偏离轨道的地方。通过这样来做.

  从smart_door导入*

  这是非常非常糟糕的!简单来说,直接导入模块里的所有东西都是一个问题。想象一下下面的代码。

  从smart_door导入*

  来自gzip导入*

  打开()

  你认为会发生什么?答案是gzip.open()将是被调用的函数,因为这个open()是我们代码中导入和定义的最后一个版本。Smart_door.open()已经被覆盖了——我们不能调用它open(),也就是说我们实际上根本不能调用它。

  当然,由于我们通常不知道,或者至少不记得每个导入模块中的每个函数、类和变量,所以我们很容易陷入很多困惑。

  Zen Python解决了这种情况。

  显性比隐性好。

  你永远不必猜测函数或变量的来源。文件中的某个地方应该有明确告诉我们它来自哪里的代码。前两个场景证明了这一点。

  我还要提一下,早期的foo.bar.baz.whatever.doThing()场景是Python开发者不喜欢看到的。同样来自Python的Zen.

  直接比嵌套好。

  嵌套一些袋子是可以的,但是当你的项目开始看起来像一套精心制作的俄罗斯娃娃时,你就做错了。将你的模块组织成包,但是要保持简单。

  将我们之前创建的项目文件结构导入到您的项目中会很方便。回想一下我的省略项目。

  省略-git

  许可证. md

  省略

   app.py

   常见

   classproperty.py

   常数. py

   游戏_enums.py

   __init__。巴拉圭

   数据

   数据加载器. py

   游戏_回合_设置. py

   __init__。巴拉圭

   记分牌. py

   设置. py

   游戏

   内容_loader.py

   游戏_item.py

   游戏_回合. py

   __init__。巴拉圭

   timer.py

   __init__。巴拉圭

   __main__。巴拉圭

   资源

   测试

   __init__。巴拉圭

   测试_游戏_项目. py

   测试_游戏_回合_设置. py

   测试_记分牌. py

   测试_设置. py

   测试_test.py

   测试_timer.py

  皮林特里克

  自述. md

   .被增加

  在我的game_round_settings,error/data/game _ round _ settings . py定义的模块中,我想使用我的GameMode类。这个类是在misinformation/common/game _ enums . py中定义的,怎么走?

  这实际上非常容易,因为我将Missession定义为一个包,并将我的模块组织到子包中。在game_round_settings.py

  from employment . common . game _ enum导入游戏模式

  这叫绝对进口。它从顶层包开始,然后向下到公共包,在那里寻找game_enums.py .

  有开发者拿着common.game _ enums导入游戏模式的类似导入语句来找我,想知道为什么不行。简单来说,数据包(game_round_settings.py所在的位置)不知道它的兄弟包。

  但是,它知道它的父节点。正因为如此,Python有一个叫相对导入的东西,它允许我们做同样的事情。

  从.common.game _ enums导入游戏模式

  意思是“这个的直接父包.包”,在这种情况下,这是误传。因此,导入返回一级,进入common,并找到game_enums.py

  关于是用绝对导入还是相对导入,有很多争论。就我个人而言,我更喜欢尽可能使用绝对导入,因为它使代码更具可读性。但是,你可以自己决定。唯一重要的部分是结果很明显。——任何东西的来源都不应该是神秘的。

  这里还有一个潜伏的陷阱!在misision/data/settings.py,我有这一行:

  从省略. data.game_round_settings导入GameRoundSettings

  当然,由于两个模块在同一个包中,我们应该可以说从game _ round _ settings导入gameround设置,对吗?

  这是不对的!它实际上无法找到game _ round _ settings.py。这是因为我们正在运行顶级包省略,这意味着搜索路径(Python在哪里寻找模块,以及以什么顺序)的工作方式不同。

  但是,我们可以使用相对导入:

  从。游戏回合设置导入游戏回合设置

  在这种情况下,单身。意思是“这个包裹”。

  如果您熟悉经典的Linux文件系统,那么这应该开始有意义了。意思是“更上一层楼”。表示“当前位置”。当然,Python走得更远:意思是“最后两层”,就是“后三关”,以此类推。

  然而,请记住,这些“级别”不仅仅是简单的目录,它们就在这里。它们是包裹。如果你有两个不同的包在一个不是包的普通目录中,你不能使用相对导入从一个跳到另一个。为此,您必须使用Python来搜索路径,这超出了本指南的范围。

  __main__。还记得我提到的那个主要问题吗?py在我们的顶包中创造了一个?这是一个特殊的文件,当我们在Python中直接运行这个包时,它将被执行。我的Missession包可以从我的存储库的根目录运行Python-m Missession。

  这是文件的内容:

  从省略导入应用程序

  if __name__==__main__ :

  app.run()

  对,其实就是它!我正在从顶层包中导入我的模块省略。

  记住,我也可以说from.importapp .或者,如果我只是想说run()而不是app.run(),我可以做from mission . app import run或者from.app import run。最后,只要代码可读,我如何导入它没有太大的技术差异。

  (PS:我们可以讨论app.py为我的主run()函数单独设置是否符合逻辑,但我有我的理由.它们超出了本指南的范围。)

  最开始让大多数人困惑的是整个if __name__==__main__ 语句。Python没有大量必须广泛使用的样板3354代码。它几乎不需要修改3354,但这是那些罕见的部分之一。

  __name__是每个Python模块的特殊字符串属性。如果我将这一行print(__name__)放在misinformation/data/settings . py的顶部,当模块被导入(并因此运行)时,我们会看到打印出“省略. data.settings”。

  当一个模块直接通过运行时python -m some_module时,该模块被赋予一个特殊值_ _ name _ _:“main”。

  因此,如果_ _ name _ _= _ _ main _ _ :实际上是检查模块是否作为主模块执行。如果是,在该条件下运行代码。

  你可以从另一个角度来看这个问题。App.py如果我将以下内容添加到.

  if __name__==__main__ :

  运行()

  然后我可以直接执行模块python-m misinformation.app,结果和python-m misinformation一样。现在__main__。py完全忽略,misinformation/app.py的__name__是 __main__。py。

  同样,如果我只是运行Python-m Missession,app.py会忽略特殊代码,因为它的__name__现在是省略. app

  总结让我们回顾一下:

  每个项目都应该使用VCS,比如Git。有很多选择可以选择。每个Python代码文件(。py)是一个模块。将模块分组到包中。每个包必须包含一个特殊的__init__。py文件。您的项目通常应该由顶层包组成,通常包含子包。这个顶层包通常与您的项目共享名称,并作为目录存在于项目存储库的根目录中。不要在import语句中使用它。在你接受一个可能的例外之前,Python的Zen指出“其他情况不足以违反这个规则”。使用绝对或相对导入来引用项目中的其他模块。可执行项目在顶层包__main__.py中应该有一个,然后,可以直接使用python -m myproject。当然,在构建Python项目时,我们可以使用更高级的概念和技术,但我们不会在这里讨论它们。

  原创作品来自程,

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: