http 192.168.1.1'

章039 挑战(求推荐)-武侠之父-http://www.zilang.net
选择字号:
选择背景颜色:
章039 挑战(求推荐)
本章节来自于
http://www.zilang.net/172/172357/
快速找到本站请搜索:&【】国学大师的话,算是为这场辩论大浪潮暂时画上了一个休止符。&&&&其实大家冷静下来后,稍微品咂品咂,也会觉得其实“武侠”两个字更加朗朗上口,更能代表一种文化精神,比“侠客”显然要高明不少。&&&&所以很快的,网络上余留下来的那几小股仍在负隅顽抗的“侠客顽固势力”也被湮灭在了广大武侠拥趸的碾压声中。&&&&而在《萍踪侠影录》12月异军突起、狂暴肆虐勇夺全国畅销书月排行榜冠军,1月又诱发全民疯狂讨论大浪潮的前前后后,甚至连“侠客”这个说法最终都被“武侠”取代了……作为最直接也是最大的利益受害者——侠客领军人物合琴生,却自始至终都没有出来发过一句言。&&&&没有说过《萍踪侠影录》一句不是,也没有上蹿下跳,批驳“武侠”支持“侠客”……&&&&邓铮自然不会天真的以为对方是艺德无双、虚怀如谷,已拜倒在《萍踪侠影录》的浩瀚精彩之下。&&&&有句话说得好,挡人财路,犹如杀人父母!更何况,他眼下这还不仅仅是挡人财路,这是连别人的以前走的路都给挖成坑了!试想,连侠客这种称呼都没了,你还领军人物,领个毛的军啊?!&&&&因此对于合琴生以及另外几位侠客名家的离奇箴默,邓铮心里隐隐总有些不踏实。&&&&不过他也没多放在心上,因为农历新年马上就要到了,这对于他来说,显然是个更值得头疼的大问题。&&&&回家过年?虽然对于这个世界的父亲邓海在情感上是很认同的,但终究……唉,想想都头疼啊!&&&&不过幸好他需要等着谈薇训练结束,接她一起回去。距离组合出道就只剩下半年时间了,谈薇她们的训练很紧,春节期间也就只放了七天的假,所以邓铮在学校放假后,就一直在租住的小屋里待着,需要等到农历二十八,谈薇她们才能休息。&&&&今年冬日,比往年要冷了不少。&&&&进入1月,全国很多地方都下起了鹅毛大雪,一片银装素裹。&&&&天虽冷,雪虽大,却一diǎn也挡不住《萍踪侠影录》的持续火爆。&&&&1月15日,农历小年,《萍踪侠影录》再传捷报,自12月5日上市以来,短短一个多月时间里,便以第一册发行41天累计35.8万、第二册发行12天累计14.3万的成绩,悍然突破50万册大关。&&&&因为这个世界华语文化地位较高,所以虽然跟前世地球上一样采用的是农历、公历双纪年法,但在国内传统节日,以及涉及文化、娱乐等重要公共事务方面,统一采用的都是老祖宗的农历纪年法。&&&&因此,《萍踪侠影录》凭借这个优异成绩,算是搭上了年度评选的末班车,以累计破50万册的成绩成为本年度第十四本“比较畅销书”。&&&&比较畅销书的门槛是自然年累计销售50万册,下一步是超级畅销书,门槛是自然年累计销售100万册。&&&&《萍踪侠影录》只用了一个多月,便踏入了比较畅销书的门槛,而这本书还有后三册尚未发行,因此出版界对于它明年荣升超级畅销书毫不怀疑,大家比较好奇的是,它能在明年那张只有差不多半页纸的超级畅销书榜单上排到第几?&&&&这件事,还有两个非常有意思的diǎn:&&&&这次《萍踪侠影录》成为本年度第十四本比较畅销书,排在它前边第十三的那本,正是游子寒的《冰风筝》!&&&&最拉仇恨值的是,最终被它踩着尸体爬上去的,正是合琴生的那本《喋血金钱镖》!&&&&《喋血金钱镖》9月发行,火了两个多月,然后一路攀爬着,眼看好不容易来到了45万的关口,冲击“比较畅销书”有望。&&&&好家伙,《萍踪侠影录》简体横空出世,人比人得死,货比货得扔啊,眼看着《萍踪侠影录》一路绝尘,水准低了三个档次的《喋血金钱镖》只有跟在后面干吃灰的份,结果最近这一个多月,累计也就挣扎着卖了三万来册,最近一周,更是悲怆地停滞在了48.2万这个销量上完全不动了!&&&&眼看距离年终还有七天,冲击年度第十五本“比较畅销书”是没多大指望了!&&&&腊月二十四,一直沉默的合琴生终于露面了,并高调接受了企鹅文学、性浪娱乐、《南国都市报》等几家权威媒体杂志的专访,瞬间便弄出了不小的声势来。&&&&记者:“请问您对武侠取代侠客一事,怎么看待?”&&&&合琴生:“注意用词。这不是取代,而是换个定义,我个人很赞同司马大师的说法,实际上我先前已经关于‘武侠’的这个概念,跟侠客协会内部的一些人有过交流,只是还未正式达成共识、形成有效提案……”&&&&记者:“您的意思是,其实‘武侠’的概念,原本是您最先提出的,金梁先生只不过是恰好抢了先?”&&&&合琴生:“呵呵,话倒也不能这么说。实际上呢,早在《萍踪侠影录》出现前两年,我本人就已经在构思一部恢弘巨著了。正是因为这本书构架太过庞大,涉及的史料、典故、民俗太多,而且还需要在此基础上重塑新的世界观,跟之前简单的侠客完全不同,所以我便想到了要用另外更富文化内涵的词汇来定义这类,于是乎,便想到了‘武侠’这两个字,后来发生的事嘛,呵呵呵……”&&&&记者:“方不方便透露这部巨著的一些信息,目前写作进展?”&&&&合琴生:“背景设在元末明初,目标字数超过80万。目前已经完成约五分之一的稿件,年后会选择一家有诚意的报纸连载。”&&&&记者:“80万字?《萍踪侠影录》的将近两倍。而且选择的也是报纸先连载。我可不可以这样认为,大师您这是在向如今公认的‘武侠第一人’金梁先生挑战?”&&&&合琴生:“注意用词。有一个事实你要先弄清楚,无论以前的侠客,还是重新定义后的武侠,我本人才是当之无愧的领军人物!绝不是一本半本书走了狗屎运的别的什么人!当然,一切还是要以绝对实力说话,你要真想把这看做挑战的话,也可以,如果有人敢应战,那我不妨就顺带教教他,谁才是真正的武侠扛鼎人物!”&位你提供最新最快最全的免费小说更新&【】
(紫琅文学http://www.zilang.net)
(快捷键:←) &&
(快捷键:→)
仅代表作家本人的观点,不代表网站立场,内容如果含有不健康和低俗信息,请联系我们进行删除处理!
,,,,,内容来源于互联网或由网友上传。版权归作者都市言情所有。如果您发现有任何侵犯您版权的情况,请联系我们,我们将支付稿酬或者删除。谢谢!热门搜索:
Copyright & 173. All rights reserved.当前访客身份:游客 [
当前位置:
Python 程序员必知必会的开发者工具
Python已经演化出了一个广泛的生态系统,该生态系统能够让Python程序员的生活变得更加简单,减少他们重复造轮的工作。同样的理念也适用于工具开发者的工作,即便他们开发出的工具并没有出现在最终的程序中。本文将介绍Python程序员必知必会的开发者工具。对于开发者来说,最实用的帮助莫过于帮助他们编写代码文档了。模块可以根据源代码中的docstrings为任何可导入模块生成格式良好的文档。Python包含了两个测试框架来自动测试代码以及验证代码的正确性:1)模块,该模块可以从源代码或独立文件的例子中抽取出测试用例。2)模块,该模块是一个全功能的自动化测试框架,该框架提供了对测试准备(test fixtures), 预定义测试集(predefined test suite)以及测试发现(test discovery)的支持。模块可以监控Python执行程序的方式,同时生成一个报表来显示程序的每一行执行的次数。这些信息可以用来发现未被自动化测试集所覆盖的程序执行路径,也可以用来研究程序调用图,进而发现模块之间的依赖关系。编写并执行测试可以发现绝大多数程序中的问题,Python使得debug工作变得更加简单,这是因为在大部分情况下,Python都能够将未被处理的错误打印到控制台中,我们称这些错误信息为traceback。如果程序不是在文本控制台中运行的,traceback也能够将错误信息输出到日志文件或是消息对话框中。当标准的traceback无法提供足够的信息时,可以使用cgitb 模块来查看各级栈和源代码上下文中的详细信息,比如局部变量。模块还能够将这些跟踪信息以HTML的形式输出,用来报告web应用中的错误。一旦发现了问题出在哪里后,就需要使用到交互式调试器进入到代码中进行调试工作了,模块能够很好地胜任这项工作。该模块可以显示出程序在错误产生时的执行路径,同时可以动态地调整对象和代码进行调试。当程序通过测试并调试后,下一步就是要将注意力放到性能上了。开发者可以使用以及模块来测试程序的速度,找出程序中到底是哪里很慢,进而对这部分代码独立出来进行调优的工作。Python程序是通过解释器执行的,解释器的输入是原有程序的字节码编译版本。这个字节码编译版本可以在程序执行时动态地生成,也可以在程序打包的时候就生成。模块可以处理程序打包的事宜,它暴露出了打包相关的接口,该接口能够被安装程序和打包工具用来生成包含模块字节码的文件。同时,在开发环境中,compileall模块也可以用来验证源文件是否包含了语法错误。在源代码级别,模块提供了一个类查看器,方便文本编辑器或是其他程序对Python程序中有意思的字符进行扫描,比如函数或者是类。在提供了类查看器以后,就无需引入代码,这样就避免了潜在的副作用影响。文档字符串与doctest模块如果函数,类或者是模块的第一行是一个字符串,那么这个字符串就是一个文档字符串。可以认为包含文档字符串是一个良好的编程习惯,这是因为这些字符串可以给Python程序开发工具提供一些信息。比如,help()命令能够检测文档字符串,Python相关的IDE也能够进行检测文档字符串的工作。由于程序员倾向于在交互式shell中查看文档字符串,所以最好将这些字符串写的简短一些。例如#&mult.py
class&Test:
&&&&&&&&a=Test(5)
&&&&&&&&a.multiply_by_2()
&&&&def&__init__(self,&number):
&&&&&&&&self._number=number
&&&&def&multiply_by_2(self):
&&&&&&&&return&self._number*2在编写文档时,一个常见的问题就是如何保持文档和实际代码的同步。例如,程序员也许会修改函数的实现,但是却忘记了更新文档。针对这个问题,我们可以使用doctest模块。doctest模块收集文档字符串,并对它们进行扫描,然后将它们作为测试进行执行。为了使用doctest模块,我们通常会新建一个用于测试的独立的模块。例如,如果前面的例子Test class包含在文件mult.py中,那么,你应该新建一个testmult.py文件用来测试,如下所示:#&testmult.py
import&mult,&doctest
doctest.testmod(mult,&verbose=True)
#&&&&&a=Test(5)
#&Expecting&nothing
#&&&&&a.multiply_by_2()
#&Expecting:
#&3&items&had&no&tests:
#&&&&&mult
#&&&&&mult.Test.__init__
#&&&&&mult.Test.multiply_by_2
#&1&items&passed&all&tests:
#&&&&2&tests&in&mult.Test
#&2&tests&in&4&items.
#&2&passed&and&0&failed.
#&Test&passed.在这段代码中,doctest.testmod(module)会执行特定模块的测试,并且返回测试失败的个数以及测试的总数目。如果所有的测试都通过了,那么不会产生任何输出。否则的话,你将会看到一个失败报告,用来显示期望值和实际值之间的差别。如果你想看到测试的详细输出,你可以使用testmod(module, verbose=True).如果不想新建一个单独的测试文件的话,那么另一种选择就是在文件末尾包含相应的测试代码:if&__name__&==&'__main__':
&&&&import&doctest
&&&&doctest.testmod()如果想执行这类测试的话,我们可以通过-m选项调用doctest模块。通常来讲,当执行测试的时候没有任何的输出。如果想查看详细信息的话,可以加上-v选项。$&python&-m&doctest&-v&mult.py单元测试与unittest模块如果想更加彻底地对程序进行测试,我们可以使用unittest模块。通过单元测试,开发者可以为构成程序的每一个元素(例如,独立的函数,方法,类以及模块)编写一系列独立的测试用例。当测试更大的程序时,这些测试就可以作为基石来验证程序的正确性。当我们的程序变得越来越大的时候,对不同构件的单元测试就可以组合起来成为更大的测试框架以及测试工具。这能够极大地简化软件测试的工作,为找到并解决软件问题提供了便利。#&splitter.py
import&unittest
def&split(line,&types=None,&delimiter=None):
&&&&&&&Splits&a&line&of&text&and&optionally&performs&type&conversion.
&&&&fields&=&line.split(delimiter)
&&&&if&types:
&&&&&&&&fields&=&[&ty(val)&for&ty,val&in&zip(types,fields)&]
&&&&return&fields
class&TestSplitFunction(unittest.TestCase):
&&&&def&setUp(self):
&&&&&&&&#&Perform&set&up&actions&(if&any)
&&&&&&&&pass
&&&&def&tearDown(self):
&&&&&&&&#&Perform&clean-up&actions&(if&any)
&&&&&&&&pass
&&&&def&testsimplestring(self):
&&&&&&&&r&=&split('GOOG&100&490.50')
&&&&&&&&self.assertEqual(r,['GOOG','100','490.50'])
&&&&def&testtypeconvert(self):
&&&&&&&&r&=&split('GOOG&100&490.50',[str,&int,&float])
&&&&&&&&self.assertEqual(r,['GOOG',&100,&490.5])
&&&&def&testdelimiter(self):
&&&&&&&&r&=&split('GOOG,100,490.50',delimiter=',')
&&&&&&&&self.assertEqual(r,['GOOG','100','490.50'])
#&Run&the&unittests
if&__name__&==&'__main__':
&&&&unittest.main()
#----------------------------------------------------------------------
#Ran&3&tests&in&0.001s
#OK在使用单元测试时,我们需要定义一个继承自unittest.TestCase的类。在这个类里面,每一个测试都以方法的形式进行定义,并都以test打头进行命名——例如,’testsimplestring‘,’testtypeconvert‘以及类似的命名方式(有必要强调一下,只要方法名以test打头,那么无论怎么命名都是可以的)。在每个测试中,断言可以用来对不同的条件进行检查。实际的例子:假如你在程序里有一个方法,这个方法的输出指向标准输出(sys.stdout)。这通常意味着是往屏幕上输出文本信息。如果你想对你的代码进行测试来证明这一点,只要给出相应的输入,那么对应的输出就会被显示出来。#&url.py
def&urlprint(protocol,&host,&domain):
&&&&url&=&'{}://{}.{}'.format(protocol,&host,&domain)
&&&&print(url)内置的print函数在默认情况下会往sys.stdout发送输出。为了测试输出已经实际到达,你可以使用一个替身对象对其进行模拟,并且对程序的期望值进行断言。unittest.mock模块中的patch()方法可以只在运行测试的上下文中才替换对象,在测试完成后就立刻返回对象原始的状态。下面是urlprint()方法的测试代码:#urltest.py
from&io&import&StringIO
from&unittest&import&TestCase
from&unittest.mock&import&patch
import&url
class&TestURLPrint(TestCase):
&&&&def&test_url_gets_to_stdout(self):
&&&&&&&&protocol&=&'http'
&&&&&&&&host&=&'www'
&&&&&&&&domain&=&&#'
&&&&&&&&expected_url&=&'{}://{}.{}\n'.format(protocol,&host,&domain)
&&&&&&&&with&patch('sys.stdout',&new=StringIO())&as&fake_out:
&&&&&&&&&&&&url.urlprint(protocol,&host,&domain)
&&&&&&&&&&&&self.assertEqual(fake_out.getvalue(),&expected_url)urlprint()函数有三个参数,测试代码首先给每个参数赋了一个假值。变量expected_url包含了期望的输出字符串。为了能够执行测试,我们使用了unittest.mock.patch()方法作为上下文管理器,把标准输出sys.stdout替换为了StringIO对象,这样发送的标准输出的内容就会被StringIO对象所接收。变量fake_out就是在这一过程中所创建出的模拟对象,该对象能够在with所处的代码块中所使用,来进行一系列的测试检查。当with语句完成时,patch方法能够将所有的东西都复原到测试执行之前的状态,就好像测试没有执行一样,而这无需任何额外的工作。但对于某些Python的C扩展来讲,这个例子却显得毫无意义,这是因为这些C扩展程序绕过了sys.stdout的设置,直接将输出发送到了标准输出上。这个例子仅适用于纯Python代码的程序(如果你想捕获到类似C扩展的输入输出,那么你可以通过打开一个临时文件然后将标准输出重定向到该文件的技巧来进行实现)。Python调试器与pdb模块Python在pdb模块中包含了一个简单的基于命令行的调试器。pdb模块支持事后调试(post-mortem debugging),栈帧探查(inspection of stack frames),断点(breakpoints),单步调试(single-stepping of source lines)以及代码审查(code evaluation)。有都能够在程序中调用调试器,或是在交互式的Python终端中进行调试工作。在所有启动调试器的函数中,函数set_trace()也许是最简易实用的了。如果在复杂程序中发现了问题,可以在代码中插入set_trace()函数,并运行程序。当执行到set_trace()函数时,这就会暂停程序的执行并直接跳转到调试器中,这时候你就可以大展手脚开始检查运行时环境了。当退出调试器时,调试器会自动恢复程序的执行。假设你的程序有问题,你想找到一个简单的方法来对它进行调试。如果你的程序崩溃时报了一个异常错误,那么你可以用python3 -i someprogram.py这个命令来运行你的程序,这能够很好地发现问题所在。-i选项表明只要程序终结就立即启动一个交互式shell。在这个交互式shell中,你就可以很好地探查到底发生了什么导致程序的错误。例如,如果你有以下代码:def&function(n):
&&&&return&n&+&10
function(&Hello&)如果使用python3 -i 命令运行程序就会产生如下输出:python3&-i&sample.py
Traceback&(most&recent&call&last):
&&File&&sample.py&,&line&4,&in&&module&
&&&&function(&Hello&)
&&File&&sample.py&,&line&2,&in&function
&&&&return&n&+&10
TypeError:&Can't&convert&'int'&object&to&str&implicitly
&&&&function(20)
&&&如果你没有发现什么明显的错误,那么你可以进一步地启动Python调试器。例如:&&&&import&pdb
&&&&pdb.pm()
&&sample.py(4)func()
-&&return&n&+&10
sample.py(6)&module&()
-&&func('Hello')
&&sample.py(4)func()
-&&return&n&+&10
(Pdb)&print&n
'Hello'
&&&如果你的代码身处的环境很难启动一个交互式shell的话(比如在服务器环境下),你可以增加错误处理的代码,并自己输出跟踪信息。例如:import&traceback
import&sys
&&&&func(arg)
&&&&print('****&AN&ERROR&OCCURRED&****')
&&&&traceback.print_exc(file=sys.stderr)如果你的程序并没有崩溃,而是说程序的行为与你的预期表现的不一致,那么你可以尝试在一些可能出错的地方加入print()函数。如果你打算采用这种方案的话,那么还有些相关的技巧值得探究。首先,函数traceback.print_stack()能够在被执行时立即打印出程序中栈的跟踪信息。例如:&&&&def&sample(n):
...&&&&&if&n&&&0:
...&&&&&&&&&sample(n-1)
...&&&&&else:
...&&&&&&&&&traceback.print_stack(file=sys.stderr)
&&&&sample(5)
File&&&stdin&&,&line&1,&in&&module&
File&&&stdin&&,&line&3,&in&sample
File&&&stdin&&,&line&3,&in&sample
File&&&stdin&&,&line&3,&in&sample
File&&&stdin&&,&line&3,&in&sample
File&&&stdin&&,&line&3,&in&sample
File&&&stdin&&,&line&5,&in&sample
&&&另外,你可以在程序中任意一处使用pdb.set_trace()手动地启动调试器,就像这样:import&pdb
def&func(arg):
&&&&pdb.set_trace()
&&&&...在深入解析大型程序的时候,这是一个非常实用的技巧,这样操作能够清楚地了解程序的控制流或是函数的参数。比如,一旦调试器启动了之后,你就可以使用print或者w命令来查看变量,来了解栈的跟踪信息。在进行软件调试时,千万不要让事情变得很复杂。有时候仅仅需要知道程序的跟踪信息就能够解决大部分的简单错误(比如,实际的错误总是显示在跟踪信息的最后一行)。在实际的开发过程中,将print()函数插入到代码中也能够很方便地显示调试信息(只需要记得在调试完以后将print语句删除掉就行了)。调试器的通用用法是在崩溃的函数中探查变量的值,知道如何在程序崩溃以后再进入到调试器中就显得非常实用。在程序的控制流不是那么清楚的情况下,你可以插入pdb.set_trace()语句来理清复杂程序的思路。本质上,程序会一直执行直到遇到set_trace()调用,之后程序就会立刻跳转进入到调试器中。在调试器里,你就可以进行更多的尝试。如果你正在使用Python的IDE,那么IDE通常会提供基于pdb的调试接口,你可以查阅IDE的相关文档来获取更多的信息。下面是一些Python调试器入门的资源列表:阅读Steve Ferb的文章 观看Eric Holscher的截图 阅读Ayman Hourieh的文章 阅读 阅读Karen Tracey的一书中的第九章——When You Don’t Even Know What to Log: Using Debuggers程序分析profile模块和cProfile模块可以用来分析程序。它们的工作原理都一样,唯一的区别是,cProfile模块是以C扩展的方式实现的,如此一来运行的速度也快了很多,也显得比较流行。这两个模块都可以用来收集覆盖信息(比如,有多少函数被执行了),也能够收集性能数据。对一个程序进行分析的最简单的方法就是运行这个命令:%&python&-m&cProfile&someprogram.py此外,也可以使用profile模块中的run函数:run(command&[,&filename])该函数会使用exec语句执行command中的内容。filename是可选的文件保存名,如果没有filename的话,该命令的输出会直接发送到标准输出上。下面是分析器执行完成时的输出报告:126&function&calls&(6&primitive&calls)&in&5.130&CPU&seconds
Ordered&by:&standard&name
ncalls&tottime&percall&cumtime&percall&filename:lineno(function)
1&0.030&0.030&5.070&5.070&&string&:1(?)
121/1&5.020&0.041&5.020&5.020&book.py:11(process)
1&0.020&0.020&5.040&5.040&book.py:5(?)
2&0.000&0.000&0.000&0.000&exceptions.py:101(_&_init_&_)
1&0.060&0.060&5.130&5.130&profile:0(execfile('book.py'))
0&0.000&0.000&profile:0(profiler)当输出中的第一列包含了两个数字时(比如,121/1),后者是元调用(primitive call)的次数,前者是实际调用的次数(译者注:只有在递归情况下,实际调用的次数才会大于元调用的次数,其他情况下两者都相等)。对于绝大部分的应用程序来讲使用该模块所产生的的分析报告就已经足够了,比如,你只是想简单地看一下你的程序花费了多少时间。然后,如果你还想将这些数据保存下来,并在将来对其进行分析,你可以使用pstats模块。假设你想知道你的程序究竟在哪里花费了多少时间。如果你只是想简单地给你的整个程序计时的话,使用Unix中的time命令就已经完全能够应付了。例如:bash&%&time&python3&someprogram.py
real&0m13.937s
user&0m12.162s
sys&0m0.098s
bash&%通常来讲,分析代码的程度会介于这两个极端之间。比如,你可能已经知道你的代码会在一些特定的函数中花的时间特别多。针对这类特定函数的分析,我们可以使用修饰器decorator,例如:import&time
from&functools&import&wraps
def&timethis(func):
&&&&@wraps(func)
&&&&def&wrapper(*args,&**kwargs):
&&&&&&&&start&=&time.perf_counter()
&&&&&&&&r&=&func(*args,&**kwargs)
&&&&&&&&end&=&time.perf_counter()
&&&&&&&&print('{}.{}&:&{}'.format(func.__module__,&func.__name__,&end&-&start))
&&&&&&&&return&r
&&&&return&wrapper使用decorator的方式很简单,你只需要把它放在你想要分析的函数的定义前面就可以了。例如:&&&&@timethis
...&def&countdown(n):
...&&&&&while&n&&&0:
...&&&&&&&&&n&-=&1
&&&&countdown()
__main__.countdown&:&0.752
&&&如果想要分析一个语句块的话,你可以定义一个上下文管理器(context manager)。例如:import&time
from&contextlib&import&contextmanager
@contextmanager
def&timeblock(label):
&&&&start&=&time.perf_counter()
&&&&&&&&yield
&&&&finally:
&&&&&&&&end&=&time.perf_counter()
&&&&&&&&print('{}&:&{}'.format(label,&end&-&start))接下来是如何使用上下文管理器的例子:&&&&with&timeblock('counting'):
...&&&&&n&=&
...&&&&&while&n&&&0:
...&&&&&&&&&n&-=&1
counting&:&1.6455
&&&如果想研究一小段代码的性能的话,timeit模块会非常有用。例如:&&&&from&timeit&import&timeit
&&&&timeit('math.sqrt(2)',&'import&math')
&&&&timeit('sqrt(2)',&'from&math&import&sqrt')
&&&timeit的工作原理是,将第一个参数中的语句执行100万次,然后计算所花费的时间。第二个参数指定了一些测试之前需要做的环境准备工作。如果你需要改变迭代的次数,可以附加一个number参数,就像这样:&&&&timeit('math.sqrt(2)',&'import&math',&number=)
&&&&timeit('sqrt(2)',&'from&math&import&sqrt',&number=)
&&&当进行性能评估的时候,要牢记任何得出的结果只是一个估算值。函数time.perf_counter()能够在任一平台提供最高精度的计时器。然而,它也只是记录了自然时间,记录自然时间会被很多其他因素影响,比如,计算机的负载。如果你对处理时间而非自然时间感兴趣的话,你可以使用time.process_time()。例如:import&time
from&functools&import&wraps
def&timethis(func):
&&&&@wraps(func)
&&&&def&wrapper(*args,&**kwargs):
&&&&&&&&start&=&time.process_time()
&&&&&&&&r&=&func(*args,&**kwargs)
&&&&&&&&end&=&time.process_time()
&&&&&&&&print('{}.{}&:&{}'.format(func.__module__,&func.__name__,&end&-&start))
&&&&&&&&return&r
&&&&return&wrapper最后也是相当重要的就是,如果你想做一个详细的性能评估的话,你最好查阅time,timeit以及其他相关模块的文档,这样你才能够对平台相关的不同之处有所了解。profile模块中最基础的东西就是run()函数了。该函数会把一个语句字符串作为参数,然后在执行语句时生成所花费的时间报告。import&profile
def&fib(n):
&&&&#&from&literateprograms.org
&&&&#&http://bit.ly/hlOQ5m
&&&&if&n&==&0:
&&&&&&&&return&0
&&&&elif&n&==&1:
&&&&&&&&return&1
&&&&&&&&return&fib(n-1)&+&fib(n-2)
def&fib_seq(n):
&&&&seq&=&[]
&&&&if&n&&&0:
&&&&&&&&seq.extend(fib_seq(n-1))
&&&&seq.append(fib(n))
&&&&return&seq
profile.run('print(fib_seq(20));&print')性能优化当你的程序运行地很慢的时候,你就会想去提升它的运行速度,但是你又不想去借用一些复杂方案的帮助,比如使用C扩展或是just-in-time(JIT)编译器。那么这时候应该怎么办呢?要牢记性能优化的第一要义就是“不要为了优化而去优化,应该在我们开始写代码之前就想好应该怎样编写高性能的代码”。第二要义就是“优化一定要抓住重点,找到程序中最重要的地方去优化,而不要去优化那些不重要的部分”。通常来讲,你会发现你的程序在某些热点上花费了很多时间,比如内部数据的循环处理。一旦你发现了问题所在,你就可以对症下药,让你的程序更快地执行。使用函数许多开发者刚开始的时候会将Python作为一个编写简单脚本的工具。当编写脚本的时候,很容易就会写一些没有结构的代码出来。例如:import&sys
import&csv
with&open(sys.argv[1])&as&f:
&&&&for&row&in&csv.reader(f):
&&&&#&Some&kind&of&processing但是,却很少有人知道,定义在全局范围内的代码要比定义在函数中的代码执行地慢。他们之间速度的差别是因为局部变量与全局变量不同的实现所引起的(局部变量的操作要比全局变量来得快)。所以,如果你想要让程序更快地运行,那么你可以简单地将代码放在一个函数中,就像这样:import&sys
import&csv
def&main(filename):
&&&&with&open(filename)&as&f:
&&&&&&&&for&row&in&csv.reader(f):
&&&&&&&&&&&&#&Some&kind&of&processing
&&&&&&&&&&&&...
main(sys.argv[1])这样操作以后,处理速度会有提升,但是这个提升的程度依赖于程序的复杂性。根据经验来讲,通常都会提升15%到30%之间。选择性地减少属性的访问当使用点(.)操作符去访问属性时都会带来一定的消耗。本质上来讲,这会触发一些特殊方法的执行,比如__getattribute__()和__getattr__(),这通常都会导致去内存中字典数据的查询。你可以通过两种方式来避免属性的访问,第一种是使用from module import name的方式。第二种是将对象的方法名保存下来,在调用时直接使用。为了解释地更加清楚,我们来看一个例子:import&math
def&compute_roots(nums):
&&&&result&=&[]
&&&&for&n&in&nums:
&&&&&&&&result.append(math.sqrt(n))
&&&&return&result
nums&=&range(1000000)
for&n&in&range(100):
&&&&r&=&compute_roots(nums)上面的代码在我的计算机上运行大概需要40秒的时间。现在我们把上面代码中的compute_roots()函数改写一下:from&math&import&sqrt
def&compute_roots(nums):
&&&&result&=&[]
&&&&result_append&=&result.append
&&&&for&n&in&nums:
&&&&&&&&result_append(sqrt(n))
&&&&return&result
nums&=&range(1000000)
for&n&in&range(100):
&&&&r&=&compute_roots(nums)这个版本的代码执行一下大概需要29秒。这两个版本的代码唯一的不同之处在于后面一个版本减少了对属性的访问。在后面一段代码中,我们使用了sqrt()方法,而非math.sqrt()。result.append()函数也被存进了一个局部变量result_append中,然后在循环当中重复使用。然而,有必要强调一点是说,这种方式的优化仅仅针对经常运行的代码有效,比如循环。由此可见,优化仅仅在那些小心挑选出来的地方才会真正得到体现。理解变量的局部性上面已经讲过,局部变量的操作比全局变量来得快。对于经常要访问的变量来说,最好把他们保存成局部变量。例如,考虑刚才已经讨论过的compute_roots()函数修改版:import&math
def&compute_roots(nums):
&&&&sqrt&=&math.sqrt
&&&&result&=&[]
&&&&result_append&=&result.append
&&&&for&n&in&nums:
&&&&&&&&result_append(sqrt(n))
&&&&return&result在这个版本中,sqrt函数被一个局部变量所替代。如果你执行这段代码的话,大概需要25秒就执行完了(前一个版本需要29秒)。 这次速度的提升是因为sqrt局部变量的查询比sqrt函数的全局查询来得稍快。局部性原来同样适用于类的参数。通常来讲,使用self.name要比直接访问局部变量来得慢。在内部循环中,我们可以将经常要访问的属性保存为一个局部变量。例如:#Slower
class&SomeClass:
&&&&def&method(self):
&&&&&&&&for&x&in&s:
&&&&&&&&&&&&op(self.value)
class&SomeClass:
def&method(self):
&&&&value&=&self.value
&&&&for&x&in&s:
&&&&&&&&op(value)避免不必要的抽象任何时候当你想给你的代码添加其他处理逻辑,比如添加装饰器,属性或是描述符,你都是在拖慢你的程序。例如,考虑这样一个类:class&A:
&&&&def&__init__(self,&x,&y):
&&&&&&&&self.x&=&x
&&&&&&&&self.y&=&y
&&&&@property
&&&&def&y(self):
&&&&&&&&return&self._y
&&&&@y.setter
&&&&def&y(self,&value):
&&&&&&&&self._y&=&value现在,让我们简单地测试一下:&&&&from&timeit&import&timeit
&&&&a&=&A(1,2)
&&&&timeit('a.x',&'from&__main__&import&a')
&&&&timeit('a.y',&'from&__main__&import&a')
&&&正如你所看到的,我们访问属性y比访问简单属性x不是慢了一点点,整整慢了4.5倍之多。如果你在乎性能的话,你就很有必要问一下你自己,对y的那些额外的定义是否都是必要的了。如果不是的话,那么你应该把那些额外的定义删掉,用一个简单的属性就够了。如果只是因为在其他语言里面经常使用getter和setter函数的话,你完全没有必要在Python中也使用相同的编码风格。使用内置的容器内置的数据结构,例如字符串(string),元组(tuple),列表(list),集合(set)以及字典(dict)都是用C语言实现的,正是因为采用了C来实现,所以它们的性能表现也很好。如果你倾向于使用你自己的数据结构作为替代的话(例如,链表,平衡树或是其他数据结构),想达到内置数据结构的速度的话是非常困难的。因此,你应该尽可能地使用内置的数据结构。避免不必要的数据结构或是数据拷贝有时候程序员会有点儿走神,在不该用到数据结构的地方去用数据结构。例如,有人可能会写这样的的代码:values&=&[x&for&x&in&sequence]
squares&=&[x*x&for&x&in&values]也许他这么写是为了先得到一个列表,然后再在这个列表上进行一些操作。但是第一个列表是完全没有必要写在这里的。我们可以简单地把代码写成这样就行了:squares&=&[x*x&for&x&in&sequence]有鉴于此,你要小心那些偏执程序员所写的代码了,这些程序员对Python的值共享机制非常偏执。函数copy.deepcopy()的滥用也许是一个信号,表明该代码是由菜鸟或者是不相信Python内存模型的人所编写的。在这样的代码里,减少copy的使用也许会比较安全。在优化之前,很有必要先详细了解一下你所要使用的算法。如果你能够将算法的复杂度从O(n^2)降为O(n log n)的话,程序的性能将得到极大的提高。如果你已经打算进行优化工作了,那就很有必要全局地考虑一下。普适的原则就是,不要想去优化程序的每一个部分,这是因为优化工作会让代码变得晦涩难懂。相反,你应该把注意力集中在已知的性能瓶颈处,例如内部循环。你需要谨慎地对待微优化(micro-optimization)的结果。例如,考虑下面两种创建字典结构的方式:a&=&{
'name'&:&'AAPL',
'shares'&:&100,
'price'&:&534.22
b&=&dict(name='AAPL',&shares=100,&price=534.22)后面那一种方式打字打的更少一些(因为你不必将key的名字用双引号括起来)。然而当你将这两种编码方式进行性能对比时,你会发现使用dict()函数的方式比另一种慢了3倍之多!知道了这一点以后,你也许会倾向于扫描你的代码,把任何出现dict()的地方替换为另一种冗余的写法。然而,一个聪明的程序员绝对不会这么做,他只会将注意力放在值得关注的地方,比如在循环上。在其他地方,速度的差异并不是最重要的。但是,如果你想让你的程序性能有质的飞跃的话,你可以去研究下基于JIT技术的工具。比如,PyPy项目,该项目是Python解释器的另一种实现,它能够分析程序的执行并为经常执行的代码生成机器码,有时它甚至能够让Python程序的速度提升一个数量级,达到(甚至超过)C语言编写的代码的速度。但是不幸的是,在本文正在写的时候,PyPy还没有完全支持Python 3。所以,我们还是在将来再来看它到底会发展的怎么样。基于JIT技术的还有Numba项目。该项目实现的是一个动态的编译器,你可以将你想要优化的Python函数以注解的方式进行标记,然后这些代码就会在LLVM的帮助下被编译成机器码。该项目也能够带来极大的性能上的提升。然而,就像PyPy一样,该项目对Python 3的支持还只是实验性的。最后,但是也很重要的是,请牢记John Ousterhout(译者注:Tcl和Tk的发明者,现为斯坦福大学计算机系的教授)说过的话“将不工作的东西变成能够工作的,这才是最大的性能提升”。在你需要优化前不要过分地考虑程序的优化工作。程序的正确性通常来讲都比程序的性能要来的重要。原文链接: &&&翻译:
- 译文链接:
Python 的详细介绍:
Python 的下载地址:
想通过手机客户端(支持 Android、iPhone 和 Windows Phone)访问开源中国:
旧一篇: 1年前
新一篇: 1年前
相关讨论话题
你也许会喜欢
2楼:蓝桥书生
3楼:huangjacky
4楼:guoyh
5楼:temgy1986 来自
好东西,收藏之。
6楼:ARKII 来自
7楼:王铁锤
8楼:林夕_信仰
10楼:老学生
不错的文档
11楼:johnchain_li
12楼:xc_xiechuang
13楼:yuris_115
非常有助于调试啊
14楼:喵心雨
15楼:Jiangxinxin
与内容无关的评论将被删除,严重者禁用帐号
本周热点资讯
本站最新资讯

我要回帖

更多关于 http 192.168.1.1 的文章

 

随机推荐