textgrocery 的模型人口数量预测模型要多少

&p&租房的烦恼,相信大家或多或少都有过。独自一人在大都市打拼,找个温暖的小窝实属不易,租个称心又价格公道的房子是件重要的事儿。&/p&&p&本文作者、阿里工程师鹿星,也是众多北漂中的一员。如何从各大租房网的房源里面,找到最称心如意的小窝?今天让鹿星带大家看看数据能不能做出最优选择。文末有代码。&/p&&h2&&b&选择困难症&/b&&/h2&&p&毕业到现在两年多了,一直住的自如合租房,但因为各种原因住处已经换过4次,每次换租都是一件头疼的事。从茫茫房海中找一间中意的房间,实在是一件费时费力的活,对于我这种买东西直奔目的地的人来说,在这么多房间里对比各种房间属性选出最优的根本就是一种折磨(这里不得不说一下自如网的选房功能,列表筛选无法准备知道房间地点,而地图找房功能的筛选项又太少,实在无法满足我的需求),所以我每次都是草草选一个,将就着住。&/p&&p&最近在经历了又一次换租后,我萌生了把自如所有在租的房间数据都爬下来,找出最符合我预期的房间的想法,制作好一套流程以后再要换租的时候就可以无脑操作了。&/p&&h2&&b&爬取数据&/b&&/h2&&p&分析之前需要从自如网上爬数据,我用的是Python的Scrapy爬虫框架,但第一遍采集后发现房间数量要比自如网上能查到的数量少,找了下原因发现是自如的房间列表页中有些房间条目是js动态生成的,因为Scrapy没有js引擎,只能爬取静态页面,这部分数据自然就没采集下来。利用scrapy-splash来提供js渲染服务,最终完整采集到了所有在租的自如房间数据,共7907条。采集到的数据样例如下。每一行是一个json格式的字符串&/p&&p&&br&&/p&&img src=&/v2-fe83def5_b.png& data-rawwidth=&872& data-rawheight=&158& class=&origin_image zh-lightbox-thumb& width=&872& data-original=&/v2-fe83def5_r.png&&&h2&&b&租金的整体印象&/b&&/h2&&p&我只关心合租房的数据,再做脏数据过滤,共得到4762条合租房数据。合租房房租的平均值和中位数非常接近,整体数据基本无偏,即低价位和高价位的房间数量差不多。&/p&&p&&br&&/p&&img src=&/v2-f0d16dc3baf9e463e466172_b.png& data-rawwidth=&675& data-rawheight=&89& class=&origin_image zh-lightbox-thumb& width=&675& data-original=&/v2-f0d16dc3baf9e463e466172_r.png&&&p&不同价格的房间数量分布如图1,基本符合正态分布。&/p&&p&&br&&/p&&img src=&/v2-40edc36dc8e1cbf1b70eeb1_b.png& data-rawwidth=&640& data-rawheight=&331& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-40edc36dc8e1cbf1b70eeb1_r.png&&&p&(图 1 合租房不同价格区间的房间数量分布)&/p&&h2&&b&神秘的最贵房间&/b&&/h2&&p&从上图可以看到一间房超过了6000元,这勾起了我的好奇心,什么房间能这么贵。这间6290元月租金的房间链接是&a href=&/?target=http%3A///z/vr/.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&/z/vr/6055836&/span&&span class=&invisible&&8.html&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a& ,如下图。除了紧邻西单商场其它属性都没什么突出的。去链家上看了一下这个西黄城根45号院,小区均价14.6万元/平米,好吧,似乎明白为啥这屋子这么贵了。&/p&&p&&br&&/p&&img src=&/v2-a121e773c91_b.png& data-rawwidth=&640& data-rawheight=&273& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-a121e773c91_r.png&&&p&为了膜拜一下这个西黄城根45号院,我又在自如上搜了这个小区的所有在租房间,如下。突然发现好像就这间很贵,而其它房间价格虽然也不算低,但也不像这间这么离谱,有些房间的属性甚至看起来还比这间更好。这个房间总感觉是被自如标错价了,难不成它有什么隐藏属性(住进去每天精神值MAX)。&/p&&p&&br&&/p&&img src=&/v2-bd43da501d2c45d6614fb6_b.png& data-rawwidth=&640& data-rawheight=&521& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-bd43da501d2c45d6614fb6_r.png&&&h2&&b&租金地图&/b&&/h2&&p&房间价格在地图上的分布如图2。红色表示大于3000元/月的房间,绿色表示元/月的房间,紫色表示小于2000元/月的房间。颜色越深表示同一个位置重叠有越多房屋,可见总体上北京北边比南边贵,东边比西边贵。而要想租到月租2000以下的房间,就得考虑去往五环之外了。&/p&&p&&br&&/p&&img src=&/v2-f0ffceaf2c_b.png& data-rawwidth=&614& data-rawheight=&599& class=&origin_image zh-lightbox-thumb& width=&614& data-original=&/v2-f0ffceaf2c_r.png&&&p&(图 2 合租房价格在地图上的分布)&/p&&h2&&b&谁最重要?&/b&&/h2&&p&接下来看一下自如对房间定价时考虑的因素主次。使用随机森林算法对房间每月租金进行预测,选取如下14个特征:房间面积、自如配置版本(1.0,2.0等)、配置类型(布丁、拿铁等)、朝向、房间所在楼层、房间所在楼的总楼层、离最近地铁站的距离、是否有独立阳台、是否有独立卫生间、几室、几厅、所在北京区县、相对天安门的方位角、与天安门的距离。对其中的自如配置版本、配置类型、朝向、所在北京区县这四个类别特征使用One-Hot Encoding进行编码,最终扩展为41个特征。使用2/3的数据训练模型,1/3的数据进行测试,在测试集上得到拟合优度R2=0.86,不同特征对租金的影响程度Top10如下:&/p&&p&&br&&/p&&img src=&/v2-e4ae4a9304eaa7e622c59be_b.png& data-rawwidth=&682& data-rawheight=&296& class=&origin_image zh-lightbox-thumb& width=&682& data-original=&/v2-e4ae4a9304eaa7e622c59be_r.png&&&p&&br&&/p&&p&可见所在方位、房间面积大小、交通方便程度、有没有独卫是影响房间租金的主要因素。话说以前我还一直觉得房间加上朝南的属性会更贵,现在看来好像是我的错觉?&/p&&h2&&b&终极目标&/b&&/h2&&p&最后,回到本次分析的终极目标,找出最符合我预期的房间。我需要做的就是综合我自己的关注属性值对房间进行排序,我最关心的房间属性是[房间面积,房间租金,到公司的距离],这里我使用的是灰度关联分析法对房间进行打分,详细计算过程网上都有,这里我就不再罗列了。&/p&&p&首先我过滤掉属性值超出我心理预期范围的房间,将价格大于等于2200元/月,面积小于等于8m2的房间过滤掉。过滤后的数据集中选5条数据如下:&/p&&p&&br&&/p&&img src=&/v2-acf8a50fd20d3_b.png& data-rawwidth=&679& data-rawheight=&191& class=&origin_image zh-lightbox-thumb& width=&679& data-original=&/v2-acf8a50fd20d3_r.png&&&p&对这三个属性值无量纲化,这里我使用的是离差标准化,如下。标准化后x_i^,的取值范围为[0,1]。&/p&&p&&br&&/p&&img src=&/v2-dbcdf2d367cf9a5e3308_b.png& data-rawwidth=&667& data-rawheight=&245& class=&origin_image zh-lightbox-thumb& width=&667& data-original=&/v2-dbcdf2d367cf9a5e3308_r.png&&&p&后数据如下:&/p&&p&&br&&/p&&img src=&/v2-7ecfbda58e8_b.png& data-rawwidth=&677& data-rawheight=&170& class=&origin_image zh-lightbox-thumb& width=&677& data-original=&/v2-7ecfbda58e8_r.png&&&p&然后设定最优序列,最理想的状态当然是房间面积最大,租金最小,到公司距离最近了。因此最优序列为[1,0,0],计算每个属性与最优序列相应属性之间的关联系数如下:&/p&&p&&br&&/p&&img src=&/v2-9ede860e9f7a74f5d4cb077cdd9b1f12_b.png& data-rawwidth=&676& data-rawheight=&192& class=&origin_image zh-lightbox-thumb& width=&676& data-original=&/v2-9ede860e9f7a74f5d4cb077cdd9b1f12_r.png&&&p&由于我对不同属性的关注程度不同,因此这里需要设定每个属性的权重,权重值使用目标优化矩阵确定。&/p&&p&&br&&/p&&img src=&/v2-cfbea6c8039d_b.png& data-rawwidth=&685& data-rawheight=&116& class=&origin_image zh-lightbox-thumb& width=&685& data-original=&/v2-cfbea6c8039d_r.png&&&p&因此房间面积权重为1/6,房间租金权重为1/3,到公司的距离权重为1/2,则每个房间的关联系数=房间面积关联系数/6+房间租金关联系数/3+到公司的距离关联系数/2,计算结果如下:&/p&&p&&br&&/p&&img src=&/v2-ca02b26cb032d00cd1f1a8_b.png& data-rawwidth=&675& data-rawheight=&168& class=&origin_image zh-lightbox-thumb& width=&675& data-original=&/v2-ca02b26cb032d00cd1f1a8_r.png&&&p&计算出所有房间的关联系数,从大到小排列后取Top10如下:&/p&&p&&br&&/p&&img src=&/v2-a988ff585f6ed40_b.png& data-rawwidth=&640& data-rawheight=&249& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-a988ff585f6ed40_r.png&&&p&这下可以挑选房间的范围就大大缩小了,以后要是再租房感觉烦恼少好多。当然由于自如网上房间信息变动较快,随时都会有人下定,这套流程还得随租随用,不然筛选出房间后过个两三天再看,说不定房间早就被别人抢了。&/p&&p&来源:阿里技术&/p&&p&租房爬虫分析代码(复制后在PC网页端打开):&/p&&p&&a href=&/?target=http%3A//-hangzhou.oss-pub./%25E7%2588%25AC%25E8%2599%25AB%25E5%E5%E6%259E%%25BB%25A3%25E7%25A0%2581.zip& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&-hangzhou.oss-pub.&/span&&span class=&invisible&&/%E7%88%AC%E8%99%AB%E5%92%8C%E5%88%86%E6%9E%90%E4%BB%A3%E7%A0%81.zip&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/p&&h2&&b&更多技术干货敬请关注云栖社区知乎机构号:&a href=&/org/a-li-yun-yun-qi-she-qu-48& class=&internal&&阿里云云栖社区 - 知乎&/a&&/b&&/h2&&p&&/p&
租房的烦恼,相信大家或多或少都有过。独自一人在大都市打拼,找个温暖的小窝实属不易,租个称心又价格公道的房子是件重要的事儿。本文作者、阿里工程师鹿星,也是众多北漂中的一员。如何从各大租房网的房源里面,找到最称心如意的小窝?今天让鹿星带大家看…
&img src=&/50/v2-1ceb6c13b34c3df51adc_b.png& data-rawwidth=&939& data-rawheight=&532& class=&origin_image zh-lightbox-thumb& width=&939& data-original=&/50/v2-1ceb6c13b34c3df51adc_r.png&&&blockquote&&i&七月末的南京简直开启了「微波炉」模式,白天要学车的我,晚上自然选择宅在家看直播,看着狗贼叔叔满屏幕的弹幕,我就想着能不能把弹幕爬下来呢?说干就干&/i&&/blockquote&&h2&结果的展示:&/h2&&p&这里只抓到弹幕内容和发送用户&br&并输出在终端上,有兴趣的小伙伴&br&可以在这个基础上接着开发,&br&搜集弹幕做做数据分析也是很ok的啊!&/p&&p&下面是展示图:&/p&&p&&br&&/p&&img src=&/v2-139ded43ed347d4e0cd9b5c_b.png& data-rawwidth=&649& data-rawheight=&434& class=&origin_image zh-lightbox-thumb& width=&649& data-original=&/v2-139ded43ed347d4e0cd9b5c_r.png&&&p&&br&&/p&&p&&br&&/p&&h2&资料的搜集&/h2&&p&面向Google编程的我,第一件事当然是键入关键词:「Python 弹幕」&/p&&p&吃惊的是,网上已经有了炒鸡完善的弹幕第三方库:「DanMU」&/p&&p&使用起来也是炒鸡简单,十几行代码就能轻松获取直播间的弹幕了,&/p&&p&有兴趣的同学可以去搜索看看。&/p&&p&本着练手和不折腾会死的态度,我还是想尝试自己写一个版本出来,&/p&&p&然后就找到了 斗鱼居然开放了Api,&/p&&p&这样的话,只要稍微处理一下,就能愉快的获取想要的信息了。&/p&&h2&斗鱼Api接口文档和接入协议&/h2&&p&&br&&/p&&ul&&li&《斗鱼弹幕服务器第三方接入协议v1.4.1》: &a href=&/?target=http%3A//dev-/forum.php%3Fmod%3Dviewthread%26tid%3D115%26extra%3Dpage%253D1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&http://dev-/forum.php?mod=viewthread&tid=115&extra=page%3D1&i class=&icon-external&&&/i&&/a&&/li&&li&《斗鱼第三方开放平台API文档v2.1》: &a href=&/?target=http%3A//dev-/forum.php%3Fmod%3Dviewthread%26tid%3D113%26extra%3Dpage%253D1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&http://dev-/forum.php?mod=viewthread&tid=113&extra=page%3D1&i class=&icon-external&&&/i&&/a&&/li&&/ul&&p&&br&&/p&&p&仔细观察文档之后,我发现只要自己实现一下协议头,&/p&&p&就能接入弹幕服务器了,&/p&&p&接着构造弹幕请求,&/p&&p&就能实时的获取每一条弹幕了。&/p&&h2&请求头的构造&/h2&&p&先看文档的要求:&/p&&p&&br&&/p&&img src=&/v2-bd921f9ca81c4_b.png& data-rawwidth=&880& data-rawheight=&1498& class=&origin_image zh-lightbox-thumb& width=&880& data-original=&/v2-bd921f9ca81c4_r.png&&&p&&br&&/p&&p&&br&&/p&&p&简而言之呢:&/p&&p&请求一共分为三个部分:长度,头部,数据部&br&分别按照文档的要求构造就行,&br&需要注意的是,获取和返回的类型是都是 &b&Bytes&/b&&/p&&p&&b&代码:&/b&&/p&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msgstr&/span&&span class=&p&&):&/span&
&span class=&sd&&'''构造并发送符合斗鱼api的请求'''&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&n&&msgstr&/span&&span class=&o&&.&/span&&span class=&n&&encode&/span&&span class=&p&&(&/span&&span class=&s1&&'utf8'&/span&&span class=&p&&)&/span&
&span class=&n&&data_length&/span& &span class=&o&&=&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span& &span class=&o&&+&/span& &span class=&mi&&8&/span&
&span class=&n&&code&/span& &span class=&o&&=&/span& &span class=&mi&&689&/span&
&span class=&c1&&# 构造协议头&/span&
&span class=&n&&msgHead&/span& &span class=&o&&=&/span& &span class=&nb&&int&/span&&span class=&o&&.&/span&&span class=&n&&to_bytes&/span&&span class=&p&&(&/span&&span class=&n&&data_length&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&s1&&'little'&/span&&span class=&p&&)&/span& \
&span class=&o&&+&/span& &span class=&nb&&int&/span&&span class=&o&&.&/span&&span class=&n&&to_bytes&/span&&span class=&p&&(&/span&&span class=&n&&data_length&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&s1&&'little'&/span&&span class=&p&&)&/span& &span class=&o&&+&/span& \
&span class=&nb&&int&/span&&span class=&o&&.&/span&&span class=&n&&to_bytes&/span&&span class=&p&&(&/span&&span class=&n&&code&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&s1&&'little'&/span&&span class=&p&&)&/span&
&span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&n&&msgHead&/span&&span class=&p&&)&/span&
&span class=&n&&sent&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&k&&while&/span& &span class=&n&&sent&/span& &span class=&o&&&&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&):&/span&
&span class=&n&&tn&/span& &span class=&o&&=&/span& &span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&[&/span&&span class=&n&&sent&/span&&span class=&p&&:])&/span&
&span class=&n&&sent&/span& &span class=&o&&=&/span& &span class=&n&&sent&/span& &span class=&o&&+&/span& &span class=&n&&tn&/span&
&/code&&/pre&&/div&&h2&获取弹幕&/h2&&p&这里的部分也是按照文档要求写就成&br&首先 发送登录请求&br&接着 每隔固定时间发送【心跳请求】防止断线&/p&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&k&&def&/span& &span class=&nf&&DM_start&/span&&span class=&p&&(&/span&&span class=&n&&roomid&/span&&span class=&p&&):&/span&
&span class=&c1&&# 构造登录授权请求&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=loginreq/roomid@=&/span&&span class=&si&&{}&/span&&span class=&s1&&/&/span&&span class=&se&&\0&/span&&span class=&s1&&'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&roomid&/span&&span class=&p&&)&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span&
&span class=&c1&&# 构造获取弹幕消息请求&/span&
&span class=&n&&msg_more&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=joingroup/rid@=&/span&&span class=&si&&{}&/span&&span class=&s1&&/gid@=-9999/&/span&&span class=&se&&\0&/span&&span class=&s1&&'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&roomid&/span&&span class=&p&&)&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg_more&/span&&span class=&p&&)&/span&
&span class=&k&&while&/span& &span class=&kc&&True&/span&&span class=&p&&:&/span&
&span class=&c1&&# 服务端返回的数据&/span&
&span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&recv&/span&&span class=&p&&(&/span&&span class=&mi&&1024&/span&&span class=&p&&)&/span&
&span class=&c1&&# 通过re模块找发送弹幕的用户名和内容&/span&
&span class=&n&&danmu_username&/span& &span class=&o&&=&/span& &span class=&n&&username_re&/span&&span class=&o&&.&/span&&span class=&n&&findall&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&n&&danmu_content&/span& &span class=&o&&=&/span& &span class=&n&&danmu_re&/span&&span class=&o&&.&/span&&span class=&n&&findall&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&n&&data&/span&&span class=&p&&:&/span&
&span class=&k&&break&/span&
&span class=&k&&else&/span&&span class=&p&&:&/span&
&span class=&k&&for&/span& &span class=&n&&i&/span& &span class=&ow&&in&/span& &span class=&nb&&range&/span&&span class=&p&&(&/span&&span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&danmu_content&/span&&span class=&p&&)):&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&c1&&# 输出信息&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'[&/span&&span class=&si&&{}&/span&&span class=&s1&&]:&/span&&span class=&si&&{}&/span&&span class=&s1&&'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&danmu_username&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span&&span class=&o&&.&/span&&span class=&n&&decode&/span&&span class=&p&&(&/span&
&span class=&s1&&'utf8'&/span&&span class=&p&&),&/span& &span class=&n&&danmu_content&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span&&span class=&o&&.&/span&&span class=&n&&decode&/span&&span class=&p&&(&/span&&span class=&n&&encoding&/span&&span class=&o&&=&/span&&span class=&s1&&'utf8'&/span&&span class=&p&&)))&/span&
&span class=&k&&except&/span&&span class=&p&&:&/span&
&span class=&k&&continue&/span&
&span class=&k&&def&/span& &span class=&nf&&keeplive&/span&&span class=&p&&():&/span&
&span class=&sd&&'''&/span&
&span class=&sd&&
保持心跳,15秒心跳请求一次&/span&
&span class=&sd&&
'''&/span&
&span class=&k&&while&/span& &span class=&kc&&True&/span&&span class=&p&&:&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=keeplive/tick@='&/span& &span class=&o&&+&/span& &span class=&nb&&str&/span&&span class=&p&&(&/span&&span class=&nb&&int&/span&&span class=&p&&(&/span&&span class=&n&&time&/span&&span class=&o&&.&/span&&span class=&n&&time&/span&&span class=&p&&()))&/span& &span class=&o&&+&/span& &span class=&s1&&'/&/span&&span class=&se&&\0&/span&&span class=&s1&&'&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'发送心跳包'&/span&&span class=&p&&)&/span&
&span class=&n&&time&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&15&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&h2&tricky 的部分&/h2&&p&上面的内容,说起来都不是很难,&br&但是想要完整的实现需求,&br&这里需要的知识还是比较多的:&/p&&ul&&li&socket相关&/li&&li&正则表达式相关&/li&&li&signal相关&/li&&li&多线程、多进程相关&/li&&/ul&&p&比如我想要实现捕捉「ctrl+c」的信号,&br&好在我们退出程序的时候,能够正确的处理&br&这时候就要用到&b&signal&/b&相关的知识&br&说起来,在今天之前,我完全不知道还可以这样用。&/p&&p&总之越是学到后面,&br&越是会觉得自己的知识储备不足,&br&Python 作为一门十分强大和容易上手的语言,&br&能够帮助我们迅速的实现需求,&br&但是不要认为他单单只能写爬虫哦,&/p&&h2&完整的代码&/h2&&p&有详细的注释哦:&/p&&div class=&highlight&&&pre&&code class=&language-python3&&&span&&/span&&span class=&sd&&'''&/span&
&span class=&sd&&利用斗鱼弹幕 api&/span&
&span class=&sd&&尝试抓取斗鱼tv指定房间的弹幕&/span&
&span class=&sd&&'''&/span&
&span class=&kn&&import&/span& &span class=&nn&&multiprocessing&/span&
&span class=&kn&&import&/span& &span class=&nn&&socket&/span&
&span class=&kn&&import&/span& &span class=&nn&&time&/span&
&span class=&kn&&import&/span& &span class=&nn&&re&/span&
&span class=&kn&&import&/span& &span class=&nn&&signal&/span&
&span class=&c1&&# 构造socket连接,和斗鱼api服务器相连接&/span&
&span class=&n&&client&/span& &span class=&o&&=&/span& &span class=&n&&socket&/span&&span class=&o&&.&/span&&span class=&n&&socket&/span&&span class=&p&&(&/span&&span class=&n&&socket&/span&&span class=&o&&.&/span&&span class=&n&&AF_INET&/span&&span class=&p&&,&/span& &span class=&n&&socket&/span&&span class=&o&&.&/span&&span class=&n&&SOCK_STREAM&/span&&span class=&p&&)&/span&
&span class=&n&&host&/span& &span class=&o&&=&/span& &span class=&n&&socket&/span&&span class=&o&&.&/span&&span class=&n&&gethostbyname&/span&&span class=&p&&(&/span&&span class=&s2&&&&&/span&&span class=&p&&)&/span&
&span class=&n&&port&/span& &span class=&o&&=&/span& &span class=&mi&&8601&/span&
&span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&connect&/span&&span class=&p&&((&/span&&span class=&n&&host&/span&&span class=&p&&,&/span& &span class=&n&&port&/span&&span class=&p&&))&/span&
&span class=&c1&&# 弹幕查询正则表达式&/span&
&span class=&n&&danmu_re&/span& &span class=&o&&=&/span& &span class=&n&&re&/span&&span class=&o&&.&/span&&span class=&n&&compile&/span&&span class=&p&&(&/span&&span class=&n&&b&/span&&span class=&s1&&'txt@=(.+?)/cid@'&/span&&span class=&p&&)&/span&
&span class=&n&&username_re&/span& &span class=&o&&=&/span& &span class=&n&&re&/span&&span class=&o&&.&/span&&span class=&n&&compile&/span&&span class=&p&&(&/span&&span class=&n&&b&/span&&span class=&s1&&'nn@=(.+?)/txt@'&/span&&span class=&p&&)&/span&
&span class=&k&&def&/span& &span class=&nf&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msgstr&/span&&span class=&p&&):&/span&
&span class=&sd&&'''构造并发送符合斗鱼api的请求'''&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&n&&msgstr&/span&&span class=&o&&.&/span&&span class=&n&&encode&/span&&span class=&p&&(&/span&&span class=&s1&&'utf-8'&/span&&span class=&p&&)&/span&
&span class=&n&&data_length&/span& &span class=&o&&=&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span& &span class=&o&&+&/span& &span class=&mi&&8&/span&
&span class=&n&&code&/span& &span class=&o&&=&/span& &span class=&mi&&689&/span&
&span class=&c1&&# 构造协议头&/span&
&span class=&n&&msgHead&/span& &span class=&o&&=&/span& &span class=&nb&&int&/span&&span class=&o&&.&/span&&span class=&n&&to_bytes&/span&&span class=&p&&(&/span&&span class=&n&&data_length&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&s1&&'little'&/span&&span class=&p&&)&/span& \
&span class=&o&&+&/span& &span class=&nb&&int&/span&&span class=&o&&.&/span&&span class=&n&&to_bytes&/span&&span class=&p&&(&/span&&span class=&n&&data_length&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&s1&&'little'&/span&&span class=&p&&)&/span& &span class=&o&&+&/span& \
&span class=&nb&&int&/span&&span class=&o&&.&/span&&span class=&n&&to_bytes&/span&&span class=&p&&(&/span&&span class=&n&&code&/span&&span class=&p&&,&/span& &span class=&mi&&4&/span&&span class=&p&&,&/span& &span class=&s1&&'little'&/span&&span class=&p&&)&/span&
&span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&n&&msgHead&/span&&span class=&p&&)&/span&
&span class=&n&&sent&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&
&span class=&k&&while&/span& &span class=&n&&sent&/span& &span class=&o&&&&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&):&/span&
&span class=&n&&tn&/span& &span class=&o&&=&/span& &span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&send&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&[&/span&&span class=&n&&sent&/span&&span class=&p&&:])&/span&
&span class=&n&&sent&/span& &span class=&o&&=&/span& &span class=&n&&sent&/span& &span class=&o&&+&/span& &span class=&n&&tn&/span&
&span class=&k&&def&/span& &span class=&nf&&DM_start&/span&&span class=&p&&(&/span&&span class=&n&&roomid&/span&&span class=&p&&):&/span&
&span class=&c1&&# 构造登录授权请求&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=loginreq/roomid@=&/span&&span class=&si&&{}&/span&&span class=&s1&&/&/span&&span class=&se&&\0&/span&&span class=&s1&&'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&roomid&/span&&span class=&p&&)&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span&
&span class=&c1&&# 构造获取弹幕消息请求&/span&
&span class=&n&&msg_more&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=joingroup/rid@=&/span&&span class=&si&&{}&/span&&span class=&s1&&/gid@=-9999/&/span&&span class=&se&&\0&/span&&span class=&s1&&'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&roomid&/span&&span class=&p&&)&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg_more&/span&&span class=&p&&)&/span&
&span class=&k&&while&/span& &span class=&kc&&True&/span&&span class=&p&&:&/span&
&span class=&c1&&# 服务端返回的数据&/span&
&span class=&n&&data&/span& &span class=&o&&=&/span& &span class=&n&&client&/span&&span class=&o&&.&/span&&span class=&n&&recv&/span&&span class=&p&&(&/span&&span class=&mi&&1024&/span&&span class=&p&&)&/span&
&span class=&c1&&# 通过re模块找发送弹幕的用户名和内容&/span&
&span class=&n&&danmu_username&/span& &span class=&o&&=&/span& &span class=&n&&username_re&/span&&span class=&o&&.&/span&&span class=&n&&findall&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&n&&danmu_content&/span& &span class=&o&&=&/span& &span class=&n&&danmu_re&/span&&span class=&o&&.&/span&&span class=&n&&findall&/span&&span class=&p&&(&/span&&span class=&n&&data&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&n&&data&/span&&span class=&p&&:&/span&
&span class=&k&&break&/span&
&span class=&k&&else&/span&&span class=&p&&:&/span&
&span class=&k&&for&/span& &span class=&n&&i&/span& &span class=&ow&&in&/span& &span class=&nb&&range&/span&&span class=&p&&(&/span&&span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&nb&&len&/span&&span class=&p&&(&/span&&span class=&n&&danmu_content&/span&&span class=&p&&)):&/span&
&span class=&k&&try&/span&&span class=&p&&:&/span&
&span class=&c1&&# 输出信息&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'[&/span&&span class=&si&&{}&/span&&span class=&s1&&]:&/span&&span class=&si&&{}&/span&&span class=&s1&&'&/span&&span class=&o&&.&/span&&span class=&n&&format&/span&&span class=&p&&(&/span&&span class=&n&&danmu_username&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span&&span class=&o&&.&/span&&span class=&n&&decode&/span&&span class=&p&&(&/span&
&span class=&s1&&'utf8'&/span&&span class=&p&&),&/span& &span class=&n&&danmu_content&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span&&span class=&o&&.&/span&&span class=&n&&decode&/span&&span class=&p&&(&/span&&span class=&n&&encoding&/span&&span class=&o&&=&/span&&span class=&s1&&'utf8'&/span&&span class=&p&&)))&/span&
&span class=&k&&except&/span&&span class=&p&&:&/span&
&span class=&k&&continue&/span&
&span class=&k&&def&/span& &span class=&nf&&keeplive&/span&&span class=&p&&():&/span&
&span class=&sd&&'''&/span&
&span class=&sd&&
保持心跳,15秒心跳请求一次&/span&
&span class=&sd&&
'''&/span&
&span class=&k&&while&/span& &span class=&kc&&True&/span&&span class=&p&&:&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=keeplive/tick@='&/span& &span class=&o&&+&/span& &span class=&nb&&str&/span&&span class=&p&&(&/span&&span class=&nb&&int&/span&&span class=&p&&(&/span&&span class=&n&&time&/span&&span class=&o&&.&/span&&span class=&n&&time&/span&&span class=&p&&()))&/span& &span class=&o&&+&/span& &span class=&s1&&'/&/span&&span class=&se&&\0&/span&&span class=&s1&&'&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'发送心跳包'&/span&&span class=&p&&)&/span&
&span class=&n&&time&/span&&span class=&o&&.&/span&&span class=&n&&sleep&/span&&span class=&p&&(&/span&&span class=&mi&&15&/span&&span class=&p&&)&/span&
&span class=&k&&def&/span& &span class=&nf&&logout&/span&&span class=&p&&():&/span&
&span class=&sd&&'''&/span&
&span class=&sd&&
与斗鱼服务器断开连接&/span&
&span class=&sd&&
关闭线程&/span&
&span class=&sd&&
'''&/span&
&span class=&n&&msg&/span& &span class=&o&&=&/span& &span class=&s1&&'type@=logout/'&/span&
&span class=&n&&send_req_msg&/span&&span class=&p&&(&/span&&span class=&n&&msg&/span&&span class=&p&&)&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'已经退出服务器'&/span&&span class=&p&&)&/span&
&span class=&k&&def&/span& &span class=&nf&&signal_handler&/span&&span class=&p&&(&/span&&span class=&n&&signal&/span&&span class=&p&&,&/span& &span class=&n&&frame&/span&&span class=&p&&):&/span&
&span class=&sd&&'''&/span&
&span class=&sd&&
捕捉 ctrl+c的信号 即 signal.SIGINT&/span&
&span class=&sd&&
触发hander:&/span&
&span class=&sd&&
登出斗鱼服务器&/span&
&span class=&sd&&
关闭进程&/span&
&span class=&sd&&
'''&/span&
&span class=&n&&p1&/span&&span class=&o&&.&/span&&span class=&n&&terminate&/span&&span class=&p&&()&/span&
&span class=&n&&p2&/span&&span class=&o&&.&/span&&span class=&n&&terminate&/span&&span class=&p&&()&/span&
&span class=&n&&logout&/span&&span class=&p&&()&/span&
&span class=&nb&&print&/span&&span class=&p&&(&/span&&span class=&s1&&'Bye'&/span&&span class=&p&&)&/span&
&span class=&k&&if&/span& &span class=&n&&__name__&/span& &span class=&o&&==&/span& &span class=&s1&&'__main__'&/span&&span class=&p&&:&/span&
&span class=&c1&&#room_id = input('请输入房间ID: ')&/span&
&span class=&c1&&# 狗贼的房间号&/span&
&span class=&n&&room_id&/span& &span class=&o&&=&/span& &span class=&mi&&208114&/span&
&span class=&c1&&# 开启signal捕捉&/span&
&span class=&n&&signal&/span&&span class=&o&&.&/span&&span class=&n&&signal&/span&&span class=&p&&(&/span&&span class=&n&&signal&/span&&span class=&o&&.&/span&&span class=&n&&SIGINT&/span&&span class=&p&&,&/span& &span class=&n&&signal_handler&/span&&span class=&p&&)&/span&
&span class=&c1&&# 开启弹幕和心跳进程&/span&
&span class=&n&&p1&/span& &span class=&o&&=&/span& &span class=&n&&multiprocessing&/span&&span class=&o&&.&/span&&span class=&n&&Process&/span&&span class=&p&&(&/span&&span class=&n&&target&/span&&span class=&o&&=&/span&&span class=&n&&DM_start&/span&&span class=&p&&,&/span& &span class=&n&&args&/span&&span class=&o&&=&/span&&span class=&p&&(&/span&&span class=&n&&room_id&/span&&span class=&p&&,))&/span&
&span class=&n&&p2&/span& &span class=&o&&=&/span& &span class=&n&&multiprocessing&/span&&span class=&o&&.&/span&&span class=&n&&Process&/span&&span class=&p&&(&/span&&span class=&n&&target&/span&&span class=&o&&=&/span&&span class=&n&&keeplive&/span&&span class=&p&&)&/span&
&span class=&n&&p1&/span&&span class=&o&&.&/span&&span class=&n&&start&/span&&span class=&p&&()&/span&
&span class=&n&&p2&/span&&span class=&o&&.&/span&&span class=&n&&start&/span&&span class=&p&&()&/span&
&/code&&/pre&&/div&&p&&br&&/p&&blockquote&&i&每天的学习记录都会 同步更新到:&br&微信公众号: findyourownway&br&&br&知乎专栏:&a href=&/Ehco-python& class=&internal&&&span class=&invisible&&https://&/span&&span class=&visible&&/Ehco&/span&&span class=&invisible&&-python&/span&&span class=&ellipsis&&&/span&&/a&&br&&br&blog :&/i& &i&&a href=&/?target=http%3A//www.ehcoblog.ml/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&www.ehcoblog.ml&i class=&icon-external&&&/i&&/a&&br&&br&Github:&/i& &i&&a href=&/?target=https%3A///Ehco1996/Python-crawler& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/Ehco1996/Pyt&/span&&span class=&invisible&&hon-crawler&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/i&&/blockquote&&p&&/p&&p&&/p&&p&&/p&
七月末的南京简直开启了「微波炉」模式,白天要学车的我,晚上自然选择宅在家看直播,看着狗贼叔叔满屏幕的弹幕,我就想着能不能把弹幕爬下来呢?说干就干结果的展示:这里只抓到弹幕内容和发送用户 并输出在终端上,有兴趣的小伙伴 可以在这个基础上接着开…
&p&&b&为啥别人能找到工作,而你不能?有部分人的情况是,能力没有达到公司对初级程序员的最低要求。&/b&&br&&/p&很多人学习编程,不是凭兴趣,是奔着高工资去的。没有兴趣,可以培养兴趣。&p&&b&很多人只关心工作,但不愿意花时间学习提高自己的技能。&/b&&/p&&p&&b&不会编程,程序员的工作和你半毛钱关系没有!&/b&&/p&&br&&p&1、毫不夸张,很多面试者,基本的循环代码写不出来,况算法乎?&/p&&p&
2014年,黄哥出的一个面试题,“一个日志文本文件有2000行,提取其中的100行到200行,怎么做?”,好多号称会编程的面试者,写不出代码。&/p&&p&2、有的面试者,简历毫无亮点,过不了,”狗眼看人低“的HR 一关。&/p&&p&3、有的求职者拒绝做面试题,听说做面试题,不去面试了。&/p&&p&4、有的面试题,在面试时,表现出没有担当,只会说不清楚,这个搞不定,没有表现出强烈
的企图心。&/p&&p&5、有的工资要求超出求职者的能力太多,也是求职失败的原因之一。&/p&&p&6、最后请大家思考一下问题?很多人担心找不到工作,看到企业要求有N年经验,就害怕了,&b&思考的问题是:已经有N年经验的程序员,他们的第一个工作是怎么找的?&/b&&/p&&p&&b&总结:打铁还需自身硬,如果自我感觉良好(只会调一些包,所有业务逻辑写在一个函数里,不会做需求分析,不会切分任务,写的类耦合严重,.....), 抓紧加强自己的技能吧。&/b&&/p&&br&&p&如何训练自己的编程思路&/p&&a href=&/?target=https%3A///pythonpeixun/article/blob/master/python/how_to_learn_program2.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&pythonpeixun/article&i class=&icon-external&&&/i&&/a&&p&部分免费python免费视频&br&&/p&&a href=&/?target=https%3A///pythonpeixun/article/blob/master/python_shiping.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&pythonpeixun/article&i class=&icon-external&&&/i&&/a&&p&216小时学会python&br&&/p&&a href=&/?target=https%3A///pythonpeixun/article/blob/master/python/hours_216.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&pythonpeixun/article&i class=&icon-external&&&/i&&/a&
为啥别人能找到工作,而你不能?有部分人的情况是,能力没有达到公司对初级程序员的最低要求。 很多人学习编程,不是凭兴趣,是奔着高工资去的。没有兴趣,可以培养兴趣。很多人只关心工作,但不愿意花时间学习提高自己的技能。不会编程,程序员的工作和你…
&h2&一、排序的基本概念和分类&/h2&&p&所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。&/p&&p&&strong&排序的稳定性:&/strong&&br&经过某种排序后,如果两个记录序号同等,且两者在原无序记录中的先后秩序依然保持不变,则称所使用的排序方法是稳定的,反之是不稳定的。&/p&&p&&strong&内排序和外排序&/strong&&br&内排序:排序过程中,待排序的所有记录全部放在内存中&br&外排序:排序过程中,使用到了外部存储。&br&通常讨论的都是内排序。&/p&&p&&strong&影响内排序算法性能的三个因素&/strong&:&/p&&ul&&li&时间复杂度:即时间性能,高效率的排序算法应该是具有尽可能少的关键字比较次数和记录的移动次数&/li&&li&空间复杂度:主要是执行算法所需要的辅助空间,越少越好。&/li&&li&算法复杂性。主要是指代码的复杂性。&/li&&/ul&&p&&strong&根据排序过程中借助的主要操作,可把内排序分为:&/strong&&/p&&ul&&li&插入排序&/li&&li&交换排序&/li&&li&选择排序&/li&&li&归并排序&/li&&/ul&&p&&strong&按照算法复杂度可分为两类:&/strong&&/p&&ul&&li&简单算法:包括冒泡排序、简单选择排序和直接插入排序&/li&&li&改进算法:包括希尔排序、堆排序、归并排序和快速排序&/li&&/ul&&p&&strong&以下的七种排序算法只是所有排序算法中最经典的几种,不代表全部。&/strong&&/p&&h2&二、 冒泡排序&/h2&&p&冒泡排序(Bubble sort):时间复杂度O(n^2)&br&交换排序的一种。其核心思想是:&strong&两两比较相邻记录的关键字,如果反序则交换,直到没有反序记录为止。&/strong&&/p&&p&其实现细节可以不同,比如下面3种:&/p&&ol&&li&最简单排序实现:bubble_sort_simple&/li&&li&冒泡排序:bubble_sort&/li&&li&改进的冒泡排序:bubble_sort_advance&/li&&/ol&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
# 冒泡排序算法
class SQList:
def __init__(self, lis=None):
self.r = lis
def swap(self, i, j):
&&&定义一个交换元素的方法,方便后面调用。&&&
temp = self.r[i]
self.r[i] = self.r[j]
self.r[j] = temp
def bubble_sort_simple(self):
最简单的交换排序,时间复杂度O(n^2)
lis = self.r
length = len(self.r)
for i in range(length):
for j in range(i+1, length):
if lis[i] & lis[j]:
self.swap(i, j)
def bubble_sort(self):
冒泡排序,时间复杂度O(n^2)
lis = self.r
length = len(self.r)
for i in range(length):
j = length-2
while j &= i:
if lis[j] & lis[j+1]:
self.swap(j, j+1)
def bubble_sort_advance(self):
冒泡排序改进算法,时间复杂度O(n^2)
设置flag,当一轮比较中未发生交换动作,则说明后面的元素其实已经有序排列了。
对于比较规整的元素集合,可提高一定的排序效率。
lis = self.r
length = len(self.r)
flag = True
while i & length and flag:
flag = False
j = length - 2
while j &= i:
if lis[j] & lis[j + 1]:
self.swap(j, j + 1)
flag = True
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4,1,7,3,8,5,9,2,6])
# sqlist.bubble_sort_simple()
# sqlist.bubble_sort()
sqlist.bubble_sort_advance()
print(sqlist)
&/code&&/pre&&/div&&h2&三、简单选择排序&/h2&&p&简单选择排序(simple selection sort):时间复杂度O(n^2)&br&通过n-i次关键字之间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1&=i&=n)个记录进行交换。&/p&&p&通俗的说就是,对尚未完成排序的所有元素,从头到尾比一遍,记录下最小的那个元素的下标,也就是该元素的位置。再把该元素交换到当前遍历的最前面。其效率之处在于,每一轮中比较了很多次,但只交换一次。因此虽然它的时间复杂度也是O(n^2),但比冒泡算法还是要好一点。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
# 简单选择排序
class SQList:
def __init__(self, lis=None):
self.r = lis
def swap(self, i, j):
&&&定义一个交换元素的方法,方便后面调用。&&&
temp = self.r[i]
self.r[i] = self.r[j]
self.r[j] = temp
def select_sort(self):
简单选择排序,时间复杂度O(n^2)
lis = self.r
length = len(self.r)
for i in range(length):
minimum = i
for j in range(i+1, length):
if lis[minimum] & lis[j]:
minimum = j
if i != minimum:
self.swap(i, minimum)
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4, 1, 7, 3, 8, 5, 9, 2, 6, 0])
sqlist.select_sort()
print(sqlist)
&/code&&/pre&&/div&&h2&四、直接插入排序&/h2&&p&直接插入排序(Straight Insertion Sort):时间复杂度O(n^2)&br&基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
# 直接插入排序
class SQList:
def __init__(self, lis=None):
self.r = lis
def insert_sort(self):
lis = self.r
length = len(self.r)
# 下标从1开始
for i in range(1, length):
if lis[i] & lis[i-1]:
temp = lis[i]
while lis[j] & temp and j &= 0:
lis[j+1] = lis[j]
lis[j+1] = temp
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4, 1, 7, 3, 8, 5, 9, 2, 6, 0])
sqlist.insert_sort()
print(sqlist)
&/code&&/pre&&/div&&p&该算法需要一个记录的辅助空间。最好情况下,当原始数据就是有序的时候,只需要一轮对比,不需要移动记录,此时时间复杂度为O(n)。然而,这基本是幻想。&/p&&h2&五、希尔排序&/h2&&p&希尔排序(Shell Sort)是插入排序的改进版本,其核心思想是将原数据集合分割成若干个子序列,然后再对子序列分别进行直接插入排序,使子序列基本有序,最后再对全体记录进行一次直接插入排序。&/p&&p&这里最关键的是跳跃和分割的策略,也就是我们要怎么分割数据,间隔多大的问题。通常将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。下面的例子中通过:increment = int(increment/3)+1来确定“增量”的值。&/p&&p&希尔排序的时间复杂度为:O(n^(3/2))&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
# 希尔排序
class SQList:
def __init__(self, lis=None):
self.r = lis
def shell_sort(self):
&&&希尔排序&&&
lis = self.r
length = len(lis)
increment = len(lis)
while increment & 1:
increment = int(increment/3)+1
for i in range(increment+1, length):
if lis[i] & lis[i - increment]:
temp = lis[i]
j = i - increment
while j &= 0 and temp & lis[j]:
lis[j+increment] = lis[j]
j -= increment
lis[j+increment] = temp
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4, 1, 7, 3, 8, 5, 9, 2, 6, 0,123,22])
sqlist.shell_sort()
print(sqlist)
&/code&&/pre&&/div&&h2&六、堆排序&/h2&&p&堆是具有下列性质的完全二叉树:&br&每个分支节点的值都大于或等于其左右孩子的值,称为大顶堆;&br&每个分支节点的值都小于或等于其做右孩子的值,称为小顶堆;&br&因此,其根节点一定是所有节点中最大(最小)的值。&br&&br&如果按照层序遍历的方式(广度优先)给节点从1开始编号,则节点之间满足如下关系:&/p&&p&堆排序(Heap Sort)就是利用大顶堆或小顶堆的性质进行排序的方法。堆排序的总体时间复杂度为O(nlogn)。(下面采用大顶堆的方式)&/p&&p&其核心思想是:将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆的根节点。将它与堆数组的末尾元素交换,然后将剩余的n-1个序列重新构造成一个大顶堆。反复执行前面的操作,最后获得一个有序序列。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
class SQList:
def __init__(self, lis=None):
self.r = lis
def swap(self, i, j):
&&&定义一个交换元素的方法,方便后面调用。&&&
temp = self.r[i]
self.r[i] = self.r[j]
self.r[j] = temp
def heap_sort(self):
length = len(self.r)
i = int(length/2)
# 将原始序列构造成一个大顶堆
# 遍历从中间开始,到0结束,其实这些是堆的分支节点。
while i &= 0:
self.heap_adjust(i, length-1)
# 逆序遍历整个序列,不断取出根节点的值,完成实际的排序。
j = length-1
while j & 0:
# 将当前根节点,也就是列表最开头,下标为0的值,交换到最后面j处
self.swap(0, j)
# 将发生变化的序列重新构造成大顶堆
self.heap_adjust(0, j-1)
def heap_adjust(self, s, m):
&&&核心的大顶堆构造方法,维持序列的堆结构。&&&
lis = self.r
temp = lis[s]
while i &= m:
if i & m and lis[i] & lis[i+1]:
if temp &= lis[i]:
lis[s] = lis[i]
lis[s] = temp
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4, 1, 7, 3, 8, 5, 9, 2, 6, 0, 123, 22])
sqlist.heap_sort()
print(sqlist)
&/code&&/pre&&/div&&p&堆排序的运行时间主要消耗在初始构建堆和重建堆的反复筛选上。&br&其初始构建堆时间复杂度为O(n)。&br&正式排序时,重建堆的时间复杂度为O(nlogn)。&br&所以堆排序的总体时间复杂度为O(nlogn)。&/p&&p&堆排序对原始记录的排序状态不敏感,因此它无论最好、最坏和平均时间复杂度都是O(nlogn)。在性能上要好于冒泡、简单选择和直接插入算法。&/p&&p&空间复杂度上,只需要一个用于交换的暂存单元。但是由于记录的比较和交换是跳跃式的,因此,堆排序也是一种不稳定的排序方法。&/p&&p&此外,由于初始构建堆的比较次数较多,堆排序不适合序列个数较少的排序工作。&/p&&h2&七、归并排序&/h2&&p&归并排序(Merging Sort):建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
# 归并排序
class SQList:
def __init__(self, lis=None):
self.r = lis
def swap(self, i, j):
&&&定义一个交换元素的方法,方便后面调用。&&&
temp = self.r[i]
self.r[i] = self.r[j]
self.r[j] = temp
def merge_sort(self):
self.msort(self.r, self.r, 0, len(self.r)-1)
def msort(self, list_sr, list_tr, s, t):
temp = [None for i in range(0, len(list_sr))]
if s == t:
list_tr[s] = list_sr[s]
m = int((s+t)/2)
self.msort(list_sr, temp, s,
self.msort(list_sr, temp, m+1, t)
self.merge(temp, list_tr, s, m, t)
def merge(self, list_sr, list_tr, i, m,
while i &= m and j &= n:
if list_sr[i] & list_sr[j]:
list_tr[k] = list_sr[i]
list_tr[k] = list_sr[j]
if i &= m:
for l in range(0, m-i+1):
list_tr[k+l] = list_sr[i+l]
if j &= n:
for l in range(0, n-j+1):
list_tr[k+l] = list_sr[j+l]
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4, 1, 7, 3, 8, 5, 9, 2, 6, 0, 12, 77, 34, 23])
sqlist.merge_sort()
print(sqlist)
&/code&&/pre&&/div&&p&另外一个版本:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def merge(lfrom, lto, low, mid, high):
两段需要归并的序列从左往右遍历,逐一比较,小的就放到
lto里去,lfrom下标+1,lto下标+1,然后再取,再比,再放,
最后lfrom里的两段比完了,lto里留下的就是从小到大排好的一段。
:param lfrom: 原来的列表
:param lto: 缓存的列表
:param low: 左边一段的开头下标
:param mid: 左右两段的中间相隔的下标
:param high: 右边一段的最右下标
i, j, k = low, mid, low
while i & mid and j & high:
if lfrom[i] &= lfrom[j]:
lto[k] = lfrom[i]
lto[k] = lfrom[j]
while i & mid:
lto[k] = lfrom[i]
while j & high:
lto[k] = lfrom[j]
def merge_pass(lfrom, lto, llen, slen):
用来处理所有需要合并的段,这需要每段的长度,以及列表的总长。
最后的if语句处理表最后部分不规则的情况。
:param lfrom: 原来的列表
:param lto: 缓存的列表
:param llen: 列表总长
:param slen: 每段的长度
while i+2*slen & llen:
merge(lfrom, lto, i, i+slen, i+2*slen)
i += 2*slen
if i+slen & llen:
merge(lfrom, lto, i, i+slen, llen)
for j in range(i, llen):
lto[j] = lfrom[j]
def merge_sort(lst):
先安排一个同样大小的列表,作为辅助空间。
然后在两个列表直接做往复的归并,每归并一次slen的长度增加一倍,
逐渐向llen靠拢,当slen==llen时说明归并结束了。
归并完成后最终结果可能恰好保存在templist里,因此代码里做两次归并,
保证最后的结果体现在原始的lst列表里。
:param lst: 要排序的原始列表
slen, llen = 1, len(lst)
templist = [None]*llen
while slen & llen:
merge_pass(lst, templist, llen, slen)
merge_pass(templist, lst, llen, slen)
&/code&&/pre&&/div&&ul&&li&归并排序对原始序列元素分布情况不敏感,其时间复杂度为O(nlogn)。&/li&&li&&p&归并排序在计算过程中需要使用一定的辅助空间,用于递归和存放结果,因此其空间复杂度为O(n+logn)。&/p&&/li&&li&&p&归并排序中不存在跳跃,只有两两比较,因此是一种稳定排序。&/p&&/li&&/ul&&p&总之,归并排序是一种比较占用内存,但效率高,并且稳定的算法。&/p&&h2&八、快速排序&/h2&&p&快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一。冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为O(nlog(n))。&/p&&p&快速排序算法的核心思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,然后分别对这两部分继续进行排序,以达到整个记录集合的排序目的。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Liu Jiang
# Python 3.5
# 快速排序
class SQList:
def __init__(self, lis=None):
self.r = lis
def swap(self, i, j):
&&&定义一个交换元素的方法,方便后面调用。&&&
temp = self.r[i]
self.r[i] = self.r[j]
self.r[j] = temp
def quick_sort(self):
&&&调用入口&&&
self.qsort(0, len(self.r)-1)
def qsort(self, low, high):
&&&递归调用&&&
if low & high:
pivot = self.partition(low, high)
self.qsort(low, pivot-1)
self.qsort(pivot+1, high)
def partition(self, low, high):
快速排序的核心代码。
其实就是将选取的pivot_key不断交换,将比它小的换到左边,将比它大的换到右边。
它自己也在交换中不断变换自己的位置,直到完成所有的交换为止。
但在函数调用的过程中,pivot_key的值始终不变。
:param low:左边界下标
:param high:右边界下标
:return:分完左右区后pivot_key所在位置的下标
lis = self.r
pivot_key = lis[low]
while low & high:
while low & high and lis[high] &= pivot_key:
self.swap(low, high)
while low & high and lis[low] &= pivot_key:
self.swap(low, high)
return low
def __str__(self):
for i in self.r:
ret += & %s& % i
return ret
if __name__ == '__main__':
sqlist = SQList([4, 1, 7, 3, 8, 5, 9, 2, 6, 0, 123, 22])
sqlist.quick_sort()
print(sqlist)
&/code&&/pre&&/div&&p&另外一个版本:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def quick_sort(nums):
# 封装一层的目的是方便用户调用
def qsort(lst, begin, end):
if begin &= end:
key = lst[begin]
for j in range(begin+1, end+1):
if lst[j] & key:
lst[i], lst[j] = lst[j], lst[i]
lst[begin], lst[i] = lst[i], lst[begin]
qsort(lst, begin, i-1)
qsort(lst,i+1,end)
qsort(nums, 0, len(nums)-1)
&/code&&/pre&&/div&&ul&&li&快速排序的时间性能取决于递归的深度。&/li&&li&当pivot_key恰好处于记录关键码的中间值时,大小两区的划分比较均衡,接近一个平衡二叉树,此时的时间复杂度为O(nlog(n))。&/li&&li&当原记录集合是一个正序或逆序的情况下,分区的结果就是一棵斜树,其深度为n-1,每一次执行大小分区,都要使用n-i次比较,其最终时间复杂度为O(n^2)。&/li&&li&在一般情况下,通过数学归纳法可证明,快速排序的时间复杂度为O(nlog(n))。&/li&&li&但是由于关键字的比较和交换是跳跃式的,因此,快速排序是一种不稳定排序。&/li&&li&同时由于采用的递归技术,该算法需要一定的辅助空间,其空间复杂度为O(logn)。&/li&&/ul&&p&下面是一个实例测试数据:&/p&测试数据量(个)0冒泡0.s--反序冒泡0.s--快速排序0....536.36~6.56s&p&从数据中可见:&/p&&ul&&li&数据过万,冒泡算法基本不可用。测试时间忠实的反映了n平方的时间复杂度,数据扩大10倍,耗时增加100倍&/li&&li&对于Python的列表,反序遍历比正序遍历还是要消耗一定的时间的&/li&&li&快速排序在数据较大时,其威力显现,但不够稳定,总体还是维护了nlog(n)的复杂度。&/li&&/ul&&p&&strong&基本的快速排序还有可以优化的地方:&/strong&&/p&&h3&1. 优化选取的pivot_key&/h3&&p&前面我们每次选取pivot_key的都是子序列的第一个元素,也就是lis[low],这就比较看运气。运气好时,该值处于整个序列的靠近中间值,则构造的树比较平衡,运气比较差,处于最大或最小位置附近则构造的树接近斜树。&br&为了保证pivot_key选取的尽可能适中,采取选取序列左中右三个特殊位置的值中,处于中间值的那个数为pivot_key,通常会比直接用lis[low]要好一点。在代码中,在原来的pivot_key = lis[low]这一行前面增加下面的代码:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&m = low + int((high-low)/2)
if lis[low] & lis[high]:
self.swap(low, high)
if lis[m] & lis[high]:
self.swap(high, m)
if lis[m] & lis[low]:
self.swap(m, low)
&/code&&/pre&&/div&&p&如果觉得这样还不够好,还可以将整个序列先划分为3部分,每一部分求出个pivot_key,再对3个pivot_key再做一次上面的比较得出最终的pivot_key。这时的pivot_key应该很大概率是一个比较靠谱的值。&/p&&h3&2. 减少不必要的交换&/h3&&p&原来的代码中pivot_key这个记录总是再不断的交换中,其实这是没必要的,完全可以将它暂存在某个临时变量中,如下所示:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def partition(self, low, high):
lis = self.r
m = low + int((high-low)/2)
if lis[low] & lis[high]:
self.swap(low, high)
if lis[m] & lis[high]:
self.swap(high, m)
if lis[m] & lis[low]:
self.swap(m, low)
pivot_key = lis[low]
# temp暂存pivot_key的值
temp = pivot_key
while low & high:
while low & high and lis[high] &= pivot_key:
# 直接替换,而不交换了
lis[low] = lis[high]
while low & high and lis[low] &= pivot_key:
lis[high] = lis[low]
lis[low] = temp
return low
&/code&&/pre&&/div&&h3&3. 优化小数组时的排序&/h3&&p&快速排序算法的递归操作在进行大量数据排序时,其开销能被接受,速度较快。但进行小数组排序时则不如直接插入排序来得快,也就是杀鸡用牛刀,未必就比菜刀来得快。&br&因此,一种很朴素的做法就是根据数据的多少,做个使用哪种算法的选择而已,如下改写qsort方法:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def qsort(self, low, high):
&&&根据序列长短,选择使用快速排序还是简单插入排序&&&
# 7是一个经验值,可根据实际情况自行决定该数值。
MAX_LENGTH = 7
if high-low & MAX_LENGTH:
if low & high:
pivot = self.partition(low, high)
self.qsort(low, pivot - 1)
self.qsort(pivot + 1, high)
# insert_sort方法是我们前面写过的简单插入排序算法
self.insert_sort()
&/code&&/pre&&/div&&h3&4. 优化递归操作&/h3&&p&可以采用尾递归的方式对整个算法的递归操作进行优化,改写qsort方法如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def qsort(self, low, high):
&&&根据序列长短,选择使用快速排序还是简单插入排序&&&
# 7是一个经验值,可根据实际情况自行决定该数值。
MAX_LENGTH = 7
if high-low & MAX_LENGTH:
# 改用while循环
while low & high:
pivot = self.partition(low, high)
self.qsort(low, pivot - 1)
# 采用了尾递归的方式
low = pivot + 1
# insert_sort方法是我们前面写过的简单插入排序算法
self.insert_sort()
&/code&&/pre&&/div&&h2&九、排序算法总结&/h2&&p&排序算法的分类:&/p&&p&没有十全十美的算法,有有点就会有缺点,即使是快速排序算法,也只是整体性能上的优越,也存在排序不稳定,需要大量辅助空间,不适于少量数据排序等缺点。&/p&&p&&strong&七种排序算法性能对比&/strong&&/p&&ul&&li&如果待排序列基本有序,请直接使用简单的算法,不要使用复杂的改进算法。&/li&&li&归并排序和快速排序虽然性能高,但是需要更多的辅助空间。其实就是用空间换时间。&/li&&li&待排序列的元素个数越少,就越适合用简单的排序方法;元素个数越多就越适合用改进的排序算法。&/li&&li&简单选择排序虽然在时间性能上不好,但它在空间利用上性能很高。特别适合,那些数据量不大,每条数据的信息量又比较多的一类元素的排序。&/li&&/ul&&br&&p&文章素材来源【开源中国社区】&a href=&/?target=https%3A//my.oschina.net/u/3346994/blog/895131& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&基于python的七种经典排序算法 - 舒运&i class=&icon-external&&&/i&&/a&&/p&
一、排序的基本概念和分类所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序的稳定性: 经过某种排序后,如果两个记录序号同等,且两者在原无序记录中的先后…
&img src=&/50/v2-ad60c90ff5f115d41451fcdd_b.jpg& data-rawwidth=&1271& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1271& data-original=&/50/v2-ad60c90ff5f115d41451fcdd_r.jpg&&&blockquote&&p&这是the5fire总结出来的Python程序员或者程序员的进阶之道——零到入门,入门到初级,初级到中级,中级到高级。仅供参考&/p&&/blockquote&&h2&前言&/h2&&p&上次在群里有同学又在问基础的问题,我不反感基础问题,就是比较反感不动脑子就贴图出来求解答的问题。有时我干脆不说话,有时我会给个地方让他去搜索。前两天突然冒出个想法,始终有一部分人会花费大量时间在低水平的重复上,得不到进阶的法门。于是我冒出一句:“Python进阶最简单的方式:搞清楚你所写代码文件的每一行,每一个字符的意义。”&/p&&p&相对于推荐几本进阶的书籍(&a href=&/?target=https%3A//mp./s%3F__biz%3DMjM5NjA3Nzk3Ng%3D%3D%26mid%3D%26idx%3D1%26sn%3Df2a14d61fbd3aac6f379c%26chksm%3Dbecdc9bb89ba40adb6c8d46d35497eda15a2ff966abcf73ff338b5frd& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python基础看完了?来两本进阶书&i class=&icon-external&&&/i&&/a&)来说,能够自行且有效的去找“食物”是更为重要的事情。&/p&&h2&理论&/h2&&p&在the5fire刚来北京,还是一个人住的时候,每次搬家到一个新的地方,都会在下班之后或者周末的时候,徒步把周围转上一转(溜达溜达)。然后看看地图。对自己所在的方位有一个大概的印象。有时候一转就是几个小时。溜达的目的很简单,我需要了解我周围的生活设施,环境,各种方位的路线。另外还有一个点就是满足我的好奇心,那些未知的地点和环境,总比已知的来的有趣。&/p&&p&现在我就在想,如果把这个类比到Python的学习中或者任何语言/技能的学习中,是不是合理。&/p&&p&拿Python来说,假设我是个新手。刚看了《Python基础编程》或者任何其他的基础书籍,然后能把书上的代码敲下来(注意!是敲下来,不是找个地方copy下来),运行了一下,发现能输出结果,跟书上一样。那么ok,这本书你熟悉的书就是你的“新家”,首先要做的事是熟悉你的“新家”。the5fire在很多文章中都说过,基础的书籍看完一本,然后就做练习,写代码。再看其他的基础书籍是无益的。所有的练习都是为了让你掌握书中的知识,掌握书上提到的,只是刚开始。&/p&&p&比方说,书上说了,敲下如下代码到hello.py文件中,然后python hello.py,得到正确的输出,说明你熟悉了print用法了。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# coding:utf-8
print(u'你好世界')
&/code&&/pre&&/div&&p&然后你开始看下一章。练习for循环的使用,输出10此“你好世界”:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&for i in range(10):
print(u'你好世界')
&/code&&/pre&&/div&&p&报错了。然后截图贴群里。迎接你的可能是石沉大海。对比下来你可能会发现只是少了第一行的# coding:utf-8,那么,这是为什么呢?&/p&&p&实际上,在写多个代码的时候,我们应该意识到自己在写的是什么东西,我们往某个文件里写上一些文字/字符,然后用python &文件名&,刚好能跑,好巧!那我再写下一个文件,刚好出错。&/p&&p&所以我说:进阶最简单的方式,就是搞明白你写的每个字符的意义/作用。那怕只是一个helloworld.py,你搞明白这一些后,会比那些已经学到了文件操作部分的人更了解Python,并且在后面会踩更少的坑。&/p&&p&好了,the5fire来总结下理论部分:从熟悉的地方中找到陌生的东西,然后搞懂,慢慢往外延伸,可能会比较吃力,但是哪有好走的捷径?&/p&&h2&下面分阶段来说下&/h2&&p&the5fire根据自己经验总结,仅供参考&/p&&p&这里只说初学者和工作一两年的同学&/p&&h3&初学者&/h3&&p&初学者指刚看了些语法,让程序碰巧可以跑起来的那些人。看了一些书,写了一些程序,但是实际经验缺乏。&/p&&p&对于这个阶段的同学来说,最好的进阶之道就是自己仔细review下你写的所有项目,找出一个觉得比较有意思的,研究透。比方说那本基础教程中的十个例子(其中有一些比较老,可以忽略),把所有涉及的内容都看下,还是那句话,了解作者/你自己写的每行代码的含义,之后尝试把项目扩展,看能不能让别人使用。&/p&&p&这个时候,你会开始考虑,怎么合理的把代码打包,然后发给室友或者朋友,让你的代码跑在他们的机器上?你可能会去搜索:如何打包python项目,或者如何把python项目打包成exe(如果你用windows的话,当然,我是不建议一直在windows学Python的,这样会找不到工作的)。&/p&&p&搞定打包之后,室友说你这个程序太垃圾,一运行就挂。这时你可能会想“我要怎么记录程序运行到哪了挂了呢”,你会找到logging模块的使用方法。&/p&&p&以此类推吧。你知识的边界仅仅通过一个项目就可以扩展的很大,大到能够满足你去找一份工作。&/p&&h3&初级工程师&/h3&&p&工作一两年的同学,暂且定为初级工程师吧。当然,我了解的实际情况是,始终会有人即便工作(正式使用Python讨饭吃)时间不长,在意识上也能够领先那些工作多年的人很多。人跟人的情况还是不同的。&/p&&p&这个阶段的同学,在生产环境中用了Python很久了,熟悉每天的日常工作。每天都想搞点事情出来,然后在github上赚star。(好吧,我承认我是在说我自己)。&/p&&p&初级工程师的工作一般是上级分派下来的,一个系统的某个模块。一开始很happy的coding,然后提交代码,被review,被吐槽———— 长此以往,终于提交代码时不再需要重新改很多次了。慢慢的,觉得不就是几个亿访问量的系统吗,你看,我也在维护呢,没让它挂过。然后沉溺在自己的熟悉的代码中。&/p&&p&对于这个阶段的工程师来说,进阶的方式很简单,因为Ta已经在生产环境中了,是其中的一个环节(其实理解为一个螺丝钉也未尝不可),Ta需要做的事情是熟悉自己每天维护的项目中从来不属于自己的部分。很多人都不愿意去开发、维护不是自己做的东西,除非那个同事离职,然后把项目交接给Ta。&/p&&p&日常工作中,我们经常能看到这样的例子,同一时间进入公司的两个人或者几个人,刚来的时候技术都差不多,但是过段时间你就会更想把重要的活儿派给其中一个。&/p&&p&作为一个螺丝钉,就得有螺丝钉的觉悟,知道自己的可替代性。我把所有的系统都比喻做数据的搬运工/整理员,你需要了解你所处理的数据的上下游,还有整个系统的全貌。&/p&&p&精通你现在维护的系统,以及上下游,是这个阶段进阶的更好的方式,当然也不是说不要搞业余的项目,主要看你侧重点在哪。&/p&&p&在工作多年后,我曾经回顾过我在工作两年的时候所做的一些事,要是能有人给我讲这些,我可能会成长的更快。&/p&&h2&总结&/h2&&p&就写这些吧,其他的几个阶段都是一样,从熟悉的地方出发,看看未知的环境。开阔下自己的视野,扩展下自己的知识边界。&/p&&p&《道德经》中讲:道生一,一生二,二生三,三生万物。所有的事物/系统都不是一蹴而成的,经过不断的演变,呈现现在的样子。但是原理/理论是相通的。&/p&&br&----EOF----- &br&&br&扫码关注,或者搜索微信公众号:码农悟凡
这是the5fire总结出来的Python程序员或者程序员的进阶之道——零到入门,入门到初级,初级到中级,中级到高级。仅供参考前言上次在群里有同学又在问基础的问题,我不反感基础问题,就是比较反感不动脑子就贴图出来求解答的问题。有时我干脆不说话,有时我会…
&img src=&/50/v2-076e3caed758a1c18c91a0e9cae3368f_b.jpg& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/50/v2-076e3caed758a1c18c91a0e9cae3368f_r.jpg&&&ul&&li&&a href=&/?target=http%3A///wiki/095c955c1e6d8bbfac& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&小白Python教程&i class=&icon-external&&&/i&&/a&,&a href=&/?target=http%3A///wiki/958fa6d3a2e542c000& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python3中文教程&i class=&icon-external&&&/i&&/a&,&a href=&/?target=https%3A///youfou/liaoxuefeng-tutorials& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&电子版&i class=&icon-external&&&/i&&/a&, 廖雪峰的小白python教程,有python2和python3两个版本:&/li&&li&&a href=&/?target=https%3A///onion7878/A-Byte-of-Python-CN/tree/master/book& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&简明Python教程&i class=&icon-external&&&/i&&/a&,简明python教程,是《A Byte of Python》的中文版&/li&&li&&a href=&/?target=https%3A///book/looly/python-basic/details& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&零基础学Python&i class=&icon-external&&&/i&&/a&,老齐(qiwsir)的Python基础教程Gitbook版&/li&&li&&a href=&/?target=http%3A//lovelypython.readthedocs.org/en/latest/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&可爱的 Python &i class=&icon-external&&&/i&&/a&,大妈(Zoom.Quiet)创意并组建团队,完全由 CPyUG 成员自发组织完成。&/li&&li&&a href=&/?target=http%3A///pythontutorial27/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python 2.7 官方教程中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A///pythontutorial3/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python 3.3 官方教程中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=https%3A///yidao620c/python3-cookbook& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Python Cookbook》 3rd Edition中文版&i class=&icon-external&&&/i&&/a&:注重实践的一本书,但不适合初学者。&/li&&li&&a href=&/?target=http%3A//old.sebug.net/paper/books/dive-into-python3/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&深入 Python 3&i class=&icon-external&&&/i&&/a&:《dive into python3》的中译版。&/li&&li&&a href=&/?target=https%3A///p/zhong-wiki/wiki/PEP8& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PEP8 Python代码风格规范&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//zh-google-styleguide.readthedocs.org/en/latest/google-python-styleguide/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Google Python 风格指南 中文版&i class=&icon-external&&&/i&&/a&,写python的人都应该遵循的原则。&/li&&li&&a href=&/?target=http%3A//lovelypython.readthedocs.org/en/latest/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&可爱的 Python&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A///pythontutorial27/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python 2.7 官方教程中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A///pythontutorial3/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python 3.3 官方教程中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A///thinkphp/python-cookbook& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python Cookbook 中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=https%3A///yidao620c/python3-cookbook& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python3 Cookbook 中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A///docs/diveintopythonzh-cn-5.4b/html/toc/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&深入 Python&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//old.sebug.net/paper/books/dive-into-python3/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&深入 Python 3&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=https%3A///p/zhong-wiki/wiki/PEP8& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PEP8 Python代码风格规范&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//zh-google-styleguide.readthedocs.org/en/latest/google-python-styleguide/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Google Python 风格指南 中文版&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//liam0205.me//Python-tutorial-zh_cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python入门教程&i class=&icon-external&&&/i&&/a& (&a href=&/?target=http%3A//liam0205.me/attachment/Python/The_Python_Tutorial_zh-cn.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PDF&i class=&icon-external&&&/i&&/a&)&/li&&li&&a href=&/?target=http%3A//article.yeeyan.org/view/706& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python的神奇方法指南&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//old.sebug.net/paper/books/LearnPythonTheHardWay/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&笨办法学 Python&i class=&icon-external&&&/i&&/a& (&a href=&/?target=http%3A//liam0205.me/attachment/Python/PyHardWay/Learn_Python_The_Hard_Way_zh-cn.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PDF&i class=&icon-external&&&/i&&/a&版下载)&/li&&li&&a href=&/?target=http%3A///s/1qW4pvnY& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python自然语言处理中文版&i class=&icon-external&&&/i&&/a& (感谢陈涛同学的翻译,也谢谢 &a href=&/?target=https%3A///shwley& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&@shwley&i class=&icon-external&&&/i&&/a& 联系了作者)&/li&&li&&a href=&/?target=http%3A//liam0205.me//matplotlib-tutorial-zh-cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python 绘图库 matplotlib 官方指南中文翻译&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//scrapy-chs.readthedocs.org/zh_CN/latest/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Scrapy 0.25 文档&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=https%3A///carfly/thinkpython-cn& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ThinkPython&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=https%3A///bingjin/ThinkPython2-CN& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ThinkPython 2ed&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A///vamei/archive//2682778.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python快速教程&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&/?target=http%3A//wiki./Python%25E6%25AD%25A3%25E5%E8%25A1%25A8%25E8%25BE%25BE%25E5%25BC%258F%25E6%E4%25BD%259C%25E6%258C%%258D%2597& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python 正则表达式操作指

我要回帖

更多关于 textgrocery视频 的文章

 

随机推荐