当前位置: 首页 > 科技观察

腾讯8年Python开发经验的程序员写给初学者的总结,希望有用

时间:2023-03-21 00:52:37 科技观察

在刚开始学习Python的时候,有一些事情我希望早点知道。我花了很多时间来学习这些东西。我想将所有这些要点整理成一篇文章。本文的目标读者是刚开始学习Python语言并希望跳过前几个月使用他们已经使用的类似工具学习Python的有经验的程序员。关于包管理和标准工具的部分也对初学者有帮助。我的经验主要基于Python2.7,但大多数工具都适用于任何版本。如果你从未使用过Python,我强烈建议你阅读Python介绍,因为你需要了解基本的语法和类型。包管理Python世界的一大优点是大量的第三方包。此外,管理这些包非常容易。按照惯例,项目所需的包都列在requirements.txt文件中。每个包一行,通常包括版本号。这是一个例子,这个博客使用Pelican:;html-script:false]pelican==3.3Markdownpelican-extended-sitemap==1.0.0Python包的一个缺陷是它们默认安装在全局范围内。我们将使用一个工具,让我们的每个项目都有一个独立的环境,这个工具叫做virtualenv。我们还需要安装一个更高级的包管理工具pip,它可以与virtualenv一起工作。首先,我们需要安装pip。大多数python安装器都内置了easy_install(python默认的包管理工具),所以我们使用easy_installpip来安装pip。这应该是您最后一次使用easy_install。如果您没有安装easy_install,它似乎可以从linux系统上的python-setuptools包中获得。如果您使用的是Python3.3或更高版本,那么Virtualenv已经是标准库的一部分,因此无需安装它。接下来,您要安装virtualenv和virtualenvwrapper。Virtualenv使您能够为每个项目创建一个隔离的环境。当您的不同项目使用不同版本的包时,这尤其有用。Virtualenv包装器提供了一些不错的脚本来使事情变得更容易。Shell;html-script:false]sudopipinstallvirtualenvwrapper安装virtualenvwrapper时,它会将virtualenv列为依赖包,因此会自动安装。打开一个新的shell并键入mkvirtualenvtest。如果你打开另一个shell,你不在这个virtualenv中,你可以通过workontest来启动它。工作完成后,您可以使用deactivate来停用。IPythonIPython是标准Python交互式编程环境的替代品,支持自动完成、快速访问文档以及许多其他标准交互式编程环境应具备的功能。当你在虚拟环境中时,你可以简单地使用pipinstallipython来安装它,并在命令行中使用ipython来启动它。另一个不错的功能是“笔记本”,它需要额外的组件。安装完成后就可以使用ipythonnotebook了,会出现一个漂亮的webUI,可以在这里创建notebook。这在科学计算中很流行。对于测试,我建议使用nose或py.test。我大部分时间都用鼻子。他们基本上是相似的。我将解释鼻子的一些细节。这是一个使用鼻子进行测试的可笑的人为示例。以test_开头的文件中所有以test_开头的函数都会被调用:Python;html-script:false]deftest_equality():assertTrue==False正如预期的那样,当运行nose时,我们的测试没有通过。Shell;html-script:false](test)jhaddad@jons-mac-pro~VIRTUAL_ENV/src$nosetestsF==========================================================================失败:test_nose_example.test_equality-----------------------------------------------------------------追溯(mostrecentcallast):文件“/Users/jhaddad/.virtualenvs/test/lib/python2.7/site-packages/nose/case.py",line197,inrunTestself.test(*self.arg)File"/Users/jhaddad/.virtualenvs/test/src/test_nose_example.py",line3,intest_equalityassertTrue==FalseAssertionError------------------------------------------------------------------nose.tools还有一些方便的方法可以调用。Python;html-script:false]fromnose.toolsimportassert_truedeftest_equality():assert_true(False)如果你想使用更像JUnit的方法,也可以:Python;html-script:false]fromnose.toolsimportassert_truefromunittestimportTestCaseclassExampleTest(TestCase):defsetUp(self):#setUp&tearDownarebothavailableself.blah=Falsedefest_blah(self):self.assertTrue(self.blah)开始测试:Shell;html-script:false](test)jhaddad@jons-mac-pro~VIRTUAL_ENV/src$nosetestsF========================================================================失败:test_blah(test_nose_example.ExampleTest)------------------------------------------------------------------------回溯(mostrecentcallast):文件“/Users/jhaddad/.virtualenvs/test/src/test_nose_example.py”,第11行,intest_blahself.assertTrue(self.blah)AssertionError:Falseisnottrue--------------------------------------------------------------------Ran1testin0.003sFAILED(failures=1)优秀的Mock库包含在Python3中,但是如果你你正在使用Python2,你可以使用pypi来获取它。这个测试会进行远程调用,但是这个调用会耗时10s。这个例子显然是人为设计的。我们使用模拟来返回示例数据,而不是实际进行调用。Python;html-script:false]importmockfrommockimportpatchfromtimeimportsleepclassSweetness(object):defslow_remote_call(self):sleep(10)return"some_data"#letspretendwegetthisbackfromourremoteapicalldeftest_long_call():s=Sweetness()result==some.slow_remote_call()assert_call()当然,我们的测试需要很长时间。Shell;html-script:false](test)jhaddad@jons-mac-pro~VIRTUAL_ENV/src$noseteststest_mock.pyRan1testin10.001sOK太慢了!所以我们问自己,我们在测试什么?我们需要测试远程调用是否有效,或者我们是在测试拿到数据后要做什么?多半是后者。让我们摆脱这个愚蠢的远程调用:Python;html-script:false]importmockfrommockimportpatchfromtimeimportsleepclassSweetness(object):defslow_remote_call(self):sleep(10)return"some_data"#letspretendwegetthisbackfromourremoteapicalldeftest_long_call():s=Sweetness。s,"slow_remote_call",return_value="some_data"):result=s.slow_remote_call()assertresult="some_data"那我们再试一次:Shell;html-script:false](test)jhaddad@jons-mac-pro~VIRTUAL_ENV/src$noseteststest_mock.py.-------------------------------------------------------------------Ran1testin0.001sOK好多了。请记住,这个例子被简化得可笑。就个人而言,我只忽略来自远程系统的调用,而不是我的数据库调用。nose-progressive是一个很棒的模块,它可以改进nose的输出,以便在错误发生时显示错误,而不是等到***。如果您的测试需要一定的时间,这是一件好事。pipinstallnose-progressive并添加--with-progressive到你的nosetests调试iPDB是一个很好的工具,我发现了很多令人难以置信的错误。pipinstallipdb安装工具,然后importipdb;ipdb.set_trace()在你的代码中,你会在程序运行时得到一个很好的交互式提示。它一次一行地执行程序并检查变量。Python有一个很好的内置跟踪模块,可以帮助我弄清楚发生了什么。这里是一个无用的python程序:Python;html-script:false]a=1b=2a=b这里是这个程序的跟踪结果:Shell;html-script:false](test)jhaddad@jons-mac-pro~VIRTUAL_ENV/src$python-mtrace--tracetracing.py1?---modulename:tracing,funcname:tracing.py(1):a=1tracing.py(2):b=2tracing.py(3):a=b---modulename:trace,funcname:_unsettracetrace.py(80):sys.settrace(None)这个函数在你想搞清楚其他程序的内部结构时非常有用。如果您以前使用过strace,它们的工作原理非常相似。有几次,我使用pycallgraph来追踪性能问题。它可以创建函数调用时间和次数的图表。***,objgraph对于查找内存泄漏非常有用。这是一篇关于如何使用它来查找内存泄漏的好文章。GeventGevent是一个很好的库,它封装了Greenlets,让Python具备了异步调用的功能。是的,很好。我最喜欢的函数是Pool,它抽象了异步调用部分,为我们提供了一种简单的使用方式,一个异步map()函数:Python;html-script:false]fromgeventimportmonkeymonkey.patch_all()fromtimeimportsleep,timedeffetch_url(url):print"Fetching%s"%urlsleep(10)print"Donefetching%s"%urlfromgevent.poolimportPoolurls=["http://test.com","http://bacon.com","http://eggs.com"]p=Pool(10)start=time()p.map(fetch_url,urls)printtime()-start非常重要的是要注意这段代码最上面geventmonkey上的补丁,如果没有的话,它无法正常工作。如果我们连续3次让Python调用fetch_url,我们通常预计该过程需要30秒。使用gevent:Python;html-script:false](test)jhaddad@jons-mac-pro~VIRTUAL_ENV/src$python.pyFetchinghttp://test.comFetchinghttp://bacon.comFetchinghttp://eggs.comDonefetchinghttp://test.comDonefetchinghttp://bacon.comDonefetchinghttp://eggs.com10.001791954如果您有大量数据库调用或从远程URL获取数据,这将很有用。我不是回调的忠实粉丝,所以这种抽象对我来说效果很好。结论好吧,如果您在这里,您很可能学到了一些新东西。在过去的一年里,这些工具对我产生了巨大的影响。查找和输入它们花了一些时间,因此希望本文能减少其他人使用该语言的工作量。