遵循最佳实践的代码库在当今世界受到高度重视。如果您的项目是开源的,这可能是吸引优秀开发人员的一种方式。作为开发人员,您希望编写高效且优化的代码:占用尽可能少的内存、执行速度更快、看起来干净、有适当的文档、遵循标准样式指南并且易于新开发人员理解。此处讨论的实践可能会帮助您为开源组织做出贡献、向OnlineJudges提交解决方案、使用机器学习解决大数据处理问题,或者开发您自己的项目。实践一:尽量不要让内存单独存在Python内存管理器在内部确保对这个私有堆的管理。当您创建对象时,Python虚拟机会处理所需的内存并决定将其放置在内存布局中的何处。与C/C++不同,Python解释器进行内存管理,用户无法控制它。Python中的内存管理涉及一个包含所有Python对象和数据结构的专用堆。一个简单的Python程序可能不会引起很多内存问题,但在高内存消耗的项目中,内存使用变得至关重要。从头开始开发大型项目时,明智地使用内存是明智的。但是,更好地了解事物的工作原理和不同的做事方式可以帮助您最大限度地减少程序的内存使用。?使用生成器计算大量结果生成器可以延迟计算。您可以通过遍历来使用它们:显式使用“for”或隐式地将它们传递给任何方法或构造。生成器可以返回多个项目,就像返回一个列表一样——不是一次全部返回,而是一个接一个地返回。生成器暂停,直到请求下一个项目。在此处阅读有关Python生成器的更多信息[1]。?对于大数字/数据的操作,您可以使用像Numpy这样的库来优雅地处理内存管理。?使用格式而不是“+”来生成字符串——在Python中,str是不可变的,因此每对连接都必须将左右字符串复制到新字符串中。如果连接四个长度为10的字符串,您将复制(10+10)+((10+10)+10)+(((10+10)+10)+10)=90个字符而不是40个字符。随着字符串数量和大小的增长,情况会变得更糟。Java有时会将一系列连接转换为使用StringBuilder来优化这种情况,但CPython不会。因此,建议使用.format或%语法。如果您无法在.format和%之间做出选择,请查看这个有趣的StackOverflow问题[2]。?在定义Python类时使用槽。您可以通过将类中的槽设置为固定的属性名称列表来告诉Python不要使用动态字典,只为一组固定的属性分配空间,从而消除为每个对象使用字典的开销。在此处阅读有关插槽的更多信息[3]。?您可以通过使用内置模块(如resource和objgraph)来跟踪对象级内存使用情况。?在Python中管理内存泄漏可能是一项艰巨的任务,但幸运的是有heapy等工具可用于调试内存泄漏。Heapy可以与objgraph一起使用来观察diff对象的分配随时间的增长。Heapy可以显示哪些对象占用的内存最多。Objgraph可以帮助你找到回溯引用,看看为什么它们不能被释放。您可以在此处阅读有关诊断Python内存泄漏的更多信息[4]。您可以在此处阅读Theano开发人员编写的有关Python内存管理的详细信息[5]。实践二:Python2orPython3当开始一个新的Python项目,或者刚开始学习Python时,你可能会发现自己在选择Python2还是Python3之间左右为难。这是一个广泛讨论的话题,网上有很多观点和很好的解释。一方面,Python3有一些很棒的新特性。另一方面,您可能希望使用仅支持Python2的包,而Python3不向后兼容。这意味着在Python3.x解释器上运行Python2代码可能会抛出错误。但是,可以编写在Python2和Python3解释器上运行的代码。最常见的方法是使用_future、builtins和six等包来维护一个简单、干净的Python3.x兼容代码库,以最小的开销同时支持Python2和Python3。python-future是Python2和Python3之间缺少的兼容层。它提供了未来和过去的包,可以向前或向后移植Python2和Python3功能。它还带有futurize和pasteurize,自定义2到3个基本脚本,可帮助您轻松地将Py2或Py3代码模块逐个模块转换为支持Python2和Python3的干净的Py3样式代码库。查看EdSchofield出色的Python2-3CompatibleCodeHandbook[6](翻墙)。如果你更喜欢视频而不是阅读,你可以找到他在PyConAU2014上的演讲,“Writing2/3CompliantCode[7]”(翻墙)。实践三:写出漂亮的代码分享代码是一种有益的尝试。无论动机如何,如果人们发现您的代码难以使用或理解,那么您的好意可能达不到预期。几乎每个组织都遵循开发人员必须遵循的风格指南,以实现一致性、易于调试和协作。ZenofPython就像一个迷你风格化的Python设计指南。主流的Python风格指南包括:1.PEP-8StyleGuide2.PythonIdiomsandEfficiency3.GooglePythonStyleGuide这些指南讨论了如何使用:空格,逗号和大括号,对象命名指南等。虽然它们在某些情况下,它们都有相同的目标——“干净、可读和可调试的代码标准”。坚持一个准则,或者遵循你自己的准则,但不要试图遵循与广泛接受的标准截然不同的东西。使用静态代码分析工具有许多可用的开源工具可以使您的代码符合标准风格指南和编写代码的最佳实践。Pylint是一个用于检查模块编码标准的Python工具。Pylint可以快速轻松地查看您的代码是否抓住了PEP-8的本质,因此对其他潜在用户“友好”。它还为您提供了出色的指标和统计报告,以帮助您判断代码的质量。您还可以通过创建自己的.pylintrc文件来自定义和使用。Pylint不是唯一的选择——还有其他工具,如PyChecker、PyFlakes和包,如pep8和flakes8。我的建议是使用coala,一个统一的静态代码分析框架,旨在通过单一框架提供与语言无关的代码分析。Coala支持我之前提到的所有linting工具,并且是高度可定制的。正确记录代码的这一方面对于代码库的可用性和可读性至关重要。始终建议您尽可能广泛地记录您的代码,以便其他开发人员更容易理解您的代码。函数的典型内联文档应包括:?函数的单行摘要。?提供交互式示例(如果适用)。这些可以供新开发人员参考,以快速了解功能的使用和预期的输出。您还可以使用doctest模块来确保这些示例是正确的(作为测试运行)。请参阅doctest文档中的示例。?参数文档(通常用一行描述参数及其在函数中的作用)?返回类型文档(除非您的函数什么都不返回!)Sphinx是一种广泛使用的工具,用于生成和管理项目文档。它提供了大量方便的功能,可以减少您编写标准文档的工作量。此外,您可以将文档推送到阅读文档,这是托管项目文档的最常用方式。Hitchiker'sguidetoPythonfordocumentation[8](由作者翻译成中文-PythonBestPracticeGuide[9])包含一些有趣的信息,可能对您在记录代码时有用。实践4:提高性能多处理,而不是多线程在提高多任务代码的执行时间时,您可能希望利用CPU中的多个内核同时执行多个任务。生成多个线程并让它们同时执行似乎很直观,但由于Python中的全局解释器锁,所有线程轮流在同一个内核上运行。对于Python中的实际并行化,您可能需要使用Python的多处理模块。另一种解决方案可能是将任务外包给:1.操作系统(通过多处理)2.一些调用您的Python代码的外部应用程序(例如Spark或Hadoop)3.由您的Python代码调用的代码(例如,您可以让您的Python代码调用C函数来执行昂贵的多线程操作)。除了并行性,还有其他方法可以提高性能。其中一些包括:?使用最新版本的Python:这是最直接的方法,因为新更新通常包括对现有功能的性能增强。?尽可能使用内置函数:这也符合DRY原则——内置函数经过精心设计,并由世界上一些最优秀的Python开发人员审查,因此它们通常是最好的选择。?考虑使用Ctypes:Ctypes提供了一个从Python代码调用C共享函数的接口。C是一种更接近机器级别的语言,与Python中的类似实现相比,它的代码执行速度更快。?使用Cython:Cython是Python语言的超集,它允许用户调用C函数并具有静态类型声明,从而生成更简单的最终代码,执行速度更快。?使用PyPy:PyPy是另一种具有JIT(即时)编译器的Python实现,可以使您的代码执行得更快。虽然我从未尝试过PyPy,但它也声称可以减少程序的内存消耗。像Quora这样的公司实际上在生产中使用PyPy。?设计和数据结构:提供多种语言版本。确保您为目标使用正确的数据结构,在正确的位置声明变量,明智地使用标识符范围,并在有意义的地方缓存结果等。我可以举一个具体的例子:Pythonisgenerallyslowataccessing全局变量和解析函数地址,因此将它们分配给当前范围内的局部变量然后访问它们会更快。实践5:分析代码通常,分析代码的覆盖率、质量和性能会很有帮助。Python自带cProfile模块来帮助衡量性能。它不仅给出了总运行时间,而且还单独为每个函数计时。然后它会告诉您每个函数调用的时间,这使得您可以轻松确定要优化的位置。下面是cProfile的实例分析:?memory_profiler是一个监控进程内存消耗的Python模块,可以对Python程序的内存消耗进行逐行分析。?objgraph可以显示占用Python程序内存的前N??个对象、一段时间内删除或添加的对象以及脚本中对给定对象的所有引用。?resource为程序提供了测量和控制系统资源使用的基本机制。该模块的两个主要用途包括限制资源分配和获取有关当前资源使用情况的信息。实践六:测试和持续集成测试编写单元测试是一个好习惯。如果您认为编写测试不值得付出努力,请查看这个StackOverflow问题[10]。最好在编码之前或期间编写测试。Python提供了unittest模块来编写函数和类的单元测试。还有一些框架,例如:?nose-可以用更少的样板文件运行单元测试。?pytest-还运行单元测试、更少的样板、更好的报告和许多很酷的额外功能。为了更好地比较,请阅读此处的介绍[11]。不要忘记doctest模块,它使用内联文档中的交互式示例测试源代码。MeasuringCoverage是一个用于测量Python程序代码覆盖率的工具。它监视您的程序,记录代码的哪些部分已被执行,然后分析源代码以识别可能已执行但未执行的代码。覆盖率度量通常用于衡量测试的有效性。它可以显示您的代码的哪些部分经过了测试,哪些没有。通常建议具有100%的分支覆盖率,这意味着您的测试应该能够执行并验证项目每个分支的输出。通过从一开始就为您的项目配置CI系统,持续集成对您的项目非常有用。您可以使用CI服务轻松测试代码库的各个方面。CI中的一些典型检查包括:?在真实环境中运行测试。在某些情况下,测试会在某些架构上通过而在其他架构上失败。CI服务允许您在不同的系统架构上运行测试。?对您的代码库实施覆盖约束。?构建您的代码并将其部署到生产环境(您可以在不同的平台上执行此操作)目前有一些CI服务:一些最流行的是Travis、Circle(适用于OSX和Linux)和Appveyor(适用于Windows)。根据我最初的使用情况,像SemaphoreCI这样的新兴产品似乎很可靠。Gitlab(与Github类似的另一个Git存储库管理平台)也支持CI,但与其他服务一样,您需要对其进行显式配置。
