├── DeliberatePracticeNotes └── 需要刻意练习的技能有哪些?.md ├── README.md ├── articles_of_coding_learning ├── 20190307_我不是技术岗,只是学了点编程.md ├── 20190315_Github进行fork后如何与原仓库同步.md ├── 20190710_有个运营妹纸心算找不到数独答案,心一横干脆写代码实现.md ├── 20190728_李笑来会用python写程序统计词频,你会吗?.md ├── 20190804_35岁有儿有女,为什么她开始自学编程?.md ├── 20190804_不懂即搜,如何用 python 读取 api 并借用文件读写数据?.md ├── 20190807_自学 python 编程,学完新的又忘旧的,该怎么办?.md ├── 20190808_谁能想到问题居然出在这里.md ├── 20190808_这道题,我不会解——关于windows环境.md ├── 20190808_适合新手的 python pandas 学习笔记(1).md ├── 20190809_适合新手的 python pandas 学习笔记(2).md ├── 20190812_30多岁想转行,零基础学编程,来得及吗?能找到功好工作吗?.md ├── 20190816_零基础自学 python3 的最少必要资源(极简推荐).md ├── 20190820_老婆说我自学 python 是不务正业.md ├── 20190905_对目标网站 7 天内发起百万次 api 请求,是攻击还是正常请求?.md ├── 20190905_手动生成 N 个爬虫太低效,用 python 实现批量生成多个文件构建爬虫群.md ├── 20190910_pandas数据分析输出excel产生文本形式存储的百分比数据,如何处理?.md ├── 20190911_pandas.to_sql()失败,提示 pandas.io.sql.DatabaseError1146表格不存在的解决办法.md ├── 20190911_win10 设定计划任务时提示所指定的账户名称无效,如何解决?.md ├── 20190911_windows 10 如何设定计划任务自动执行 python 脚本?.md ├── 20190911_用 python 写个小爬虫监控某人的 CSDN 文章数据.md ├── 20190912_python 字符串替换功能 string.replace()可以用正则表达式,更优雅.md ├── 20190927_整理总结我如何在python中实现与mysql的数据交互及常用sql语句.md ├── 20190928_整理总结 python 中时间日期类数据处理与类型转换(含 pandas).md ├── 20191009_24H玩转 Grafana 被工程师称相当专业,如何做到?.md ├── 20191012_能写数据后台,需要掌握哪些进阶的sql语句?.md ├── 20191016_小结 python 实战中遇到的几种需要化名的情境.md ├── 20191023_数据分析师如何自力更生统计用户行为频次?.md ├── 20191024_mysql 数据分析如何实现日报、周报、月报和年报?.md ├── 20191024_告别硬编码,mysql 如何实现按某字段的不同取值进行统计.md ├── 20191109_闯缸鱼:看懂python如何实现整数加和,再决定是否自学编程.md ├── 20191110_Python 刷题笔记:math.floor() 的用法.md ├── 20191110_Python 刷题笔记:这很不python,官方大大能改下吗?.md ├── 20191110_python刷题笔记:内建函数 getattr与setattr.md ├── 20191110_刷题翻车:python 布尔运算操作符的优先级.md ├── 20191110_和35岁刘阿姨一起自测 Python 流程控制基本功.md ├── 20191120_grafana 连接mysql 和 postgresql,如何查看数据库所有表格及表格字段?.md ├── 20191127_如何批量添加中文和英文数字之间的空格?用正则表达式吧.md └── readme.md ├── code_of_practise ├── cipin.py ├── creat_todo_list_from_sample.py └── spider_crawler_csdn_user_homepage.py ├── file_sample └── afiledata.txt ├── homework ├── homework_A.md ├── homework_B.md ├── homework_C.md ├── homework_X.py ├── homework_sample │ ├── boolean.py │ ├── file.py │ ├── list.py │ └── string.py └── testyourself │ ├── test_yourself_001.py │ └── test_yourself_001.txt └── test-for-you.md /DeliberatePracticeNotes/需要刻意练习的技能有哪些?.md: -------------------------------------------------------------------------------- 1 | # 需要刻意练习的技能有哪些? 2 | 3 | ## 通用技能 4 | 5 | - 写作 6 | - 写文章 7 | - 写深度好文 8 | - 写书 9 | - 写长销书/畅销书 10 | - 写多本长销书/畅销书 11 | 12 | > 我写书就是这样的。在准备的过程中 —— 这个过程比绝大多数人想象得长很多 —— 我会罗列所有我能想到的相关话题…… 等我觉得已经再也没有什么可补充的时候,再为这些话题写上几句话构成的大纲…… 这时候就会发现很多话题其实应该是同一个话题。如此这般,一次扩张,一次搜索之后,就会进行下一步,应用 MoSCow 原则,给这些话题打上标签 —— 在这过程中,总是发现很多之前感觉必要的话题,其实可以打上 Won't have 的标签,于是,把它们剔除,然后从 Must have 开始写起,直到 Should have,至于 Could have 看时间是否允许,看情况,比如,看有没有最后期限限制…… 13 | > by 李笑来《自学是门手艺》 14 | 15 | - 沟通 16 | 17 | 18 | - 讲演 19 | 20 | 21 | - 思考 22 | - 独立思考 23 | - 深度思考 24 | 25 | 26 | - 刻意练习 27 | - 刻意思考:这东西我还能用在哪儿呢?(这东西,是你正在刻意练习的某个技能) 28 | 29 | 30 | - 有自己完整的作品,用“全面完整”的原则来对抗“注意力漂移” 31 | - 全面地学 32 | - 完整地做 33 | - 用纸笔罗列整理那些为了做到“全面完整”而必须优先做的事。 34 | 35 | - 融会贯通(跨领域使用) 36 | 37 | > 把另外一个领域里的知识拿过来用,是在一个“没人教、也没人带,甚至没有书籍可供参考”的领域中,最基本的生存技巧。 38 | 39 | 40 | - 英语 41 | 42 | 43 | ## 独立模块的小技能 44 | 45 | - 采用 google 搜索的技能 46 | - 能 Google 出答案的问题,就不需要去麻烦别人 47 | 48 | 49 | https://www.google.com/search?q=How+to+use+google+effectively 50 | 51 | https://www.lifehack.org/articles/technology/20-tips-use-google-search-efficiently.html 52 | 53 | - 正则表达式 54 | 55 | 56 | - 练习键盘盲打&&输入法方案选择改为微软双拼方案 57 | 58 | 59 | - markdown 语法 60 | 61 | 62 | ## CS基础/编程基础 63 | 64 | - git(如果学,不如学点高档的) 65 | 66 | - 编辑器 67 | - vscode 68 | 69 | - 互联网协议 70 | 71 | - linux shell命令行 72 | 73 | - python 74 | 75 | ## 区块链专家: 76 | 77 | - 研读比特币白皮书 78 | - 反复研读,每年都要重复若干遍。 79 | 80 | - 了解行业内新的信息 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 这是什么? 2 | 3 | you can you up, no bb. 4 | 5 | 6 | # 可能用得上的作业集 7 | 8 | 跟着以下作业,从0开始,一点点来。 9 | 10 | 每次作业,最少1天,最多2天。如果难度超纲,可以自行搜索解决,也请给我反馈。 11 | 12 | 完全0基础,就跟着作业来,刚好完成作业要求即可。时间充裕、精力旺盛,可以超前,自己拓展都OK。很灵活的。 13 | 14 | 下列内容,只是提供作业,并不是提供教学。主要还是依靠自学、并在兴趣小组中互受鼓舞。 15 | 16 | A系列:[准备vscode + github,并熟悉git的最少必要操作。](https://github.com/liujuanjuan1984/ucanuupnobb/blob/master/homework/homework_A.md) 17 | 18 | B系列:[hello python,极简开始的python编程之旅。](https://github.com/liujuanjuan1984/ucanuupnobb/blob/master/homework/homework_B.md) 19 | 20 | 建议记录你在编程这件事上的时间投入,但不做自我评判,单纯记录而已。 21 | 22 | 保持你对编程的好奇心,并呵护你尝试编程的愿望,比什么都重要。试试玩玩看呗! 23 | 24 | 如果你已经启动自学,并解决了一些可能对他人有用的“困难”,欢迎写成简明清晰的教程(或具有“输送价值观”的、完整的作品:文章),并向 本项目 发起 pull request。 25 | 26 | 文件路径: \ucanuupnobb\ourStories\文章标题+你的名字.md 27 | 28 | # 《自学是门手艺》中,哪些值得刻意练习的技能。 29 | 30 | - 采用 google 搜索的技能 31 | 32 | - 正则表达式 33 | 34 | - 刻意思考:这东西我**还**能用在哪儿呢?(这东西,是你正在刻意练习的某个技能) 35 | 36 | - 能 Google 出答案的问题,就不需要去麻烦别人 37 | 38 | - 练习键盘盲打 39 | 40 | - 有自己的完整作品(从写一篇完整的文章开始) 41 | 42 | - 用纸笔罗列整理那些为了做到“全面完整”而必须优先做的事。 43 | 44 | - 用“全面完整”的原则来对抗“注意力漂移”。 45 | 46 | - git(如果学,不如学点高档的) 47 | 48 | 如果你已经刻意练习了以上技能,欢迎向 这个项目 发起 pull request,添加你的练习记录或者感悟心得。 49 | 50 | 文件路径: \ucanuupnobb\DeliberatePracticeNotes\技能名+你的名字.md 51 | 52 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190307_我不是技术岗,只是学了点编程.md: -------------------------------------------------------------------------------- 1 | # 我不是技术岗,只是学了点编程 2 | 3 | 首次读《自学是门手艺》时,我手痒痒,偷时间用 vscode + git 练习,一坐就是两三个小时,如此沉迷几次,玩出来一个自动处理时间开销数据的脚本,顺便把我们团队用来面试程序员的一道 python 题给做了。看了我的代码后,工程师打趣说:你可以来上班了;另一位也颇为乐意鼓励我说:面试时写出这样的代码确实可以考虑招进来。额……我代码读得少,莫哄我转岗。 4 | 5 | 我是一名运营,不是程序员,没有相关的教育或培训经历。2003 年大一首次接触电脑并只必修了 C 语言。2009 年在网易当 QC,主程帮我破冰了很多小到不能再小的知识点,让我学会 linux shell 命令行和 mysql 操作,得以独立胜任在无任何游戏界面的情况下完成游戏战斗系统与合服功能的测试。2011 年在网易内部转岗做策划,主程给我找了一本 python 简明教程,我用一个上午浏览语法规则和全书框架,下午就直接读项目的任务系统脚本,并把代码逻辑转换到 excel 中配表。三个月内,我在搜索引擎和简明教程的帮助下,写了几个子类、一些函数以及很多个游戏脚本,其中包括复杂的场景剧情逻辑。这些代码在主程的把关之下全部提交到项目库并正式上线。这两段职场经历中,我都是拿到就用,边做边学。 6 | 7 | 与立志通过自学成为专职的程序员的人不同,我喜欢编程,但尚未想过把它变成职业。单凭兴趣,我还有两段编程学习经历,一次是 2016 年底刚生二宝,参加新生大学 js 入门课,只是因产后上班颇为辛苦而中断。另一次就是《自学是门手艺》。 8 | 9 | 我是如何使用《自学是门手艺》这本书,如何完成了让大家打趣我水平确实不错的代码呢?8 年前的那三个月用中学的经历或许让我有些常识和印象,但早已模糊。思来想去,大概是因为:我不善于 coding 但善于拆解需求和迭代代码,我不喜欢硬记于是总是用 google 找答案,且总是把《自学是门手艺》和其它参考书放在手边备查。 10 | 11 | 《自学是门手艺》这本书的使用方法是,先囫囵吞枣,其后多次细细咀嚼。部分章节用于自我激励与充能,部分章节用于纲领性地建立起一个编程知识框架。编程不复杂,老师一句话就概括起来一个非常健壮的框架线条: 12 | 13 | > 从结构上来看,一切的计算机程序,都由且只由两个最基本的成分构成: 14 | > - 运算(Evaluatation)、 15 | > - 流程控制(Control Flow)。 16 | 17 | 我初步掌握编程的方法也并没有超出老师所强调的:练习、拆解、搜索这 3 条。以我的实践经验来看,这 3 条也并非孤立,而是同时存在、互相促进。下面以一道简单的题目为例,展示一下我作为初学者是如何以此为契机练习的: 18 | 19 | > 在给出的某篇文章(一份 txt 文件),统计所有字符的出现次数,并按照次数倒序输出。 20 | 21 | 原始需求经横向初步拆解后,变成: 22 | - 需求 1.统计次数, 23 | - 需求 2.按照次数倒序。 24 | 25 | 需求 1 又该如何继续横向拆解呢?统计 1 个字符的出现次数,与统计所有字符的出现次数,后者仅仅是在前者的基础上的一个循环处理。于是就继续拆解为: 26 | 27 | - 需求 1.1 如何统计某个字符的出现次数 28 | - 需求 1.2 一共需要统计哪些字符? 29 | 30 | 如果问题复杂,超出了自己的理解范畴,我就降低问题的复杂程度,然后先写代码实现那个简化版的需求。比如需求 1.1 经纵向拆解后,难度从低到高可以转变为: 31 | 32 | - 需求 1.1.1 统计一个字符串中某个字符出现的次数 33 | - 需求 1.1.2 统计一个列表中某个字符出现的次数 34 | - 需求 1.1.3 统计一个文件中某个字符出现的次数 35 | 36 | 对于初学者来说,文件比列表复杂,列表比字符串复杂,但字符串是基础功。如何处理字符串,初学者能立马通过书本和教程 get 到。虽说文件复杂,但其实一点也不复杂。通过搜索或阅读,你很快就会知道 file.readlines() 可以读取文件返回一个列表,for 循环可以依序处理列表中的每一项,由此打通文件→列表→字符串的路径。 37 | 38 | 并非每次都拆解到基础功,我拆解到自己能掌握的粒度,就开始写代码并运行调试;等这块逻辑通顺了,就写另一块。过程中肯定会遇到困难,我就直接 google 解决办法。带着问题去检索、找到答案、问题解决的这个美妙循环,总是令我一旦编程就停不下来。正因为自己被某个知识点难住,在重读书本的过程中,常常有找到答案的惊喜之感。 39 | 40 | 编程作为一个专业领域,会有很多专有名词。通读《自学是门手艺》全书,熟悉最少必要的专有名词,就能知道大家一般如何称呼,如此将提高准确描述问题的能力并提高检索效率。其实,就连熟悉专有名词这件事,我都不是硬着头皮记忆的。我的专有名词记忆能力实在是差劲,于是我总是把书在手边随时备查,多搜几次就熟悉了。 41 | 42 | 通过练习搜索来精通搜索,通过练习编程来掌握编程。确实没什么新鲜秘诀。 43 | 44 | 这就是我作为一个运营,编程初心者的切身经历。 45 | 46 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190315_Github进行fork后如何与原仓库同步.md: -------------------------------------------------------------------------------- 1 | # Github 进行 fork 后如何与原仓库同步 2 | 3 | 实在是……有太多人同时在帮忙修订错别字或优化 xiaolai 的 `the-craft-of-selfteaching` 了。如果你提交的 pull request 未被接受且得到回复说:“重新 fork”,其实是你遇到一个问题: 4 | 5 | > * 在你 fork 之后, xiaolai 的仓库又更新了; 6 | > * 但 github 不会自动帮你把 xiaolai 的仓库 同步给你 fork 后的仓库; 7 | > * 导致你提交 pull request 时的版本和 xiaolai 的版本不一致。 8 | 9 | 这个问题,用显得更“专业点”的说法,叫做:`Github 进行 fork 后如何与原仓库同步`。那到底怎么做呢? 10 | 11 | 最省事的办法可能是: 12 | 13 | > * 在你 fork 的仓库 setting 页翻到最下方,然后 delete 这个仓库; 14 | > * 然后重新 fork xiaolai 的仓库,并 git clone 到你的本地。 15 | 16 | 有时候,你需要用到这个省事的办法,比如 xiaolai 的仓库再次整理了 commit 。但在更多情况下,删掉自己 fork 的库,应该是你的最后选择,而不应该是首选。 17 | 18 | 和很多人一起向 xiaolai 提交 pull request,这实在是一个反复练习 `merge` (中文说法:合并,或版本合并)的机会。毫不夸张地讲,版本管理是软件工程极其重要的规范,也是极其基础的必备技能。而 `merge` 则是版本管理中最必须也最常用的场景。 19 | 20 | 那要不然,就多练练?以下是傻瓜版操作步骤,还细心配了截图,保管你从 0 也能上手。至于原理嘛,慢慢再搞懂吧。 21 | 22 | ### merge 前的设定 23 | 24 | step 1、进入到本地仓库的目录。 25 | 26 | 下面所有操作,如无特别说明,都是在你的本地仓库的目录下操作。比如我的本地仓库为`/from-liujuanjuan-the-craft-of-selfteaching` 27 | 28 | ![image](https://user-images.githubusercontent.com/31027645/54422899-6938e880-474a-11e9-8768-27ac24673e28.png) 29 | 30 | 31 | step 2、执行命令 `git remote -v` 查看你的远程仓库的路径: 32 | 33 | ![image](https://user-images.githubusercontent.com/31027645/54422975-95ed0000-474a-11e9-96bf-1018d6bc06f2.png) 34 | 35 | 如果只有上面 2 行,说明你未设置 `upstream` (中文叫:上游代码库)。一般情况下,设置好一次 `upstream` 后就无需重复设置。 36 | 37 | step 3、执行命令 `git remote add upstream https://github.com/selfteaching/the-craft-of-selfteaching.git` 把 xiaolai 的仓库设置为你的 `upstream` 。这个命令执行后,没有任何返回信息;所以再次执行命令 `git remote -v` 检查是否成功。 38 | 39 | ![image](https://user-images.githubusercontent.com/31027645/54423107-d8aed800-474a-11e9-9ab8-7bb901181283.png) 40 | 41 | step 4、执行命令 `git status` 检查本地是否有未提交的修改。如果有,则把你本地的有效修改,先从本地仓库推送到你的 github 仓库。最后再执行一次 `git status` 检查本地已无未提交的修改。 42 | 43 | `git add -A` 或者 `git add filename` 44 | `git commit -m "your note"` 45 | `git push origin master` 46 | `git status` 47 | 48 | 注 1:这一步作为新手,建议严格执行,是为了避免大量无效修改或文本冲突带来的更复杂局面。 49 | 50 | 注 2:如果你已经在 fork 后的仓库提交了大量对 xiaolai 的仓库并没有价值的修改,那么想要 pull request,还是重新回到本文最初的“最省事办法”吧。 51 | 52 | 53 | ### merge 的关键命令 54 | 55 | 以下操作紧接着上面的步骤。 56 | 57 | step 5、执行命令 `git fetch upstream` 抓取 xiaolai 原仓库的更新: 58 | 59 | ![image](https://user-images.githubusercontent.com/31027645/54448734-60b2d300-4787-11e9-9fdf-90fcc2e66052.png) 60 | 61 | step 6、执行命令 `git checkout master` 切换到 master 分支: 62 | 63 | ![image](https://user-images.githubusercontent.com/31027645/54448759-6dcfc200-4787-11e9-8bbc-a5beef23ea88.png) 64 | 65 | step 7、执行命令 `git merge upstream/master` 合并远程的 master 分支: 66 | 67 | ![image](https://user-images.githubusercontent.com/31027645/54449526-47128b00-4789-11e9-9add-09217eb91a68.png) 68 | 69 | 70 | step 8、执行命令 `git push ` 把本地仓库向 github 仓库(你 fork 到自己名下的仓库)推送修改 71 | 72 | 如果担心自己不小心改了哪里,可以再次执行命令 `git status` 检查哪些文件有变化。这个操作仅是检查,不会改变任何状态,放心用。 73 | 74 | ![image](https://user-images.githubusercontent.com/31027645/54449665-a07aba00-4789-11e9-9181-bdcc814fffe6.png) 75 | 76 | 77 | 现在你已经解决了 fork 的仓库和原仓库版本不一致的问题。可以放心向 xiaolai 发起 pull request 了。如果以上操作你花了不少时间,而 xiaolai 的仓库 又恰好更新了。很好,一次新的练习机会来了…… 78 | 79 | 补记:这份笔记最初整理于 2019 年 3 月。或许因为我平时 git 操作仅是简单的修改新增,与其它仓库协作少,于是这种上游仓库的设置与同步相关指令需要用时,还是得搜到这篇笔记来看。那就发出来,或许也能帮到其他人吧~ -------------------------------------------------------------------------------- /articles_of_coding_learning/20190710_有个运营妹纸心算找不到数独答案,心一横干脆写代码实现.md: -------------------------------------------------------------------------------- 1 | # 有个运营妹纸心算找不到数独答案,心一横干脆写代码实现 2 | 3 | ## 0、代码写不好,心痛吖 4 | 5 | 家里新购了一个数独,午饭后消食便拿起来玩。半小时过去了,一小时过去了,一直没成功…… 6 | 7 | 超级不服气的,这道难题想逼我是吗?干脆直接写 python 代码破解好了!半小时后代码还没写好,我被自己蠢哭了。在写代码这件事上,我显然手生得很呢。 8 | 9 | 值得欣慰的是,我起码知道生物脑无法完成的,电脑可以代劳,只不过这代码依然需要生物脑来完成。 10 | 11 | 趁着端午小长假有点时间,就来琢磨下这件事好了。 12 | 13 | ## 1、不擅长写代码,总擅长需求分析吧? 14 | 15 | **计算目标**:找到数独的答案。是找一些答案,还是找出所有答案呢?后者难度高,且包含前者,我选择后者。 16 | 17 | **数独规则**:在下述六角形棋盘的 12 个位置中分别放入数字 1 至 12,使得图中每条连线 4 个位置加和为 26。 18 | 19 | ![shudu](https://user-gold-cdn.xitu.io/2019/6/8/16b35eeef90cba38?w=1421&h=1079&f=jpeg&s=139698) 20 | 21 | ## 2、生物脑和电脑在演算方法上的迥异 22 | 23 | 我的生物脑是如何尝试解出答案的呢? 24 | 25 | > 从棋盘取下所有数字。 26 | > 先随意选择 4 个数字放入某条线使之加和为 26, 27 | > 然后再选择 3 个数字放入与此线有交点的另外一条线使之加和为 26, 28 | > 然后尝试第 3 条线…… 29 | > 结果是,每次尝试到第 3、4 条线时开始吃力,偶尔能满足 5 条线但最后一条线无法满足条件。 30 | 31 | 我将如何用代码来指挥电脑演算呢? 32 | 33 | 用代码复原生物脑的思路,显然是非常蠢的解法。如何知道自己蠢? 34 | 35 | 上述思路拆解出来就是: 36 | 37 | 1. 指定前 3 个位置数值,计算得出第 4 个数,使得一条线==26 38 | 2. 选择剩余 5 条线中已得到赋值的位置最多的那条线,计算得出使该条线加和为 26 的数值 39 | 3. 循环以上,尝试使所有线的加和都满足 26;如果不满足,则重新指令最初 3 个位置的数值 40 | 41 | 我完全无法快速用代码表达出以上思路,基于此不难判断这个方法的愚蠢……(自黑不怠) 42 | 43 | 经过一些摸索,我把碳基问题抽象为下述硅基问题: 44 | 45 | 1. 棋盘 12 个位置的不同取值,构成了一个列表。 46 | 2. 自然数 1 至 12 有多少种排列组合的方式,就有多少个上述列表。 47 | 3. 对于每个列表,计算特定位置的加和(6 条线)是否满足条件,是通用的,能定义为函数。 48 | 4. 穷举自然数 1 至 12 所有的排列组合方式。 49 | 50 | ## 3. 多说无益,秀出代码 51 | 52 | ### 3.1 版本 1.0:能找到部分答案,但找不到所有答案 53 | 54 | ![img](https://user-images.githubusercontent.com/31027645/60950725-49958380-a32a-11e9-9a3b-238e3afa8251.png) 55 | 56 | ### 3.2 版本 2.0:自己动手,穷举所有排列组合 57 | 58 | 初步搜索,我没有找到如何实现输出列表项全部的排列组合。鉴于非常清楚自己对排列组合的代码实现接近于 0 经验,于是故意想要自己写代码实现。 59 | 60 | 计算目标的大框架已经实现,现在只缺排列组合。那我聚焦于此: 61 | 62 | **子目标:输出自然数 1 至 12 的所有排列组合** 63 | 64 | 演算方法是怎样的呢? 65 | 66 | 1. 位置 1 的取值范围为 1 至 12,先取值 1,完成下列所有演算后,再取值 2,完成下列所有演算,再取值 3……直至完成取值范围内的所有数值 67 | 2. 位置 2 的取值范围为除了位置 1 当前取值之外的 11 个数,先取值其中一个数值,完成下列所有演算后,再取值另外一个数值,完成下列所有演算后,再取值第 3 个数值……直至完成取值范围内的所有数值 68 | 3. 位置 3 的取值范围为除了位置 1 和位置 2 当前取值之外的 10 个数,先取值其中一个数值,完成下列所有演算后,再取值另外一个数值,完成下列所有演算后,再取值第 3 个数值……直至完成取值范围内的所有数值 69 | 4. 位置 4 的取值范围为除了位置 1 和位置 2 当前取值之外的 9 个数,…… 70 | 5. …… 71 | 6. 位置 12 的取值范围为除了位置 1 至 11 当前取值之外的 11 个数,此为唯一取值。输出位置 1 至位置 12 的当前取值 72 | 73 | 这个演算方法可行吗?代码将如何写?似乎有些困难。那我我先试着简化问题:输出自然数 1 至 3 的所有排列组合。并写出代码来验证结果是否正确。 74 | 75 | ![image](https://user-images.githubusercontent.com/31027645/60951192-2f0fda00-a32b-11e9-96ba-30621c7856d4.png) 76 | 77 | 78 | 在完成上述代码的过程中,刚开始列表赋值并没有采用切片的方式,导致所有列表均发生改变。无他,还是反映我对列表的操作不熟。 79 | 80 | 先不论代码是否简洁优雅,至少它在功能上实现了。那么现在,先试着用这个思路实现自然数 1 至 12 的全部排列组合,并计算得出数独 26 的解法共有多少个! 81 | 82 | 下面就是不简洁不优雅版本的数独所有答案的代码。因为太长,就直接放 github 文件地址啦: 83 | 84 | > [https://github.com/liujuanjuan1984/sudoku/blob/master/six_pointed_star_sudoku_v1_20190717.py](https://github.com/liujuanjuan1984/sudoku/blob/master/six_pointed_star_sudoku_v1_20190717.py) 85 | 86 | ### 3.3 还有什么遗憾? 87 | 88 | 上述代码 for 循环嵌套代码部分,不够简洁优雅。如何优化,是我接下来需要再琢磨的。笨办法也是办法,终于把数独的答案全部演算出来了,终于能安心睡个好觉了。 89 | 90 | 这就完了吗?当然不!这个碳基转硅基的解决方式中,有个内核的问题是,棋盘是个对称的六角星型,于是碳基世界的正确答案,其实只需硅基代码演算出答案的 1/6。 91 | 92 | 以正确答案[1,2,3,6,11,7,5,12,10,8,4,9]为例,棋盘每转动 60°就产生一个新答案: 93 | [2,3,6,11,7,1,12,10,8,4,9,5] 94 | [3,6,11,7,1,2,10,8,4,9,5,12] 95 | [6,11,7,1,2,3,8,4,9,5,12,10] 96 | [11,7,1,2,3,6,4,9,5,12,10,8] 97 | [7,1,2,3,6,11,9,5,12,10,8,4] 98 | 99 | 咿??如何优化代码,能撇掉那 5/6 臃肿的答案/计算量呢?——难度超纲,我还是暂时放下吧。 100 | 101 | ## 一句话小结 102 | 103 | 代码写得好不好,手熟与否很关键呀!而手熟并非简单的经常写就够了,而是要专门分解出哪些基础功或知识点薄弱,并重点突破之。此乃大咖们常曰的“刻意练习”。 104 | 105 | 欢迎来 https://xue.cn/ 和我一起从 0 开始自学 python,刷习题吖~ 106 | 107 | ## 更新简便高效算法 108 | 109 | 因为代码不优雅,这个数独的解法一直挂念,后来想出来一个更简便的做法如下。思路就是:采用 python 内置的 `itertools.permutations()` 得出所有的排列组合,然后计算每一个组合是否满足通关条件。实际运行效率比我之前的版本,不知道快多少呢! 110 | 111 | ```python 112 | """ 113 | GET Six_pointed_star answer with python script 114 | version 2.0 115 | author:liujuanjuan1984 116 | date:2019-08-28 117 | HOW does Six_pointed_star look like? view this picture: 118 | https://user-images.githubusercontent.com/31027645/63708468-23d72600-c867-11e9-9347-5ef925b4d108.png 119 | """ 120 | 121 | import itertools 122 | 123 | lines_list = [[1,8,9,3,],[1,7,12,5],[2,8,7,6],[2,9,10,4],[3,10,11,5],[4,11,12,6]] 124 | times = 1 #count how many results will get 125 | 126 | for a_rlt in itertools.permutations(range(1,13)): 127 | for a_line in lines_list: 128 | sum = 0 129 | for a_point in a_line: 130 | sum += a_rlt[a_point-1] 131 | if sum != 26: 132 | break 133 | else: 134 | with open('d:/shudu0828.txt','at',encoding='utf-8') as f: 135 | f.write(str(times)+" "+str(a_rlt)) 136 | #print(times,end=',') 137 | times += 1 138 | print('well done! all results are in this file: \nd:/shudu0828.txt') 139 | 140 | ``` 141 | 142 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190728_李笑来会用python写程序统计词频,你会吗?.md: -------------------------------------------------------------------------------- 1 | # 李笑来会用 python 写程序统计词频,你会吗? 2 | 3 | ## 1、李笑来能写,你能不能? 4 | 5 | 在李笑来所著《时间当作朋友》中有这么一段: 6 | 7 | > 可问题在于,当年我在少年宫学习计算机程序语言的时候,怎么可能想象得到,在 20 多年后的某一天,我需要先用软件调取语料库中的数据,然后用统计方法为每个单词标注词频,再写一个批处理程序从相应的字典里复制出多达 20MB 的内容,重新整理…… 8 | 9 | 在新书《自学是门手艺》中,他再次提及: 10 | 11 | > 又过了好几年,我去新东方教书。2003 年,在写词汇书的过程中,需要统计词频,C++ 倒是用不上,用之前学过它的经验,学了一点 Python,写程序统计词频 ——《TOEFL 核心词汇 21 天突破》到今天还在销售。一个当年 10 块钱学费开始学的技能,就因为这本书,这些年给我 “变现” 了很多钱。 12 | 13 | 正在通过 [xue.cn](https://xue.cn/) 自学 python 的我顺手在 trello 中给自己添加一张卡片:**要不用 python 写个统计词频的脚本玩玩?** 这是前不久的事儿了。 14 | 15 | 今日周末,我翻出这张卡片,打算实践看看。下文是我写词频统计脚本时的一些思考与实践成果。 16 | 17 | ## 2、如何把难题拆解为小 CASE? 18 | 19 | 从需求来看,“统计词频的脚本”是一个泛泛的需求。——我并不是想要统计特定内容的词频,我希望生成的脚本可以处理各式内容。这对脚本的最终交付成果提出了高要求。 20 | 21 | 如果请你用 python 写个统计词频的脚本,你会如何写呢?当我正襟危坐,正视这道题目时,第一秒钟感知到了为难与胆怯。有个小人儿在脑袋里说:“好难,我做不到吧?” 22 | 23 | 面对新事物、新挑战,人们善于用想象力把困难放的很大。而我已经有了多次迎难而上的经验,于是我喝了一口苦咖啡,问自己: 24 | > 从哪儿下手呢?不如进一步拆解来看看吧。 25 | 26 | 需求拆解如下: 27 | 28 | > “统计词频的脚本”,可以拆分为 2 个部分,a) 有哪些词?b) 统计这些词出现的次数。 29 | > b 是简单的。 30 | > a 分为 2 种情况:i) 给定词库;ii) 自己从内容中找词。 31 | > i 是简单的,ii 则可能复杂。 32 | 33 | 此时你可能问,你是如何判断简单还是复杂?简单吖,根据自己的编程能力与经验,预判自己能否写出代码。 34 | 35 | 需求经过拆解后,当前的重点聚焦于: 36 | 37 | > 如何从内容中抓取词? 38 | 39 | 其中,内容是一个宽泛的概念。在程序中,它可能是:string 常量,文件,网页,api 返回的数据如此等等。关键是什么呢?关键是脚本的一线代码们处理的是 string,列表或字典。其余的文件、网页、api 返回数据等,无非是数据的载体更为复杂,我已经掌握了把从它们那里获取数据,生成 string、列表或字典的能力。而这个能力你也能很简单获得,即通过“python 如何读取文件数据”之类句式,从搜索引擎中找到答案。 40 | 41 | 一篇文章可以直接定义或读取为一个 string 常量。而 `for i in stringcontent` 句式能够帮我们遍历 string 统计单个字的词频。然后双字词、三字词、N 字词等等,都可以由单字词拼接而成。 42 | 43 | 难点既然这么快想清楚,那么写代码实现吧! 44 | 45 | ## 3、从上帝视角调控成长体验 46 | 47 | 第一个版本代码如下图所示,还是非常简便的。我在同个目录下,另起一个`poem.py `文件用来把内容定义为常量,供该脚本调用。 48 | 49 | ![img](https://user-images.githubusercontent.com/31027645/62006676-7218dc80-b176-11e9-9781-59d4a1a37a66.png) 50 | 51 | 首次测试的 string 常量 poem 是一首中文小诗,从常理来说,中文词汇包括汉字 1、2、3、4 个,超过 4 个的虽有但很少。顺着上面的思路,我继续把 3 字词、4 字词的代码也写出来了。运算结果正常。 52 | 53 | 我想试试复杂的。比如读取 pdf 文件。这涉及到一个我尚未掌握的新知识点:python 如何读取 pdf 文件?获取答案也很容易,搜索然后尝试。 54 | 55 | 如果把“统计词频的 python 脚本”当作主线任务,那么“python 如何读取 pdf 文件”就是分支任务啦。在这个分支任务上我立即遇到困难:使用 anaconda powshell prompt 安装第三方库时, `pip install pdfminer` 命令行执行了小段就报错。 56 | 57 | ![img](https://user-images.githubusercontent.com/31027645/62006803-3bdc5c80-b178-11e9-9bd2-5aeaf79bef70.png) 58 | 59 | 此时要么在支线任务中深究下去,要么回归主线任务。我选择回归主线任务,但顺手在 trello 上给自己建卡“python 如何读取 pdf 文件”等以后专门来研究它。 60 | 61 | 现在,我继续专注于词频脚本。 62 | 63 | 除了内容载体的复杂,还可以有内容量的冗长。我拷贝了一篇几千字的中文文章,定义为 string 常量,然后用刚才调试通过的脚本统计词频。 64 | 65 | 在处理数百字的小诗时,脚本运行迅速,结果几乎立即被终端打印出来。而处理这篇长文时,终端打印完单字词、双字词的统计结果后,就一直没有输出,好似“卡”在那里。于是我强制结束脚本,在代码中添加了几条打印来检查程序是否正常运行中。由此发现了一个“性能”上的问题:电脑或编辑器,都没有卡住,程序运算持续在进行中,只是没有运算完成。 66 | 67 | 这篇长文,单字词几百条;按照我的上述代码逻辑,双字词运算 几百\*几百 次,三字词运算 几百\*几百 \*几百 次,四字词运算 几百\*几百 \*几百 次。演算一下,具体是多少呢? 68 | 69 | > 4 字词运算次数:467758877041 次 70 | 71 | 四千六百多亿次!难怪迟迟没有结果输出!看来代码本身需要被修改优化,以降低计算量。第二个版本除了修改算法外,也调整了代码结构,使之更易于调试和增删。 72 | 73 | 在这个版本中,词频统计仅可用于中文,处理几千字的文章,大概需要 1 分钟左右。此时,一个下午已经过去了。再次久坐忘动的我,决定暂停休息一下,扭扭脖子甩甩胳膊。而且,很重要的一件事是,**把实践过程中的思考与第二个版本的脚本做一个阶段交付**。 74 | 75 | 不得不提的是,**写文章是一个提升阶段交付成就感的小策略**。这也是此文的由来。当然啦,我还要顺手在 trello 上给自己添加 2 张新卡片,等有精力时继续实践: 76 | 1. python 如何统计英文文章词频? 77 | 2. python 统计中文词频的脚本处理十几万字的书籍时,性能如何? 78 | 79 | 在群里谈及我在写的词频脚本时,有位网友提出一个观点,“不是程序员,学编程没用”。我想,他肯定是没有读过李笑来的书,或者干脆读过,只是读成了另外一个版本吧! 80 | 81 | 如果你也在学习 python 或想要提高自学能力,欢迎来 [xue.cn](https://xue.cn/) 聊天室找我 @liujuanjuan1984 ~ 82 | 83 | 84 | ```python 85 | def write_rlt(content,dic1,dic2): 86 | rlt = {}#有该结果但并没有用上 87 | rlts = {} 88 | for i in dic1.keys(): 89 | for j in dic2.keys(): 90 | cix = i + j 91 | if cix in content: 92 | num = content.count(cix) 93 | if cix not in rlt.keys(): 94 | rlt[cix]=num 95 | if num > 1: 96 | rlts[cix]=num 97 | return rlts 98 | 99 | def cipin_1(content): 100 | rlt1 = {} 101 | rlt1s = {} 102 | for ci in content: 103 | #r"[^\u4e00-\u9fa5^a-z^A-Z^0-9]" 104 | atext =""" 105 | \ \\\\n ,.,。/一()()<>《》 106 | """ 107 | if ci not in atext: 108 | num = content.count(ci) 109 | if ci not in rlt1.keys(): 110 | rlt1[ci]=num 111 | if num > 1: 112 | rlt1s[ci]=num 113 | return rlt1s 114 | 115 | def merge_dic(dic1,dic2): 116 | rlt = dic1.copy() 117 | rlt.update(dic2) 118 | return rlt 119 | 120 | def cipin_x(content,dic1,dic2): 121 | rltsx = write_rlt(content,dic1,dic2) 122 | rltsy = write_rlt(content,dic2,dic1) 123 | rlts = merge_dic(rltsx,rltsy) 124 | return rlts 125 | 126 | def sorted_dic(dic1,txt=None): 127 | rlt = sorted(dic1.items(),key=lambda x:x[1],reverse=True) 128 | print("\n--------------------\n") 129 | if txt==None: 130 | atxt = "结果共" 131 | else: 132 | atxt = txt + "字词共" 133 | print(atxt,len(rlt),"条,具体为:\n",rlt) 134 | return rlt 135 | 136 | 137 | def main(): 138 | from txt import zixue_x as content #加载想要统计的内容,string type 139 | import datetime 140 | 141 | print("---begin---",datetime.datetime.now()) 142 | 143 | rlt1s = cipin_1(content) 144 | rlt2s = cipin_x(content,rlt1s,rlt1s) 145 | rlt3s = cipin_x(content,rlt1s,rlt2s) 146 | rlt4s = cipin_x(content,rlt1s,rlt3s) 147 | rlt5s = cipin_x(content,rlt1s,rlt4s) 148 | rlt6s = cipin_x(content,rlt1s,rlt5s) 149 | rlt7s = cipin_x(content,rlt1s,rlt6s) 150 | 151 | sorted_dic(rlt1s,"单") 152 | sorted_dic(rlt2s,"双") 153 | sorted_dic(rlt3s,"3") 154 | sorted_dic(rlt4s,"4") 155 | sorted_dic(rlt5s,"5") 156 | sorted_dic(rlt6s,"6") 157 | sorted_dic(rlt7s,"7") 158 | 159 | print("---end---",datetime.datetime.now()) 160 | 161 | if __name__ == "__main__": 162 | main() 163 | 164 | ``` 165 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190804_35岁有儿有女,为什么她开始自学编程?.md: -------------------------------------------------------------------------------- 1 | # 35 岁有儿有女,为什么她开始自学编程? 2 | 3 | 另一个标题:35 岁有儿有女,为什么她开始自学编程? 4 | 5 | ## 零基础编程入门越来越容易 6 | 7 | 这么讲并不夸张:无论你初学哪门编程语言,第一行代码几乎都是打印出 `Hello world !` 8 | 9 | ```python 10 | 11 | print('Hello world!') 12 | print('Hello python!') 13 | 14 | ``` 15 | 16 | 遥想当年,花上一两天折腾完各种安装配置调试环境,写下第一句“面世代码”。看到终端被打印出的那句 `Hello world!`,甜蜜滋味,如同热恋期被男友亲一大口,如同酷暑中啃块冰镇西瓜。 17 | 18 | 时代在进步。无论是编程领域的纯小白,还是老手尝试一门全新的语言,需要花上数天本地安装配置调试环境才能写上第一行代码,已经是旧时代特色。如今,我能直接访问 xue.cn 网页,在网页上敲入第一行代码并立即运行查看结果。曾经阻碍我们这些 70、80 乃至 90 后的,即将不再阻碍 90、00 乃至 10 后。 19 | 20 | ![xuecn 截图](https://user-images.githubusercontent.com/31027645/62353399-2cc12a00-b53d-11e9-94e6-a575740ec1fc.png) 21 | 22 |
xue.cn
23 | 24 | ## 学习一定需要功利性吗 25 | 26 | 科技的进步,给我们带来了方便,也带来了烦恼。 27 | 28 | 我两岁多的女儿,通过 ipad 上的 app “自主”学会了数字、英文 26 个字母、汉语部分拼音的读、认,正积极练习着写。我的儿子今秋将上小学五年级,从小也通过 ipad 学了不少东西,但如今却对“枯燥”的在校学习总是兴致乏乏,易被生动的游戏、动漫、直播等牵走注意力。年中我专门给一台笔记本电脑安装了 linux arch 操作系统,想让他试着学习书本之外的知识,他也没啥兴致,倒是妹妹看到我们都在用电脑,硬挤着上桌,学我们有模有样地敲键盘、用鼠标。 29 | 30 | ![儿女在玩 linux 电脑](https://user-images.githubusercontent.com/31027645/62419506-34570f00-b6b4-11e9-846c-09b0ef6b0eb9.jpg) 31 | 32 | 儿子的现状说明了什么呢?生动的启蒙教育总归是需要的;但如果想要继续顺知识之径攀登,总归仍需下一番苦功夫。孩子渐渐长成,我越来越觉得,与其填鸭式塞给他们一堆知识点,不妨教给他们学习的方法,培养学习的兴致,并对学习的苦乐建立清醒的认知。 33 | 34 | 咱们这些做父母的,提起子女教育总是忧心忡忡,并总能高谈阔论一番。可是,说起来容易做起来难啊!有位老哥们,今年四十余岁,今夏孩子小升初可令他操碎了心。我们数次聊起如何培养孩子主动学习的意识,如何让孩子自己爱上学习……结果呢,家长付出许多心力,孩子们依然故我。 35 | 36 | 比起这个老哥们,我稍微狠心的地方在于,我能接受孩子在一段时间内学习成绩不佳,与此同时,我不想停止自己的学习。 37 | 38 | 说到这里,我请问诸位一句: 39 | > 成人的学习一定需要功利性吗? 40 | 41 | 功利性的学习,无论是升学排名还是升职加薪,解决了部分学习的动力。晓之以利害,无论是儿子的学习,还是家长自学,总能生效吗?我看两岁多的妹妹,自主反复诵读数字或字母时,她凭借的仅仅只是兴趣与好奇心。——她需要我的,仅仅是帮她下载 app 并在她取得一点成绩时为她鼓掌欢呼。 42 | 43 | 我原本希望自己掌握一套经得起考验的学习方法论,然后授子女以渔。现在看来,妹妹的学习状态,才是我和哥哥应该学习的榜样。我能为哥哥做的,是在他自制力尚不足够时,限制他看电视玩手机的时间,给多一些陪伴去探索和培养他的兴趣,以及,以身作则在学习这件事上作出好榜样。 44 | 45 | 有人问我为什么自学编程,我脱口而出:喜欢、好奇,所以就学了。还管什么功利用途呢?这又跟我三十好几、有儿有女有什么关系呢?——如同树木的本能是生长,智人的本能就该是成长啊! 46 | 47 | ## 在线编程课如此昂贵的本质 48 | 49 | 作为一个本职工作不是程序员、无需写代码的编程爱好者,我停留在编程学习的“新手村”已持续多年。我曾花每本几十上百元买过好几本编程的书。我也曾付费参加编程课,买过几十、几百的,然后在标价几千、几万的课程面前犹疑不决。 50 | 51 | 付费课程如此高标价,自有其存在的合理性,也有一定的市场容量。只不过我作消费决策前,多做了一件小事,问自己一句: 52 | 53 | > 如此贵的本质是什么? 54 | 55 | 花钱也总得花个明白吧!带着这个疑问,复盘一下我最近参加某个 python 的付费体验课程的观察与判断。这家的授课形式有新颖之处,知识点的讲解非常细致,知识点的归纳都是现成的,学习与练习的结合节奏也挺不错。初看都很好,对不对? 56 | 57 | 很多事情是怕对比的。如果我没有看过《自学是门手艺》,没有花 15 元/月 购买 xue.cn 的服务,我可能会花几千元买这家的后续课程,并且深以为自己赚到了。现在我有多了一些判断的能力。它有哪些问题呢?它会鼓励你持续付费买它的更多课程,也会鼓励你把它已经总结归纳好的知识点图片另存保管,上面都有它的 logo 与品牌名。问题在于,它绝口不提哪里去获得最优质的信息、或获取必要的最新知识;它绝不鼓励你关注或练习自学能力或自己解决问题的能力,所以干嘛要让你自己整理归纳,加重你的学业负担呢?塞给我的只有知识点,并无学习的方法论。 58 | 59 | 有了对比之后,我才发现:买此类课程,颇有买椟还珠之嫌。自学能力毕竟是比编码能力更重要的底层能力。如果依赖此类课程学习编程,那么我将出让提高自学能力的机会,出让自己解决问题的能力的机会,出让自己获取和分辨最新优质信息能力的机会。 60 | 61 | 我将花大价钱买到手的,是一个“我很努力”的尚未成为现实却已然安抚我的幻觉,是一个“只要制造足够大的沉没成本,我一定会认真学完”的错觉,是一个“我交了这么多钱于是学好学坏的责任全在他人身上”的诡秘认知。 62 | 63 | 我将花大价钱买到手的,是用金钱鼓励和支持这类“教育者”继续迎合大众偷懒、畏难、怕枯燥、没耐心等人性必然。而我将依然持续保留“被教育者”的身份,无缘给自己贴一个“自教育者”的标签。 64 | 65 | 无论是孩子的教育,还是我的自教育,我越来越觉得:知识点真的不是最重要的。何况,在编程世界里,知识点从来不是稀罕物……只要你动动小手去互联网检索,真正有用、时新的知识点,都会呈现到你面前。如果大互联网范围太大,信息嘈杂,你起码还能在该语言的官方网站查阅文档或在该语言的专属社区或专为编程人员准备的公共社区交流。与此同时,重要的是什么?是学习的方法,学习的兴致,和对学习之路苦乐的践行体悟。 66 | 67 | ## 选择把编程当做自学的入口 68 | 69 | 为什么即便很喜欢编程,也有学习的外在条件,之前的我却一直停留在新手阶段?原因倒也简单……以往我总把学习看得过于功利,认为自己用不上,就不需要学那么多。直到,我在《自学是门手艺》中看到这句话: 70 | 71 | > 要么干脆别学算了,何必把自己搞成一个半吊子? 72 | 73 | 哈哈哈,啪啪啪打脸啊,简直要高兴地哭出来。——当了这么多年老师,李笑来太懂学生心理了。他还反复强调,自学的重要原则是“全面完整”。按照他书中说法,我可以选择任何其它技能来作为自学能力的践行场景,编程只是其中一个选项而已。 74 | 75 | 不过既然我这么喜欢编程,我最终决定把 python 学得全面完整,目前已在 xue.cn 练习 python 编程有一段时间了。至于`为什么一定要掌握自学能力?`,`为什么把编程当做自学的入口?`这些书中都有独立的章节讲到,我丝毫没有补充说明的必要。你可以在 xue.cn 网站在线阅读《自学是门手艺》这本书,未来还会有更多不同作者的书或文集,但 15 元/月的订阅费,并非是购买书籍的阅读权限,而是购买 xue.cn 的云计算服务,“xue 服务为每一位付费用户分配独立的容器、运行环境与云计算资源,从而让一本晦涩的平面书变得生动、可交互,让学习的过程更加充满乐趣。”官网如此解释道。 76 | 77 | 相对于动辄几百几千上万的编程课,每月 15 元的定价真低。关键是,还能学到真章。李笑来在《自学是门手艺》的 `1.5.4 函数` 这一节再次强调查阅 python.org 官方文档的重要性。 78 | 79 | > 很多人只看各种教材、教程,却从来不去翻阅官方文档 —— 到最后非常吃亏。 80 | 81 | ![image](https://user-images.githubusercontent.com/31027645/62420113-b6990080-b6bf-11e9-9de7-9a32575a26bd.png) 82 | 83 | 不夸张地讲,我可能写过上千行 `print()` ,却首次理解 `print()` 原来有如此多花样可以玩。如果你想去 python.org 查看?链接如下: 84 | 85 | https://docs.python.org/3/library/functions.html#print 86 | 87 | 88 | 初阶学习者仅仅关注具体的知识点,并很容易掏钱购买别人包装好的知识点,而学会了学习的人是已经进化的学习者,他们依然会付费购买知识服务,但绝不会干出买椟还珠的事情。进阶的学习者很清楚:**自学能力毕竟是比编码能力更重要的底层能力**。 89 | 90 | ## 如果要给学习再添一点功利性 91 | 92 | 有人说,“娟姐,你这太潇洒了,说换行业就换行业,光凭兴趣学编程也很牛逼,可我不行,生活压力是明摆着的啊。” 93 | 94 | 哪儿有这么潇洒啦~说到底,只要我在不断地学习进步,是功利之心驱动,还是兴趣使然,都 OK 啊。即便我对编程持续有兴趣,但我也会持续发掘学编程的功利,来增强自己的学习动力,动力从来嫌少不嫌多,对不?你且听,我列举一下目前我所想到的自学编程的动力: 95 | 1) 把编程学好,能了结我多年以来浅尝辄止的“未完成心结”, 96 | 2) 能让我践行体悟“自学能力”的首要原则“全面完整”,切实提升自学能力, 97 | 3) 中年妇女学会编程,这岂不是超酷的! 98 | 4) 编程能力可以帮助我更好地成为 growth hacker , 99 | 5) 能让我帮助孩子们接触计算机科学,看看他俩是否有兴趣成为程序员。——这几乎是未来最好的职业选择。 100 | 101 | 关于最后一个观点,推荐你读一下[霍炬](https://github.com/virushuo)在 2015 年底写的一篇长文[《为什么你招聘不到程序员,以及软件如何定义现实世界》](https://mp.weixin.qq.com/s/mmW_oyupSpNZ-jPf0JJLkA) 。文中提到: 102 | > 在中国,大概唯一增长率可以比的上北上广房产的,就是程序员的薪水了。 103 | > 这个世界对程序员的需求几十年没降低,按照我的观点,甚至未来几十年也不会降低,薪酬也只会持续上升。 104 | > 现实世界的虚拟化已经快到了相当的程度,我们真的需要大量的程序员,未来仍然需要,有多少都不够用。 105 | 106 | 这篇文章视角新颖,且非常有前瞻性。即便晚上 4 年 8 年才读到,也绝不过时。当然啦,先有兴趣,再谈功利,无论对我的两个孩子,还是对我自己,我都会如此操作。 107 | 108 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190804_不懂即搜,如何用 python 读取 api 并借用文件读写数据?.md: -------------------------------------------------------------------------------- 1 | # 不懂即搜,如何用 python 读取 api 并借用文件读写数据? 2 | 3 | 人类天生有一种本领,即便不懂那原理,居然也能拿来就用。李笑来在提出这个观点时,举了很多生动的例子。我呢,恰好最近搜索了好几个第三方库并拿来就用。如果你和我一样,正在自学 python,想试试新玩意,不妨顺着我的笔记来尝鲜。即便你暂时没有自学编程的习惯,那么也祝愿你能从下述过程中和我一样发现:不懂即搜,原来可以帮助我们解决好多“难题”。 4 | 5 | 起因是这样的,上周尾,我向同事要一些未经统计的原始数据,想要周末自行尝试写脚本做统计分析。工程师同事开放了一个 api 给我。以前我只知 api 这个词汇,但并没有见过 api 长什么样子。第一次拿到 api 一看,哟,居然只是一个 url 链接。用浏览器打开,是一个网页,而我想要的内容数据,都呈现在那网页上。 6 | 7 | 于是我去搜索`“python 如何读取网页内容 site:csdn.net”`,后面这一小串字符,表示我仅想查阅 csdn.net 网站上的内容。当然你也可以改成别的网站。下文提到搜索时,我将不再重复后面这一小串。但这一小串作为一个实用的搜索技巧,能很好地提高你的搜索成效。 8 | 9 | 搜索到结果后,我依葫芦画瓢,在 vscode 中写了以下几行代码。 10 | 11 | ```python 12 | 13 | def read_url_to_str(url): 14 | import urllib.request as request 15 | webpage = request.urlopen(url) 16 | data = webpage.read() # 17 | content_str = data.decode("utf-8") # 18 | return content_str 19 | 20 | ``` 21 | 22 | 但 urllib 被编辑器自动画了红色的波浪线,这是在提醒我,我并没有安装它。它是什么?打个类比吧,我们去买奶茶,默认的奶茶仅有水、茶末、奶的混合体就相当于 python 本尊,但你可以选择加的各种料,芒果粒、椰果、红豆等等,你把它们想成是 python 的各种第三方模块啊库啊包啊之类,更讲究的人会自制果粒放到自己的奶茶让它更好喝,那就是你自定义的模块啊库啊包啊之类。 23 | 24 | 用什么方式能简便地安装 python 的第三方库呢?我用的是 anaconda,你可以搜`“anaconda windows 10 如何安装”`,windows 10 是我的操作系统,你也可以换成自己的操作系统。装好后,搜 `“anaconda 如何安装 urllib” `即可。其实简单的就只有一句话,即,打开 anaconda powershell prompt ,输入命令行并回车就行。如果问你 Y/N ,输入 Y 并回车即可。 25 | 26 | > pip install urllib 27 | 28 | 以上操作完全无需记忆,只需要懂的如何搜索到答案即可。每次需要用到时,直接去互联网搜。本文我会反复提到“搜索”,它简直是自学编程的最佳伴侣。 29 | 30 | 在《自学是门手艺》的`Jupyterlab 的安装与配置` 这一节,具体讲到了 anaconda 的安装与更新,以及如何检查已安装的版本。如果你有需要,也可以直接照着做吖: 31 | 32 | ![image](https://user-images.githubusercontent.com/31027645/62422517-831d9c80-b6e6-11e9-9a85-ba506dd8ec86.png) 33 | 34 |
xue.cn 内容截图
35 | 36 | 经检查,我的 urllib 已安装成功, 那么上面一段程序已可运行。于是调用试试看吧。 37 | 38 | ```python 39 | 40 | # 上述 api 不便公开,我另找 url 也可演示该功能 41 | url_a = 'https://static.press.one/e5/2d/e52d0c03fc7b8587ec73412519a76f13177ada09f8b8a9810724e3f018ee50ff.md' 42 | 43 | content_str = read_url_to_str(url_a) 44 | print(content_str) 45 | 46 | ``` 47 | 48 | 嗯,但是这样直接在终端打印,会产生刷屏的效果吖。那干脆定义一个简单的函数,用来把页面内容保存在 txt 文件中吧。相信你也能简单理解下面这几行代码: 49 | 50 | ```python 51 | 52 | def write_str_to_txt_file(content_str): 53 | import os.path 54 | import random 55 | x = random.randint(10000,99999) 56 | txt_file_url = 'd:/file'+str(x)+'.txt' #增加随机数功能,方便多次调用时生成的文件不同。 57 | with open(txt_file_url,'at',encoding='utf-8') as tf: 58 | tf.write(content_str) 59 | print('内容已写入文件',txt_file_url) 60 | ``` 61 | 62 | 我的工程师同事给我的 api 其数据的格式是 json 的,后来我又检索了`“python 如何读取 json 数据”` ,这样一来,代码读了网页之后返回的,不再是 string 类型,而是 json 与 python 都兼容的 字典类型。 63 | 64 | 其后我又遇到了数据写入 txt 文件,再读取使用时,变成了“列表”的问题。如果你用过 python 的 `fileobject.readlines()` 就会明白我在讲什么。好在我去搜了 `“python 如何处理 json 数据 文件读写”`并顺利掌握。 65 | 66 | ```python 67 | 68 | def read_url_to_dict(url): 69 | import urllib.request as request 70 | webpage = request.urlopen(url) 71 | data = webpage.read() # 72 | content_str = data.decode("utf-8") # 73 | #如果你的编辑器提醒你没有安装 json,你搜索一下安装即可 74 | import json 75 | content_dict = json.loads(content_str) 76 | return content_dict 77 | 78 | def dict_write_json_file(content_dict,file_url="d:/json_file.json"): 79 | import json 80 | import os.path 81 | with open(file_url,'w',encoding='utf-8') as write_f: 82 | json.dump(content_dict,write_f,ensure_ascii=False,sort_keys=True, indent=4) 83 | print('数据 dict 已写入文件:',file_url) 84 | 85 | def read_json_file_to_dict(file_url="d:/json_file.json"): 86 | import json 87 | import os.path 88 | with open(file_url,'r',encoding='utf-8') as read_f: 89 | content_dict = read_f.load(read_f) 90 | return content_dict 91 | 92 | ``` 93 | 94 | 但这并不算完。我又试着用最初的`read_url_to_str(url)` 去读了更多网页并调用`write_str_to_txt_file(content_str)`然后发现,很多网页读出来的,并非网页上肉眼可见的中文内容,而是各种代码。 95 | 96 | 我试了以下几种网页。如果你好奇,拷贝我的代码到你本地的编辑器,运行试试看吧。 97 | 98 | ``` python 99 | #读出来一个汉字也没有,全是代码 100 | url_a = 'https://press.one/' 101 | 102 | #能完整读完整个网页的内容,整个网页的内容就是一个 markdown 文件内容 103 | url_b = 'https://static.press.one/e5/2d/e52d0c03fc7b8587ec73412519a76f13177ada09f8b8a9810724e3f018ee50ff.md' 104 | 105 | #仅能读到部分标题文本,其余也都是代码 106 | url_c = 'https://www.zhihu.com/question/338250156' 107 | 108 | #阮一峰老师的个人博客 RSS 订阅网址,能读不少内容 109 | url_d = 'https://feeds.feedburner.com/ruanyifeng' 110 | 111 | #github 的一个旧版本的 api 112 | url_e = 'https://api.github.com/graphql' 113 | 114 | ``` 115 | 116 | 少量网页能读出来中文内容,而绝大多数网页读出来的仅仅只有掺杂了 JavaScript 或其它语言的 html 代码。到底为什么呢,我现在并不理解,倒也不妨碍我**善用搜索技能**从而掌握了部分用法。未来我还想要纯靠自学掌握 python 爬虫技巧。你觉得我能办到吗? 117 | 118 | 其实吖,搜索本身并不困难。困难的是,对于自学编程的人来说,常常不懂用专业词汇描述自己的问题。如果你曾遇到这类困难,不妨加入我的 python 自学小群,和大家切磋“搜索”时如何描述问题吧~ 我的微信号:qiaoanlu,暗号:编程自学 119 | 120 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190807_自学 python 编程,学完新的又忘旧的,该怎么办?.md: -------------------------------------------------------------------------------- 1 | # 自学 python 编程,学完新的又忘旧的,该怎么办? 2 | 3 | ## 一个普遍的现象 4 | 5 | 在学习时,我们常常遇到一个现象:学了新内容,转头又忘了旧内容。以自学 python 编程为例,即便你已经完成 python 基础功入门,只要在持续进步,比如开始接触各种各样的库,该现象依然频发。 6 | 7 | 这不是某个自学者特有的问题,这简直是持续学习过程中的必然。 8 | 9 | 针对该现象,我整理出来 3 个锦囊,邀请也在持续学习的你一起打开看看,是否能有效解决“学新忘旧”的困境。 10 | 11 | ## 锦囊①给知识分类 12 | 13 | 我们以“需要记忆到何种程度”作为标准,来给自己所接触到的知识做一个分类。A 类是牢牢记住的,B 类是常用的于是放在手边方便随时检索的,C 类是无需记忆,等到用时再去搜即可。 14 | 15 | 对知识的分类可能是主动的,也可能是被动的。你既可以主动选择把哪些知识化为 A 类并刻意重复,也可以被动地跟随多次重复自然而然地掌握。 16 | 17 | 对知识的分类是动态的,视学习程度和阶段而定。最初自学 python 时,单单记住 print() 或者字符串的增删改查如何操作就很费神;但随着我们的进步,部分知识转变为了牢固的基础功,部分知识依然夹生,但能轻车熟路知道哪里检索可得。 18 | 19 | 对于持续进步的 python 自学者来说,新知识先进入 C 类,再进入 B 类,最后进入 A 类。但 A 类其实持续消耗一个人的脑内存,会有容量的上限。当你已经掌握了基础功甚至进阶技能时,再往 A 类塞新知识开始感到明显吃力,又或者任何时候当你主动往 A 类塞知识并感到吃力时,就没必要强塞了。 20 | 21 | 在对学习成效感到焦虑时,检视自己对所学知识的分类。如果你忘掉的是 C 类的用法,没啥可焦虑的。而居然忘掉了 A 类,那就好好捡起来做功课。这就引出了第②个锦囊。如果忘掉的是 B 类知识,那就把做好整理归纳,这就引出了第③个锦囊。 22 | 23 | ## 锦囊②重复是必然的 24 | 25 | 在学习的过程中,重复读,重复练,重复用,甚至重复造,是每个学习者必经的过程。匠人需经历过无数次重复,学编程也如此,不可能学一次、用一次就完全掌握。 26 | 27 | 作为学习者,要么主动遵循记忆曲线,主动重复去读或练前段时间接触的新知识、夹生知识;要么被动接收“用时发现自己忘了”的信号,然后再重复捡起来。后者看似消极,但其实也非常有效。曾经学过练过的,大脑都有痕迹,当你第 2 次、3 次重复时,依然有印象,重新掌握的速度也会快起来。 28 | 29 | 这时不得不再提第①个锦囊。比如,你已经掌握了基础功,正为了自学爬虫而了解几大爬虫相关的库,你对这些库完全陌生,你不知道谁和谁都有哪些特性,也不知道自己最终会反复用到哪些方法,或者掉进哪些坑里……于是你尝鲜然后不小心忘掉,并没有什么不妥。反复踩同样的坑……搜索同样的问题并练习同样的代码……是很多人在接触新知识时会经历的过程。 30 | 31 | 小孩子练习走路,还要跌到在地无数次呢,但在大人眼中,小孩子颤颤巍巍的样子多可爱啊。在自学编程的时候,我们大脑中所对应的那个部分,就是个初生的孩子!稚嫩是必然的,重复摔倒也是必然的,完全没必要用成人的标准要求自己在每个新领域都是高手表现。 32 | 33 | 还有一种特殊情况是,有的人新学知识时,总是一股脑往前冲,忘了“重复”的必要性,回过头好像自己读完了,记住的也寥寥。没事,回过神来,刻意重复吧。 34 | 35 | ## 锦囊③整理归纳,写学习笔记 36 | 37 | 总是逐新知识而去,旧知识欠缺必要的整理归纳,当然很容易忘掉。不妨认真写学习笔记,并公开发表为文章。为什么学技术的牛人中,写作能力强的大有人在?为什么刘未鹏大佬的好文“[怎样花两年时间去面试一个人](http://mindhacks.cn/2011/11/04/how-to-interview-a-person-for-two-years/)”提到博客的重要性?程序员最初的写作,通常都是学习笔记,很多技术大佬也常年写新的学习笔记并广为流传。作为新手,在学习的过程中,千万别丢了整理归纳、写读书笔记这个锦囊。 38 | 39 | 学习笔记有不同的写法。一种写法,复制粘贴并汇总该知识点的方方面面,复制粘贴完了,其实自己也没啥心得和深刻印象。另一种写法,以未来的自己为读者,记录自己如何获取、使用该知识点的。第二种写法,在过程之中就有许多思考,产生取舍、整理、归纳等思维活动。写学习笔记时,你的大脑工作量越多,该知识点从 C 类转为 B 类甚至 A 类的可能性越大。 40 | 41 | 同一个主题的学习笔记也可重复进行。这种重复是因为你在不同时期,你对知识的掌握程度、侧重的点都已经发生变化。重复写同一个主题,也能让你再次复习,重新整理归纳,并常常发现,原来许多夹生的知识点可能早已默默转变为牢牢记住的了。 42 | 43 | 好啦,以上就是我为自己备好的③个锦囊。如果对你有用,一定要告诉我!自学 python 不易,此路应携手前行。 44 | 45 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190808_谁能想到问题居然出在这里.md: -------------------------------------------------------------------------------- 1 | 上周完成了一个 python 脚本,可以自动帮我做不少数据的统计分析。已经成功运行过。今天运行时,遇到一个报错: 2 | 3 | > urllib.error.URLError: 4 | 5 | 我尝试了重装 urllib,也尝试了把 url 中的 : 改成 %3A ……网上推荐的做法,逐一尝试,就是不成功。 6 | 7 | 发现一个回答是:需要 openssl 模块。或者 openssl 没成功。无意中又看到:“win10 Anaconda python 中 SSL 模块无法正常使用”…… 8 | 9 | 我昨晚在已直接装过 vscode 的情况下,又通过 anaconda 装过 vscode,这中间可能发生了什么…… 10 | 11 | 于是添加几条环境变量……问题解决。脚本可正常运转了。说起来简单,这过程中绕了很多圈儿…… 12 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190808_这道题,我不会解——关于windows环境.md: -------------------------------------------------------------------------------- 1 | # 这道题,我不会解——关于 windows 环境 2 | 3 | 我用的是 windows 10 + 64 位的笔记本电脑。在自学编程的过程中,我遇到以下困惑。因为没有足够的线索,更欠缺相关基础知识来理解,我暂时记下这道我不会解的难题。 4 | 5 | ## 困惑 1 6 | 7 | 我直接在官网下载安装了 vscode,正常使用很久。 8 | 9 | 后来我装了 anaconda ,在 anaconda navigator 的 home 界面,显示 vscode install 。既它认为我没装 vscode。 10 | 11 | 可我明明装了吖。 12 | 13 | 后来我手贱,点了那个 install ,执行完后,似乎也没有发生变化,打开 vscode 也依然呈现我关闭它之前的各种界面。 14 | 15 | 我的疑问是: 16 | 17 | 直接装 vscode 和通过 anaconda 装 vscode 有什么区别? 18 | 19 | 为什么 anaconda 不能检测到我已经装了 vscode ? 20 | 21 | 当我先直接装了 vscode ,再通过 anaconda 安装了 vscode ,发生了哪些变化? 22 | 23 | ## 困惑 2: 24 | 25 | 我曾经直接通过软件管家之类的工具安装过 python,但后来我在 vscode 中初次写 python 脚本时,似乎依然提示我没有安装 python? 26 | 27 | 于是我通过 vscode 自带的 extensions 安装了 python。 28 | 29 | 再后来,我装了 anaconda 后,它似乎也提示我装 python。(当时没有特别留意,只有模糊印象,可能失真。) 30 | 31 | 我的疑问是,为什么无论 vscode 或 anaconda ,都需要我重新装 python?我如何知道我正在用哪个 python?装来装去,我电脑中到底有 1 个 python 还是 3 个 python? 32 | 33 | ## 困惑 3: 34 | 35 | 我学 python 的过程中,开始接触到越来越多的库。比如 pandas,或者 numpy 之类,在 anaconda prompt 中,我执行 pip install 时,会提示我已经被满足了。但在 vscode 写导入语句或直接打开 python 的 IDE 写导入语句,都提示没有该模块。 36 | 37 | 几经搜索尝试,我通过 cmd 调出电脑自带终端执行 pip install 才成功。 38 | 39 | 这又是为什么呢? 40 | 41 | ## 线索? 42 | 43 | 我请教了程序员们,他们提到了环境变量、python 环境 之类的关键词。但这个线索依然非常大……有几句方便我将来理解、但现在依然懵懂的很有价值的话: 44 | 45 | > 我理解 vs code 上只需要设置下你的 Python 在哪里。用了 virtual env 或 其它工具创建了虚拟环境后,就在 vs code 上指定下虚拟环境的 Python 路径就好了环境变量仅仅是可能让你不需要手动指定了,但,你明确手动指定下,我觉得最清晰。尤其在不知道为啥不行时。 46 | > Python 环境问题特复杂,在 windows 上难度\*10 47 | > 我一直用 venv 倒是没出过问题 48 | > 一直用 venv ,一个环境坏了删了重建一个就好了 49 | 50 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190808_适合新手的 python pandas 学习笔记(1).md: -------------------------------------------------------------------------------- 1 | ## 一、准备工作 2 | 3 | ### 解决动力:为什么学? 4 | 5 | 知道 pandas ,来源于可靠的人强烈推荐。(我们团队中擅长 python 的程序员,甚至我们的 CTO 都推荐。) 6 | 7 | 后来我搜一下发现,pandas 并非程序员的必需,反而是很多需要做数据分析岗位的利器,比如运营、产品或增长黑客。 8 | 9 | 通常我们还没有开始学一样新技能时,会被“它太难了吧”,“我可能学不会”这样的念头吓到。但“鸡贼的”pandas 官网居然自己出了一篇面向新手的攻略,名字如此吸引人: 10 | 11 | [10 minutes to pandas](https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html) 12 | 13 | ### 准备工作:学习材料 14 | 15 | 好的教程,是开始的第一步。但官网的教程可能让英文不好的人产生困惑。为了适时调控自己的学习体验,我另外准备了两个备查的网址: 16 | 17 | [10 分钟搞定 pandas](https://blog.csdn.net/matrix_laboratory/article/details/50704160) 18 | 19 | [Python 数据处理:关于 Pandas 你需要知道的都在这里了](https://zhuanlan.zhihu.com/p/28085204) 20 | 21 | 当然必不可少的,还有一本书:《利用 python 进行数据分析》,我用的是微信读书的电子版。 22 | 23 | ### 准备工作:安装环境 24 | 25 | 我用的是 windows10 64 位操作系统,之前已经安装好了 anaconda, python3.7, pip 等。这次需要新增安装 3 个库。 26 | 27 | 你可能会困惑,我如何得知应该安装哪些库呢?很简单,顺着官方的 10 分钟搞定文档逐行尝试,最初的 3 行就是答案。 28 | 29 | ```python 30 | 31 | import pandas as pd 32 | import numpy as np 33 | import matplotlib.pyplot as plt 34 | 35 | # 在我的本地编辑器输入这 3 行代码后,import 部分被打了红色波浪线,这就是提示我未安装相应模块。 36 | 37 | ``` 38 | 39 | 我的本地编辑器用的是 vscode,如果我未安装某个模块,它会有如下提示。但用 anaconda prompt 安装以上 3 个库时并不顺利,一方面终端告诉我已经安装好了,另一方面编辑器中依然有未安装的提示。 40 | 41 | ![img](https://user-images.githubusercontent.com/31027645/62598685-cc573180-b91c-11e9-8eb0-eeeb8e2d0cd7.png) 42 | 43 | 在网上搜并尝试了后,最终是通过 windows 10 自带的 cmd 调出终端执行 pip install 才搞定。 44 | 45 | ![img](https://user-images.githubusercontent.com/31027645/62598883-4c7d9700-b91d-11e9-9fe5-feace692fba9.png) 46 | 47 | 如何验证自己是否安装成功呢?作为新手我也曾困惑于此,这个经验分享如下。 48 | 49 | 方式一,是启用 python 自带的 IDE 输入 `import pandas as pd`并回车,如无报错,才说明 pandas 安装成功了。 50 | 51 | 方式二,是 vscode 中创建新的 `.py` 类型的文件,输入 `import pandas as pd` 后无任何红线提示。 52 | 53 | ### 准备工作:python 基础 54 | 55 | 学 pandas 的最少必要知识是什么呢?完全没学过 python 恐怕非常困难。 56 | 57 | 我自己是仅掌握了 python 的基础知识,对部分进阶知识有所了解,即《自学是门手艺》中的内容。这个程度,到底够不够,我没办法预判,但我可以边走边看。 58 | 59 | 当然,学习新技能的最大资源其实是时间和精力。这个就不再多说。 60 | 61 | 准备工作就到此为止。 62 | 63 | ## 二、找到入口 64 | 65 | ### 太难没耐心,换姿势找线索 66 | 67 | 接下来的学习过程,每个人有自己特定的方法论或习惯。我的方法或节奏不一定适合你,仅供参考。 68 | 69 | 最初我先顺着官网的 10 分钟文档,在自己的本地编辑器逐行敲下代码并运行。除了对于 output 感到小惊喜外,整个过程一脸懵逼。花了半小时左右,学了数据的创建和获取,我便没耐心逐行尝试了。 70 | 71 | 没耐心当然不是不学,而是换一个姿势学。我快速浏览了官方的 10 分钟文档下面的内容,大概是讲数据的增删改查文件读取绘图之类的处理。我的一个基本判断是: 72 | 73 | > 我遇到的第一个难点,在最前面。我应该优先解决这个难点,要不然后面只会如同天书。 74 | 75 | 于是我检索了一些中文的文章,并快速找到一个关键信息: 76 | 77 | > 最好对 python,pandas 和 numpy 有一丢丢的小了解,最起码对 series, array, dataframe 等基本概念有所了解。 78 | 79 | 我对 python 当然是有一丢丢的小了解,但对 pandas 这不刚接触呢。numpy 更是首次听说,`series, array, dataframe` 这三个概念很陌生啊! 80 | 81 | ——慌什么!这不刚抓到了最重要的线索?大喜事啊。所谓线索,就是作为关键词去搜索别人的好文章来读,筛选并构建自己所需的知识。 82 | 83 | 得出判断: 84 | 85 | > **我的入门关键,就是先理解 `series, array, dataframe` 这三个概念。** 86 | 87 | 88 | ### 用已知理解未知 89 | 90 | 从第一个概念开始:series 是什么呢? 91 | 92 | 欠缺背景知识的人,通常比较难抽象地理解新知识。我的办法是:写一些代码来让自己形象地认知。既然在官网的 10 分钟文档最初部分创建对象时,也用到了列表 list 和字典 dict,那么,我就用这 2 个数据容器,来理解 series。 93 | 94 | 以下这段代码,我逐步写然后运行,理解后再继续写,再运行…… 95 | 96 | ```python 97 | 98 | """ 99 | 形象地理解 list 与 series 的关联和区别。 100 | """ 101 | 102 | import pandas as pd 103 | import numpy as np 104 | 105 | list_a = [1,3,5,6,'好','good'] 106 | series_x = pd.Series(list_a) 107 | 108 | print(list_a) 109 | print(type(list_a)) 110 | print() 111 | 112 | print(series_x) 113 | print(type(series_x)) 114 | print() 115 | 116 | ``` 117 | 118 | 119 | ```python 120 | 121 | """ 122 | 形象地理解 dict 与 series 的关联与区别。 123 | """ 124 | 125 | import pandas as pd 126 | import numpy as np 127 | 128 | dict_a = {'Ohio':35000,'Texax':71000,'Oregon':16000,'Utah':5000} 129 | series_y = pd.Series(dict_a) 130 | 131 | print(dict_a) 132 | print(type(dict_a)) 133 | print() 134 | 135 | print(series_y) 136 | print(type(series_y)) 137 | print() 138 | 139 | ``` 140 | 141 | 142 | 有了形象的认知,再继续读别人有关 `series` 的文章,就比较好懂一些。通常 `series` 的文章也会提及`dataframe`,关于两者的区别与关联,让我好理解的一个说法是: 143 | > 区别: 144 | > series,只是一个一维数据结构,它由 index 和 value 组成。 145 | > dataframe,是一个二维结构,除了拥有 index 和 value 之外,还拥有 column。 146 | > 联系: 147 | > dataframe 由多个 series 组成,无论是行还是列,单独拆分出来都是一个 series。 148 | > 来源:[pandas 中 Series()和 DataFrame()的区别与联系](https://blog.csdn.net/missyougoon/article/details/83301712) 149 | 150 | 通读一些文章后,我现在能清晰一些理解 `series` 和 `dataframe` 了,不再像之前那样模糊。此时面临 2 个选择,其一是继续按官网文档挨个尝试它的各种方法,其二是从一个具体需求切入,看看怎么用。 151 | 152 | 我已经知道 pandas 大概有哪些功能或方法,能做些什么,只是还不知道具体怎么做。目前备查的材料充分且可靠,我对材料的结构也比较清晰,于是我选择方向二,找一个具体的需求来动手实操。实操的过程中,来搜查使用以上知识点。 153 | 154 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190809_适合新手的 python pandas 学习笔记(2).md: -------------------------------------------------------------------------------- 1 | ![banner](https://press.one/thumbnail?width=792.0000171661377&url=https://static.press.one/05/b8/05b8cd6f7762d4f0668557a80d0c30f241b4617f5be6dd0decf3b74ed5341dc3.jpg) 2 | 3 | ## 回顾一下昨天的学习笔记 4 | 5 | 在[适合新手的 python pandas 学习笔记(1)](https://mp.weixin.qq.com/s/87FsOZE2AVAP5fD7dbOdXw)中,准备工作已经完成。同时我也通过探索找到了适合自己的学习入口:先了解 pandas 所特有的数据结构`series`与`dateframe`。 6 | 7 | 昨天,我并没有按照官方的[`10 minutes to pandas`](https://pandas.pydata.org/pandas-docs/version/0.22.0/10min.html)完整地练习一遍,但我已经知道这两种数据容器**有**增删改查、IO 处理等各种方法,只是还没用过。我决定,结合一个实际的需求试着把 pandas 先用起来。我预料到这个过程中将会遇到很多新知识,但我心中有数一点不慌,无非是根据实际所需在手头材料中检索而已,现学现用吧。 8 | 9 | 这种不会就敢用的学习方法,其实非常“大胆”,并不适合绝大多数人。为什么呢?因为有些人善于把遇到的困难经自己的大脑认知加工成挫败体验,而我似乎很善于解决问题和主动调控成长体验,于是我在拆解和反复地找到答案的过程中,收获的是持续的成就感。 10 | 11 | 回顾和整理昨天顺手做的学习笔记,使之可读性加强到可公开发布,是我做心理建设的一种方法。完成这一步后,我就开始聚焦今天的学习。 12 | 13 | ## 用什么姿势解决什么需求? 14 | 15 | 实际需求如下: 16 | 17 | > 通过 api url 读取 json 数据,对数据进行统计分析后,输出结果到 excel。 18 | 19 | 上上个周末,我已经完成了该需求,下文所指代的原有实现方法即是指该脚本。代码有 300 行,有一半是用 `xlwt` 把处理结果写入 excel 文件。另外 150 行代码,处理的是数据的提取、数据指标的定义与演算。未来我还将统计更多具体的数据指标,可以预想到逻辑会更加复杂,代码只会更加臃肿。 20 | 21 | 昨晚临睡前,我用手机浏览了一点《利用 python 做数据分析》中的代码,简洁而优雅,我非常期待用 `pandas` 重新满足我的需求。 22 | 23 | 今天的心理建设已经完成,动力很足。然后我写下了需求,然后按惯例把需求拆解,思考每个步骤如何用 `pandas` 实现,……但我突然意识到这种做法是错误的。——这是一个重要的思维岔道口,这个思维过程是一闪即过的,所幸我还是抓到了。 24 | 25 | 电光闪石之间,我意识到,我原来的做法是在用零散的方法处理零散的数据,但 pandas 的关键就是结构化的数据。 `api url` 提供的 `json` 数据就是结构化的!想法涌现,有些甚至来不及显现为语言,我只是模糊地意识到,自己的原有实现是低纬度、低效率的,我不能再把结构化的数据打散,我应该用 pandas 特有的做法。 26 | 27 | 我再次看了看` api url` 所展现的 `json` 数据结构。 28 | 29 | ## 源数据的结构 30 | 31 | 从 api url 获取到的 json 数据结构是这样的: 32 | 33 | ```json 34 | 35 | { 36 | "comments" : [{},{},…,{}], 37 | "total" : 123, 38 | } 39 | 40 | ``` 41 | 42 | 然后 `comments`的值,是个由字典构成的列表。每个字典就是一条`comment`,它再次嵌套了一个`user`字典(为了节省篇幅,我已经简化了很多字段),是这样的: 43 | 44 | ```json 45 | 46 | { 47 | "created_at": "2019-07-31 22:15:29.658500+08:00", 48 | "up_vote_count": 0, 49 | "id": 447, 50 | "user":{ 51 | "admin" : false, 52 | "username" : "liujuanjuan1984", 53 | }, 54 | } 55 | 56 | ``` 57 | 58 | 无论是字典,还是列表,在`pandas`处理为`series` 或者`datafrome`,都是容易的。 59 | 60 | ## 今日的学习成果 61 | 62 | 为了完成这个需求,我读`pandas`官网文档,不仅仅是 10 分钟上手部分,更多看的是 IO tools 那部分。`pandas`的方法如此简约、直白。相关的方法,拿来即用。只不过必须要知道自己想要什么。比如,“如何从 url 获取数据?”或者“如何从嵌套的字典中,取出内层的字典,然后把数据和外层字典数据合并?”在获取此类疑问的答案时,我也走了些弯路,但一旦知道答案后,就再次惊喜于`dataframe`作为数据容器,如此好用。 63 | 64 | 没有花太多时间,我就用`pandas`完成了从 api url 获取数据,并与文件读写交互这个需求。 65 | 66 | 调试完代码后,我哭笑不得,和我原来的实现方法相比,简直一个在天,一个在地。揣摩了许久,我越来越惊喜,自己昨晚怎么就一下子抓到了重点:**用 pandas 的核心,应该是把数据整理为结构化的数据后再用它的方法处理**。 67 | 68 | 代码仅有区区 10 行。 69 | 70 | ```python 71 | 72 | import pandas as pd 73 | import os.path 74 | 75 | url = 'https://url.path'# api url 不能公开,现在放的这个是假数据 76 | rlt_file = 'd:/pandas_rlt.xls' 77 | 78 | df1 = pd.read_json(url) #读出来的数据,就是 dataframe 79 | df2 = pd.DataFrame([x for x in df1['comments']])#把 comments 抽出来 80 | df3 = pd.DataFrame([x for x in df2['user']])#把 comments 内嵌的 user 抽出来 81 | df = pd.concat([df2,df3], axis=1)#把 user 数据和 comments 数据合并 82 | df.to_excel(rlt_file, encoding='utf-8') #数据写 excel 文件 83 | xdf = pd.read_excel(rlt_file, encoding='utf-8') #从 excel 文件读数据 84 | 85 | ``` 86 | 87 | 你或许好奇我原来怎么写。下面是比较臃肿的原实现方法。在上上周末,我能写出下面的脚本,且是首次根据需要检索到并安装使用 `urllib.request`,`json`,`xlrd`,`xlwt`,也挺不容易的。 88 | 89 | ## 原有的实现方法 90 | 91 | 我原有的实现方法是,通过 `urllib.request` 读取 `api url` 网页拿到 `string` 格式的数据,并用`json.loads`方法转换为字典数据。且为了降低后续每次从 `api url` 获取的数据量,已有的数据会保管在本地的,于是需要处理 `dict` 字典数据到文件的读写处理。这一部分代码如下: 92 | 93 | ```python 94 | # 读取 api url 内容并返回为字典 95 | def read_url_to_dict(url): 96 | import urllib.request as request 97 | webpage = request.urlopen(url) 98 | data = webpage.read() # 99 | content_str = data.decode("utf-8") # 100 | #如果你的编辑器提醒你没有安装 json,你搜索一下安装即可 101 | import json 102 | content_dict = json.loads(content_str) 103 | return content_dict 104 | # 字典内容写入.json 文件 105 | def dict_write_json_file(content_dict,file_url="d:/json_file.json"): 106 | import json 107 | import os.path 108 | with open(file_url,'w',encoding='utf-8') as write_f: 109 | json.dump(content_dict,write_f,ensure_ascii=False,sort_keys=True, indent=4) 110 | print('数据 dict 已写入文件:',file_url) 111 | # 读取 .json 文件 生成 dict 字典 112 | def read_json_file_to_dict(file_url="d:/json_file.json"): 113 | import json 114 | import os.path 115 | with open(file_url,'r',encoding='utf-8') as read_f: 116 | content_dict = read_f.load(read_f) 117 | return content_dict 118 | 119 | ``` 120 | 121 | 通过以上处理,我拿到的原始数据即是字典形式。然后我开始了对数据的肢解和拼接……来定义统计数据指标。下面粘贴的代码只是一部分。这部分在掌握了 pandas 的写法后再来看,真是“小小幼儿学走路,歪歪扭扭真可爱”。 122 | 123 | ```python 124 | 125 | how_many_comms = data_dic['total']#总的留言条数,int 126 | all_comms_list = data_dic['comments']#总的留言列表,list 127 | 128 | content_list = [] 129 | date_list = [] #留言不为 0 的日期,list 130 | time_list = [] 131 | urs_list=[]#留言的用户列表,list 132 | up_vote_list=[] 133 | comms_at_questions = 0 #在习题下的留言条数,int 134 | comms_at_posts = 0 #在章节下的留言条数,int 135 | 136 | for comm in all_comms_list: 137 | content = comm['content']#留言的内容,str 138 | created_at = comm['created_at']#留言创建日期时间,str 139 | created_date = created_at[:10]#留言创建日期 140 | created_time = created_at[11:13]#留言创建时间,仅取小时位 141 | object_type = comm['object_type']#留言的类型,习题/章节,str 142 | up_vote_count = comm['up_vote_count']#留言的点赞数,int 143 | user = comm['user']#留言的用户数据,dic 144 | urs_name = user['name']#留言的用户名,str 145 | 146 | content_list.append(content) 147 | date_list.append(created_date) 148 | time_list.append(created_time) 149 | urs_list.append(urs_name) 150 | up_vote_list.append(up_vote_count) 151 | 152 | #用户列表:已留言的用户列表,list 153 | urs_name_list = list(set(urs_list.copy())) 154 | #用户数:已留言的用户总数,int 155 | urs_num = len(urs_name_list) 156 | #用户的留言条数:每个用户的累计留言条数,list 157 | comms_by_urs = list_count(urs_list.copy()) 158 | comms_by_urs.sort(key=lambda x:x[1],reverse=True) 159 | 160 | ``` 161 | 162 | 原实现方法最臃肿的,就是有关 `xlwt` 的处理了…… 163 | 164 | ```python 165 | 166 | #设置表格样式 167 | def set_style(name,height,bold=False): 168 | import xlwt 169 | style = xlwt.XFStyle() 170 | font = xlwt.Font() 171 | font.name = name 172 | font.bold = bold 173 | font.color_index = 4 174 | font.height = height 175 | style.font = font 176 | return style 177 | 178 | #创建子表 179 | import xlwt 180 | f = xlwt.Workbook() 181 | sheet1 = f.add_sheet('留言总览',cell_overwrite_ok=True) 182 | sheet2 = f.add_sheet('留言用户',cell_overwrite_ok=True) 183 | style = set_style('宋体',220,False) 184 | 185 | sheet1.write(0,0,"统计日期",style) 186 | sheet1.write(0,1,date_today,style) 187 | sheet1.write(0,2,time_now,style) 188 | 189 | sheet1.write(2,0,"留言的内容分布",style) 190 | sheet1.write(3,0,"ALL",style) 191 | sheet1.write(4,0,"习题",style) 192 | sheet1.write(5,0,"章节",style) 193 | sheet1.write(3,1,how_many_comms,style) 194 | sheet1.write(4,1,comms_at_questions,style) 195 | sheet1.write(5,1,comms_at_posts,style) 196 | sheet1.write(3,2,'%.2f%%'%100,style) 197 | sheet1.write(4,2,'%.2f%%'%(100*comms_at_questions/how_many_comms),style) 198 | sheet1.write(5,2,'%.2f%%'%(100*comms_at_posts/how_many_comms),style) 199 | # 还有一百多行 sheet1.write 语句没贴 200 | f.save(saved_url) 201 | 202 | ``` 203 | 204 | 特别可笑的是,在设置 sheet.write()的行列参数时,要一条条在 excel 表格中布好,然后小心翼翼逐个修改对应的参数值。 205 | 206 | 为`pandas`作为数据统计与分析领域的最佳实践而干杯! 207 | 208 | ## 下一步学习计划 209 | 210 | 通过第 2 天的以用促学,我对`pandas`代码的简约,`dataframe`数据结构的好用,印象深刻,赞誉不断。我掌握了`pandas`创建`dataframe`的方法,也掌握了`pandas`部分 IO 处理的方法。 211 | 212 | 接下来我依然围绕自己的这个实际需求,用`pandas`来处理数据的统计与分析。我能预料到的是,这将反复练习增删改查中的“查”,相关的具体方法是什么?我不会,但我不着急,因为准备工作中的学习材料中都有,我想用,立即查就是了。用多几次,我自然就懂了。 213 | 214 | 我的学习笔记并不罗列到处可以查到的知识点,即便罗列的再好也不如官方文档权威全面。我想记录的,是自己的学习过程与学习思路,一些重要的资源或者坑。这些是对我非常有价值的东西,对大家也或许有一些借鉴意义。 215 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190812_30多岁想转行,零基础学编程,来得及吗?能找到功好工作吗?.md: -------------------------------------------------------------------------------- 1 | # 30 多岁想转行,零基础学编程,来得及吗?能找到功好工作吗? 2 | 3 | 另一个标题:30 多岁 0 基础学编程,想当程序员,来得及吗? 4 | 5 | “30 多岁想转行,零基础学编程,来得及吗?能找到好工作吗?”这类问题,总是反复出现。尤其是最近我受《自学是门手艺》鼓舞,也借着参与 [xue.cn](https://xue.cn/) 的契机想要把 python 学的全面而完整,也总有朋友找我打听此类话题。 6 | 7 | 本文便是我对这类问题的看法。不过,我把它拆分为 3 个更细的话题,如果你要阅读,一定记得读完全文。 8 | 9 | 10 | ## 1、30 多岁,零基础学编程,能学吗? 11 | 12 | 当然能学,一点也不晚。 13 | 14 | 事实上,这一辈子就该持续学习和成长。很多人刚刚三十多岁,就给自己判了“死刑”,认为自己再也无法学会什么东西了,很是可悲 。 15 | 16 | ## 2、学了编程,一定能找到编程的工作吗? 17 | 18 | 有没有编程方面的好工作,关键点就一个,这取决于你在用人市场是否有竞争力。 19 | 20 | 那自学编程的人,如何提高在用人市场的竞争力呢? 21 | 22 | 一方面是基础功要扎实。 23 | 24 | 1) 所掌握的那门语言要尽可能全面完整地学到位。除了搞定你手头的教程或一两本书,还有官方文档、cookbook 乃至源码,也应该要搞懂。 25 | 26 | 2) 计算机专业的基础课也要自己补足,不能只是掌握特定语言的那一点内容。 27 | 28 | 有些企业或用人单位不喜欢招聘培训班出来的人,其实本质上是不喜欢只学皮毛或学的过窄的人,这类人一旦实战要么无法干活,要么就是行走的 bug 制造机。 29 | 30 | 另一方面要多参与项目,刷实战经验。 31 | 32 | 1) 既可以参与开源项目,作出贡献, 33 | 34 | 2)也可以自己 solo 写小项目或者和人合作做 side project。 35 | 36 | 实战经验可以说是非常重要了,刚开始不容易找工作,就只能先找这样的项目来刷实战经验。 37 | 38 | ## 3、成功入职程序员,一定会比自己之前的工作好吗? 39 | 40 | 不一定。 41 | 42 | 有一些程序员在本职工作浑浑噩噩许多年,也未见能力或薪水显著成长。这一方面要看企业或项目是否在上升通道,甚至可能仅仅是当事人多次运气不佳,没碰到好项目好企业。另外一方面更要看自己是否有持续的成长,甚至是高出平均水平的成长。 43 | 44 | 但很显然,程序员是一个需求面很大的岗位,且只要你有不错的学习能力,在某一门语言或方向上有自己的可靠积累,总是能让自己找到新的工作。 45 | 46 | 说到底,程序员也是一个职业。在你零积累的赛道上,你和别人竞争,你当然一开始就是弱势的。只不过大家的加速度和速度不同,如果你对编程没有深刻的热爱,没有持续的学习力,你拿什么和人家竞争呢? 47 | 48 | ## 必要的补充 49 | 50 | 有人看了第二、三点的大实话,就会想:既然学了编程,不保证自己能找到编程工作,就算找到也不保证比之前的工作好,那就干脆不学了。 51 | 52 | 这个逻辑是不是超级熟悉? 53 | 54 | 职场逻辑是,因为你能力到位,在用人市场有竞争力,所以你才有好工作。 55 | 56 | 这个逻辑是,因为没有人许诺给我一个好工作,所以我干脆不学,不提高能力了。 57 | 58 | 你觉得,是个人的逻辑大,还是职场的逻辑大? 59 | 60 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190816_零基础自学 python3 的最少必要资源(极简推荐).md: -------------------------------------------------------------------------------- 1 | # 零基础自学 python3 的最少必要资源(极简推荐) 2 | 3 | 4 | 当你想要自学 python3 编程时,面临的第一个问题是:“**我应该看哪些书/教程/视频?**”我有一份亲自验证过的**极简**答案。我刚经过 python3 入门阶段,这份答案是对编程小白有用的、最少必要入门资源。 5 | 6 | ## 首推 python 官方文档 7 | 8 | 我很少看到有攻略、教程、书籍、视频等强调 python 官方文档的重要性。这其实并不妥当,官方文档才是本源,是 python 入门与精进道路上的必读物。 9 | 10 | python 官网:https://www.python.org/ 11 | 12 | 尤其是 python 官方文档: https://docs.python.org/zh-cn/3/contents.html 13 | 14 | **别担心自己的英语。**如果刚开始不想让英语难住自己,你可以勾选简体中文,只看中文版的官方文档。等你开始找到编程的感觉,适应了自学的节奏,不再对英语发怵时,最好还是开始读英文原文,最起码和中文版对照阅读,多用用英语你更容易掌握英语。 15 | 16 | ![image](https://user-images.githubusercontent.com/31027645/63156768-02489400-c048-11e9-82e6-c5612d78ea89.png) 17 | 18 | **官方文档最权威,也是最新最全的。所提供的内容质量也最高。** 19 | 20 | **如何使用官方文档?**按目录挨着顺序看一遍?不建议如此,主要是这会让新手发怵畏难。刚开始**直接用搜索引擎(搜狗、百度、谷歌等)的方式来使用官方文档**即可。比如用这句话搜:`列表 site:python.org` 就是指定搜索引擎在 `python.org` 网站上找结果。点开搜索结果,就是 python 官方文档中关于列表的内容,且是中文的。等你过了 python 新手的扫盲关卡,再慢慢通读官方文档,或根据具体需要认真通读某个章节,都是极好的。 21 | 22 | ## 心理建设与自学方法很有必要 23 | 24 | 零基础自学编程,其实最缺的就是心理建设。各种奇怪、莫须有的担心、自我否定。这方面的好书不多,适合编程自学的新手则更少,对我帮助非常大的,是这本书: 25 | 26 | ![image](https://user-images.githubusercontent.com/31027645/63157328-438d7380-c049-11e9-8427-514c5b4bf80c.png) 27 | 28 | 尤其是书中的这句话: 29 | 30 | > 要么干脆别学算了,何必把自己搞成一个半吊子? 31 | 32 | 这本书在京东,当当都有不错的优惠力度,你可自行买一本。如果好奇我的自学编程心路,可以看我写的另外一篇文章:[《35 岁有儿有女,为什么她开始自学编程?》](https://juejin.im/post/5d51156ae51d4557dc774e70) 33 | 34 | 不想立即花钱的,可以用电脑直接访问它在 github 上的开源项目: 35 | https://github.com/selfteaching/the-craft-of-selfteaching 在电脑中用浏览器访问这个地址,就能读到此书的电子版。放心,不是盗版,是作者主动开源的。 36 | 37 | 李笑来《自学是门手艺》这本书除了帮你做心理建设,还能帮你提高自学能力,同时更是 python 官方文档的极好补充。读过此书,再看 python 官方文档,会容易许多。 38 | 39 | ## 编程环境必须要自己安装配置吗? 40 | 41 | 以前想要自学编程,确实要花上半天乃至一两天的时间安装配置调试环境,才可能写上一句`hello world`。不过这对编程小白非常不友好。如果你对自己安装配置编程环境没概念,或者遇到困难无从解决感到发怵,则可以来 https://xue.cn/ 用你的 github 账号授权登录,之后花 15 元买 30 天 的订阅服务,就无需自己安装配置环境,直接在网页上学习编程、直接写代码、运行代码了。 42 | 43 | xue.cn 上有《自学是门手艺》的电子版内容,也很快会有第二本甚至更多编程的优质内容。除了阅读和编写调试代码,你在这个网站还能聊天、留言,做习题等等,这些会让自学编程的过程不那么寂寞、无助。 44 | 45 | 书是免费的,它的收费主要是因为配置了 jupyter 的云服务,让你无须自己折腾安装一堆东西,就能直接用到 jupyter lab 的交互式特性。对编程新手来说,非常惊艳。 46 | 47 | ![image](https://user-images.githubusercontent.com/31027645/63158035-f7433300-c04a-11e9-9e5c-146cc2cc9a0a.png) 48 | 49 | 50 | ## 一本书可能是不够的 51 | 52 | 虽说有 python 官方文档、《自学是门手艺》和 https://xue.cn/ 你已经可以畅快地开始自学 python 编程了。根据《自学是门手艺》书中建议,一本书总不太够,最好再多准备点内容作为参照阅读,实体书,电子书、视频教程都 OK。 53 | 54 | 我在入门阶段,并没有额外准备其它书籍。通读完《自学是门手艺》并做了一些 python 的习题实操后,我只是又看了下面这本书《笨办法学 python》,尤其是关于模块、类的部分,它的讲解非常细致。这书是大名鼎鼎的《Learn Python The Hard Way》的中译版。 55 | 56 | ![image](https://user-images.githubusercontent.com/31027645/63158408-c44d6f00-c04b-11e9-8f5b-0260de20e6c2.png) 57 | 58 | 等你发现自己过了入门关卡,就可以开始选择具体方向来精进,或者反复读官方文档、手头的书来查漏补缺、夯实基础功。我自学 python 过了入门关后,正在自学 python 的一个重要库 pandas 用作数据分析,看的是这本书《利用 python 进行数据分析》。 59 | 60 | ![image](https://user-images.githubusercontent.com/31027645/63158592-29a16000-c04c-11e9-8c10-40056a2c4054.png) 61 | 62 | 63 | 以上便是我自学 python3 的过程中实际上用到的资源/教程/书籍/工具,并不多。在我自学 python 编程的过程中,充满了高效、惊喜、成就感等美好的体验,也祝愿你的编程之旅启动顺利。 64 | 65 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190820_老婆说我自学 python 是不务正业.md: -------------------------------------------------------------------------------- 1 | # 老婆说我自学 python 是不务正业 2 | 3 | 4 | ![免费图片-pixaby](https://user-gold-cdn.xitu.io/2019/8/20/16caf3c4ba593761?w=960&h=639&f=jpeg&s=157103) 5 | 6 |
备注:题图源自 pixabay.com
7 | 8 | 今天是 2019 年 8 月 20 日,我启动了一个小型的倾听项目:**`你自学 `python` 学不下去了?你说,我听。 `** 发在了我的朋友圈和一两个微信群。如果你想找我聊聊,请微信私聊我约时间。 9 | 10 | 找我聊的人有点多。下午,我和一位中年男士语音聊过,征得他的同意,把我们的聊天转化为这篇文章,希望能给遭遇相似情形的人带去一些启发。下文简称他为 X 吧。 11 | 12 | X 约我时讲的第一句话,令我印象深刻,他说,“我中枪了,想找你抢救一下”。这让我意识到,X 内心依然是想要学编程的。 13 | 14 | X 人到中年,家中有妻,有两个小孩。学历不高,读到高二便离校了,目前也有工作,淘宝开店多年,给自己打工。早年赚到一些钱,近年流量下滑严重,营业额不稳定,当前收益仅够糊口。我细问他的经营策略。X 倒没有什么可藏私的,到市场拿货,放到淘宝卖,赚个差价而已;定价策略、市场推广、数据分析之类,一概都没用过。我提及这些词时,X 不好意思地说,这些都太高大上了。 15 | 16 | X 开始自学 `python` 是受李笑来《自学是门手艺》的影响,在 `xue.cn` 上边读边练。他说,开始几天劲头非常足,很喜欢学编程,也取得一些不错的进展,点亮好几个成就。其后某次和妻子聊天,妻子不支持他学编程,认为他可能要学很久才能见成效,并不能很快为家庭带来收益,这对他已有的淘宝店铺业务没有帮助,也无法让他未来转换行业找工作。妻子说,何况我们已经到了这个年纪,该现实地考虑如何赚钱,我们早已经过了学习阶段。和妻子的沟通显著影响到了 X 的自学状态,自那之后他试着继续学,但劲头没了,读了好一会儿也不知道刚才读了啥。 17 | 18 | 我先和他交流了两个问题,第一是,有无闲暇时间用来学习,第二是,如何解读妻子的观点。 19 | 20 | 我问他,如果你不再自学 `python`,是否有闲暇时间?他说有的,工作不忙,闲暇时间有许多。我又问他,你是否在刚开始自学 `python` 时过于投入,导致陪伴妻子、分担家务比如帮忙照看孩子的时间都被占用了?语音中他愣了一下,说,是的……确实有所忽略。 21 | 22 | 我们继续交流下去。我说,我并不认为妻子会刻意打压你追求上进。表面来看,妻子不支持你自学 python 是在否定你的行为,其实是在表达自己未被满足的需求。 23 | 24 | 妻子的需求有二。其一是从投入产出比的角度来看,她误以为学会一门技能所需要的时间投入非常大,而那收益预期她完全看不到或者持悲观看法。其二是你短期投入很多时间精力自学 `python`,无意中对妻子和家庭有所忽略。在不看好学习成效的情况下,她自然不愿意因此少了你的亲密陪伴和家务分担。 25 | 26 | 满足妻子的第二项需求,只要你的意识到位,如何做你当然懂啦,就不用我多说。之前你只是忽略了这一点。 27 | 28 | 满足妻子的第一项需求,你目前已有哪些想法呢?X 说他想做一个最小可行性的产品,让妻子体会到编程能做出赚钱的产品。具体来说,妻子的闺蜜在朋友圈发淘宝客链接赚点外快,但闺蜜使用的是别人开发的软件,赚的淘宝客佣金已被软件开发者抽掉一些,闺蜜能到手的佣金就少了。X 说,如果我自己做个小程序,可以很方便地把淘宝链接转换成淘宝客链接,正好能向妻子证明学编程不是不务正业,学编程确实能做出产品,提高效率,产生收益。 29 | 30 | 至此,总结我的看法如下: 31 | 32 | 其一,`python` 对淘宝店铺业务当然是有用的。 33 | 34 | 在你开淘宝店铺商业逻辑已理顺的情况下,`python` 能帮助你知己知彼,找到业务瓶颈、有效突破。比如,把你的淘宝店铺业务的各环节的所有数据统筹起来做数据分析,是知己;爬取和监控同品类或竞品数据,是知彼。数据分析和爬虫脚本,我都尝试了,你也看到我很快就学到了能用的地步。 35 | 36 | 但我需要强调一点,`python` 是实现你的商业逻辑的工具。如果你开了这么多年淘宝店铺,吃的是平台早期红利,全凭本能运作业务,还谈不上有什么自己的商业逻辑。这么多年,你没靠早期红利、长期积累越做越大,反而随着竞争加剧败下阵来,你缺的是什么呢?缺的就是学习能力。 37 | 38 | 人到中年,确实不再是学生了,我们难得有机会专注地学习。可是想过没有,人群中的大多数,生来普通,学生时期无法专注学习;离开学校后,主动放弃了学习和成长。学习是停滞了,接下来步入社会、成立家庭所面临的难题,则只见增多没见少呀。一旦主动放弃学习,普通人解决难题的能力丝毫上不去。 39 | 40 | 学习的本质,不是抓来一本书死记硬背,或者考个高分拿个凭证。学习的本质,更像是把未知转变为已知,学习的成效,是能给问题找到至少一个甚至多个解决方案。你想着用 `python` 来写淘宝客链接的自动处理,是个很好的开始。 41 | 42 | 其二,不应该对妻子承诺自学 `python` 编程的美好蓝图。 43 | 44 | 你说,你能靠自学编程写个产品帮咱家自动赚钱。你说,淘宝店铺咱们开不下去了,等我学成能靠这个本事换行去做程序员。在你描绘的蓝图尚未发生时,你的承诺越多,极大可能都会数倍转化为你的压力。人性决定其结果大概率是你做不到(100 个人开始自学,能有 5 个人学到底,就很难得),然后妻子对你的信心进一步下降;更可怕的是什么?是自我认可度也随之大幅度**永久**下降。 45 | 46 | 那要怎么办?悄悄在心底立小志、瞅着空闲持续坚持就好。至于她看到你还在自学编程心生不满,你就说:“反正这闲暇时间拿来刷手机打游戏也是浪费嘛,我学点编程纯粹兴趣啦,起码未来还能指导咱们孩子出人头地,老婆你说是不是?”更何况,你原本该做的,并没有落下:原本的工作没落下,原本你该陪她的、该分担的家务,照做不误。她能产生多少微词呢? 47 | 48 | 当你做闲钱投资时,有人说,赶紧买这个,三个月后铁赚。你会怀疑吧?当你学习时,有人说,赶紧学这个,三个月后铁定见成效。你会怀疑吗?当然,我们这批通过 xue.cn 自学 `python` 的人,都是自发的,并没有得到这方面的“诱惑”。可人呢,却不由自主地希望从一开始就从谁那里拿到一个承诺,对你说,你学 3 个月后铁定能找到工作或写什么脚本赚到钱。——你仔细品品看,这里面是不是有思维陷阱?你再左右观察看看,拿这个“承诺”诱惑你高额付费买课程的,是不是多了去? 49 | 50 | 你恰好有闲暇,有兴致,刚开始自学 `python` 的效果不错,那就继续学呗。轻拿轻放,搞不好我们还真成为了那学到全面完整的 5%,其后人生岂不是时时收获意外惊喜? 51 | 52 | 最后当我把这篇文章预览发给 X 看时,他由衷感慨:“在今天的谈话中,我深刻意识到自己对家人的关注及陪伴过少,自己有错的。”——替你妻子高兴,她的第二项需求有望啦。 53 | 54 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190905_对目标网站 7 天内发起百万次 api 请求,是攻击还是正常请求?.md: -------------------------------------------------------------------------------- 1 | # 对目标网站 7 天内发起百万次 api 请求,是攻击还是正常请求? 2 | 3 | ### 关键词: 4 | 5 | 爬虫,大数据,编程 6 | 7 | ### 描述: 8 | 9 | 目前准备爬取一家目标网站的公开数据,预测将累计发起 120 万次 api 请求,每个爬虫脚本都是单进程、单线程。把想要爬取的数据,按关键字段拆分 20 多段,分别安排给不同的爬虫同时爬取。每个爬虫脚本每次请求的响应和处理时间,约为 20 秒。即平均每秒至少 1 次请求。 10 | 11 | ### 疑问: 12 | 13 | 这个请求量,对目标网站,是攻击,还是正常? 14 | 15 | ### 思路: 16 | 17 | 1、爬虫的伦理:不应对目标网站的业务产生干扰或影响,也不应爬取目标网站未公开数据。 18 | 19 | 2、爬虫的性能:要计算和掌握自己的爬虫群的性能,并根据目标网站的业务判断该性能是否超出目标网站的承受范围。爬虫群的性能,一方面是对目标网站产生的流量,一方面是本地流量与 IO 读写,内存、CPU 等一般没啥问题。 20 | 21 | 3、爬虫的安全:一方面考虑来自目标网站的反爬,另一方面考虑伦理。 22 | 23 | ### 结论: 24 | 25 | 1、爬虫群本地性能无压力。 26 | 27 | 2、目标网站的业务量并不大,当前爬虫群的请求频次明显过高,应至少削减至少一半以上。 28 | 29 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190905_手动生成 N 个爬虫太低效,用 python 实现批量生成多个文件构建爬虫群.md: -------------------------------------------------------------------------------- 1 | # 构建爬虫群很简单,掌握 python 基础功就能做到 2 | 3 | 4 | ### 关键词: 5 | 6 | 爬虫,编程,python,批量文件操作 7 | 8 | ### 描述: 9 | 10 | 目前准备爬取一家目标网站的公开数据,预测将累计发起 百万次 api 请求,每个爬虫脚本都是单进程、单线程。把想要爬取的数据,按关键字段(如 id)拆分多段(每段为 10000 条数据),分别安排给不同的爬虫同时爬取。这些爬虫,我称之为爬虫群。爬取到的数据我都存储在本地的 mysql 中。 11 | 12 | 我是如何实现爬虫群呢?用的是 jupyter lab,创建 N 个 .ipynb 文件,每个文件创建一个 cell,并把初始爬虫脚本拷贝进去,并修改关键参数(如起始 id),然后启动该 cell,即激活该爬虫。 13 | 14 | 如果主动关闭爬虫群,或因为异常重启爬虫群,关键参数(如起始 id),需要检测已爬取的情况,修改该值然后重新启动。 15 | 16 | 创建 20 多个爬虫文件,修改每个爬虫文件中的 id ,用手工操作太低效。这是一个可以优化的地方。 17 | 18 | ### 疑问: 19 | 20 | 如何用 python 脚本实现自动化检测已爬取的情况,修改关键参数,并批量生成或修改爬虫群呢? 21 | 22 | ### 思路: 23 | 24 | 1、需求 1:检测已爬取的情况。所需知识技能:python 读取 mysql 数据,并对数据进行统计分析。我用到 pymysql 和 pandas。 25 | 26 | 2、需求 2:修改关键参数,批量生成爬虫群(N 个文件)。所需知识技能:python 批量创建文件。很简单,for 循环+写文件。 27 | 28 | ### 结论: 29 | 30 | 共用 2 段脚本分别完成需求 1 和 2。实际使用时,先执行脚本 1,再执行脚本 2(当然也可以把两个脚本放在一块,一次性执行完毕)。 31 | 32 | 33 | 1、需求 1 的脚本(关键信息已模糊处理) 34 | 35 | ```python 36 | 37 | import datetime 38 | import pandas as pd 39 | import pymysql 40 | 41 | connect = pymysql.connect('localhost','username','password','database_name') 42 | cursor = connect.cursor() 43 | 44 | sql_search = 'SELECT `id` FROM `table_name`;' 45 | users_data = pd.read_sql(sql_search,connect) 46 | 47 | connect.close() 48 | cursor.close() 49 | 50 | print(datetime.datetime.now(),'准备就绪') 51 | 52 | ids = users_data['id'].to_frame() 53 | id_lvs = [] 54 | for id_lv in range(0,1200000,10000): 55 | try: 56 | x =ids[(ids['id']>=id_lv) & (ids['id']<(id_lv+10000))] 57 | y = x['id'].values.max() 58 | id_lvs.append((id_lv,y)) 59 | except ValueError: 60 | continue 61 | else: 62 | rlt = pd.DataFrame(id_lvs,columns=["from_id","got_to"]) 63 | 64 | ``` 65 | 66 | 2、需求 2 的脚本(关键信息已模糊处理) 67 | 68 | 69 | ```python 70 | 71 | import os.path 72 | import sys 73 | 74 | def check_mkdir(path): 75 | path=path.strip() 76 | path=path.rstrip("\\") 77 | isExists=os.path.exists(path) 78 | if not isExists: 79 | os.makedirs(path) 80 | print(datetime.datetime.now(), ' 创建文件夹 ', path) 81 | else: 82 | print(datetime.datetime.now(), ' 文件夹已存在 ', path) 83 | 84 | path = "dir_name/" 85 | check_mkdir(path) 86 | 87 | 88 | file_content_1 = r"""{ 89 | "cells": [ 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [ 96 | "#爬虫脚本片段 1",""" 97 | 98 | 99 | file_content_2 = r"""\n", 100 | "#爬虫脚本片段 2""" 101 | 102 | 103 | 104 | file_content_3 = r"""\n", 105 | "#爬虫脚本片段 3" 106 | ] 107 | } 108 | ], 109 | "metadata": { 110 | "kernelspec": { 111 | "display_name": "Python 3", 112 | "language": "python", 113 | "name": "python3" 114 | }, 115 | "language_info": { 116 | "codemirror_mode": { 117 | "name": "ipython", 118 | "version": 3 119 | }, 120 | "file_extension": ".py", 121 | "mimetype": "text/x-python", 122 | "name": "python", 123 | "nbconvert_exporter": "python", 124 | "pygments_lexer": "ipython3", 125 | "version": "3.7.3" 126 | } 127 | }, 128 | "nbformat": 4, 129 | "nbformat_minor": 2 130 | } 131 | 132 | """ 133 | 134 | for got_to in rlt['got_to'].values: 135 | start_idi = (got_to//10000)*10000 136 | file_content = file_content_1 + str(got_to+1) + file_content_2 + str(start_idi+10000) + file_content_3 137 | f = open('./dir_name/dir_name%s'%start_idi + '.ipynb',"a",encoding='utf-8') 138 | f.write(file_content) 139 | f.close() 140 | 141 | print(datetime.datetime.now(),"批量创建完毕") 142 | 143 | ``` 144 | 145 | 请留意,在脚本 2 中,我把爬虫脚本的具体内容已经模糊掉了。 146 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190910_pandas数据分析输出excel产生文本形式存储的百分比数据,如何处理?.md: -------------------------------------------------------------------------------- 1 | ## **关键词**: 2 | 3 | python、pandas、to_excel、文本形式存储的数据 4 | 5 | ## **需求描述**: 6 | 7 | 我用 python pandas 写了数据统计与分析脚本,并把计算结果用 pandas 的 `to_excel()` 存入到 `excel` 表格提交给团队。但遇到一个问题:当我的老板和同事们打开 `excel` 文件时,发现百分比数值无法正常显示,提示为“文本形式存储的数据”。 8 | 9 | ![image](https://user-gold-cdn.xitu.io/2019/9/10/16d1ab6070cf5ab4?w=822&h=239&f=png&s=37958) 10 | 11 | 12 | 想让此类百分比数值正常显示,我该怎么办呢? 13 | 14 | ![image](https://user-gold-cdn.xitu.io/2019/9/10/16d1ab6070d7ca60?w=725&h=216&f=png&s=31819) 15 | 16 | 17 | ## **解决思路**: 18 | 19 | 1、必须从自己身上找解决方案。在工作中,当我们需要输出文档给团队查阅,必须自己为文档的质量负责,而非要求或期望我的老板和同事来处理。 20 | 21 | 22 | 2、立即生效、简单好用的笨办法。 23 | 24 | 手动打开 excel 文件,选中“文本形式存储的数据”的一列数据,点击“数据 - 分列” 在弹出的菜单中点击两次“下一次”,然后点击“完成”即可。每次操作只能选中一列数据,如果有多列数据,就要分别操作多次。没办法偷懒。 25 | 26 | ![image](https://user-gold-cdn.xitu.io/2019/9/10/16d1ab6070f121f7?w=874&h=745&f=png&s=94642) 27 | 28 | 该方法看上去有点粗笨,但在紧急情况下,你能立即用,马上解决问题。 29 | 30 | 如果单个文件中此类“文本形式存储的数据”较多,或你需要频繁输出该类文件,那么当然更好的做法是:直接优化脚本,从根源上解决问题。 31 | 32 | ## **解决方案**: 33 | 34 | ### 0、初始脚本 35 | 36 | 为了完成这篇学习笔记,我把此类情况的最小情境构建一些数据,写个小脚本,如下: 37 | 38 | ```python 39 | 40 | import pandas as pd 41 | 42 | #构建一组数据 43 | df = pd.DataFrame([['文章阅读量', 982000], 44 | ['查看原文访问详情页', 8912], 45 | [ '翻到详情页底部', 4514], 46 | [ '点击购买', 1207], 47 | ['支付成功', 124]], 48 | columns=['action','count']) 49 | 50 | # 根据数据计算绝对转化率、相对转化率 51 | df['abs_rate'] = df['count']/df['count'].values[0] 52 | df['opp_rate'] = (df['count'].shift(axis=0,periods=-1))/df['count'] 53 | df = df.fillna(0) 54 | 55 | # 设置百分比数据的显示 56 | df['abs_rate'] = df['abs_rate'].apply(lambda x:format(x, '.2%')) 57 | df['opp_rate'] = df['opp_rate'].apply(lambda x:format(x, '.2%')) 58 | 59 | df.to_excel('result.xlsx', index=False) 60 | 61 | ``` 62 | 63 | ### 1、单个子表,改用 to_csv() 方法 64 | 65 | 如果只有一个表格,那么可不再使用 `to_excel()` 而是改用 `to_csv()`。具体代码为: 66 | 67 | ```python 68 | 69 | df.to_csv('result.csv',encoding='utf_8_sig',sep=',',index=False) 70 | 71 | ``` 72 | 73 | 里面的两个关键参数,解释一下: 74 | - `encoding='utf_8_sig'` 而不是默认的 `utf-8` 是为了解决中文乱码问题; 75 | - `index=False` 则是不写入 dataframe 数据类型的 `index` 那列无意义数据。 76 | 77 | 但实际情况是,数据统计分析的输出,通常有多个子表构成,所以还是得用回 `to_excel()` 吖! 78 | 79 | ### 2、多个子表,束手无措,作出取舍 80 | 81 | 我搜了非常多网页,尚未找到直接解决问题的方法。在这种情况下,我只能从以下 2 个结果中二选一: 82 | 83 | - 显示为百分数,打开 excel 表格时有异常提示:以文本形式存储的数据(即现状) 84 | - 显示为小数,打开 excel 表格时无异常提示 85 | 86 | 想要显示为小数,则直接注释掉脚本中的 2 句百分数格式设置语句即可。 87 | 88 | ```python 89 | 90 | #df['abs_rate'] = df['abs_rate'].apply(lambda x:format(x, '.2%')) 91 | #df['opp_rate'] = df['opp_rate'].apply(lambda x:format(x, '.2%')) 92 | 93 | ``` 94 | 95 | 真是不甘心吖!!希望有天能找到答案,更新本文!笔记先落笔至此吧! 96 | 97 | btw,您有解决办法吗?当需要把 dataframe 数据输出到 excel 并有多个子表时,如何能让百分数正常显示,而无任何异常提示呢? 98 | 99 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190911_pandas.to_sql()失败,提示 pandas.io.sql.DatabaseError1146表格不存在的解决办法.md: -------------------------------------------------------------------------------- 1 | # pandas.to_sql()失败,遇到 pandas.io.sql.DatabaseError:1146 提示表格不存在的解决办法 2 | 3 | 在写我的爬虫脚本 `csdn_my_article` 时,遇到一处报错: 4 | 5 | ![image](https://user-images.githubusercontent.com/31027645/64673793-be5b7a00-d4a1-11e9-9b54-c754288f8995.png) 6 | 7 | > pandas.io.sql.DatabaseError: Execution failed on sql 'select * from csdn_my_article;': (1146, "Table 'zhihuclawer.csdn_my_article' doesn't exist") 8 | 9 | 相关的代码是: 10 | 11 | ```python 12 | 13 | pd.io.sql.to_sql(article_df, "csdn_my_article", conn, if_exists='append', index=False) 14 | 15 | ``` 16 | 17 | 因为该爬虫脚本是首次运行,`mysql` 中并没有该` table`,在执行上述语句时,将会自动创建新表格。但显然,创建新表格遇到问题,导致创建表格失败。 18 | 19 | 经检查,失败的原因是: 20 | 21 | ```python 22 | attn = r'some_(.*?)attn_(.*?)desct_(.*?)' 23 | result = re.findall(attn,html_text,re.S) 24 | if result: 25 | article_df = pd.DataFrame(result,columns=['some_columns','title_list']) 26 | 27 | ``` 28 | 我在执行该脚本之前,曾修改正则匹配式 `attn`里的描述,导致多抓取一个变量,但在定义 `article_df` 这个 `pandas dataframe `数据时,忘记定义该参数的 `columns` 名称。从而导致正则匹配拿到的每项结果的参数个数,比 `dataframe` 所定义的 `columns` 个数要多。最终导致接下来`to_sql()` 执行失败。 29 | 30 | 在 `columns` 的 `list` 中增加对应的 `columns` ,果然能正常执行。 31 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190911_win10 设定计划任务时提示所指定的账户名称无效,如何解决?.md: -------------------------------------------------------------------------------- 1 | # win10 设定计划任务时提示所指定的账户名称无效,如何解决? 2 | 3 | 我想把我的 python 爬虫脚本设定为自动定时执行,我的设备是 win10 操作系统,这将用到系统自带的计划任务功能。且我希望不管用户是否登录都要运行该定时任务,但在设置计划任务的属性时,遇到一个报错:**所指定的账户名称无效**。 4 | 5 | 该报错是如何发生的,以及如何解决?记录如下: 6 | 7 | ## 报错是如何发生的? 8 | 9 | 如下图所示,设置计划任务的属性: 10 | - 如果仅勾选“只在用户登录时运行”,点击“确定”后直接创建成功。并不会遇到如题报错。 11 | 12 | - 如果勾选“**不管用户是否登录都要运行**”,点击“确定”后弹出账户信息输入界面。这种情况才会遇到这个错误。 13 | 14 | ![image](https://user-images.githubusercontent.com/31027645/64668533-7e3fcb80-d490-11e9-99eb-e523f58b7891.png) 15 | 16 | 17 | 这种情况下,正确输入密码,也会遇到报错:所指定的账户名称无效 18 | 19 | ![image](https://user-images.githubusercontent.com/31027645/64668542-8b5cba80-d490-11e9-8617-56dffe679420.png) 20 | 21 | 22 | 报错截图:任务 name 出错。错误消息:所指定的账户名称无效。 23 | 24 | ![image](https://user-images.githubusercontent.com/31027645/64668550-944d8c00-d490-11e9-90dd-afafecdaec76.png) 25 | 26 | 27 | ## 如何解决该报错? 28 | 我搜了好多办法,唯一对我的情况有效的解决办法是:在计划任务属性页面,点击“更改用户或组”,输入用户名(比如我的“75801”),然后点击“检查名称”,再点击“确定”提交,就可以了。 29 | 30 | **请留意,执行该操作前与之后,“安全选项-运行该任务时,请使用下列用户账户”那里发生了变化。** 31 | 32 | ![image](https://user-images.githubusercontent.com/31027645/64668567-a5969880-d490-11e9-92cc-47201257c054.png) 33 | 34 | ![image](https://user-images.githubusercontent.com/31027645/64668576-adeed380-d490-11e9-994e-3056138e6533.png) 35 | 36 | 无论是设定计划任务,还是修改计划任务的属性,当勾选了“不管用户是否登录都要运行”后,都有可能遇到此类报错。都可以按照这个方式解决问题。 37 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190911_windows 10 如何设定计划任务自动执行 python 脚本?.md: -------------------------------------------------------------------------------- 1 | # windows 10 如何设定计划任务自动执行 python 脚本? 2 | 3 | 我用 `python` 写了一些脚本,有一些是`爬虫`脚本,比如爬取知乎特定话题的热门问题,有一些是定期的`统计分析`脚本,输出统计结果到文档中。之前我都是手动执行这些脚本,现在我希望如何这些脚本能自动定时执行。那么,windows 10 操作系统如何定时自动执行 python 脚本? 4 | 5 | 我的设备是 windows 10 操作系统,自带的“计划任务”可以满足我的需求,具体操作步骤,整理如下。 6 | 7 | ## 步骤 1:打开 “计算机管理” 界面 8 | 9 | 点击电脑左下角的 windows 图标,或者键盘的 windows 按键。 10 | 11 | ![image](https://user-images.githubusercontent.com/31027645/64669032-87ca3300-d492-11e9-8158-3be079f41812.png) 12 | 13 | 在弹出的界面中,鼠标移到“此电脑”上右键点击,选择“更多”-‘管理’,点击则可进入“计算机管理”界面。 14 | 15 | ![image](https://user-images.githubusercontent.com/31027645/64668693-1d64c300-d491-11e9-9ebd-062ce7f02dfe.png) 16 | 17 | ## 步骤 2:开始 “创建基本任务” 18 | 19 | 在打开的“计算机管理”界面上,依次点击“系统管理”-“任务计划程序”,然后最右侧选择“创建基本任务”,即可开始创建计划任务。 20 | 21 | ![image](https://user-images.githubusercontent.com/31027645/64669112-d677cd00-d492-11e9-8583-c467922e3751.png) 22 | 23 | ## 步骤 3:输入计划任务的基本属性 24 | 25 | 计划任务的属性设置分为多个步骤,按照操作提示一步步来即可。即便刚开始弄错了,之后也可以修改或完善。所以不要紧张。第一次使用时,可按照以下截图依次尝试: 26 | 27 | #### - 输入该任务的名称和描述。 28 | 29 | 注意:这是写给自己看的哟,最好标记清楚,避免时间久了自己迷糊了。 30 | 31 | ![image](https://user-images.githubusercontent.com/31027645/64669135-ef807e00-d492-11e9-8ddd-2d99184ca6bf.png) 32 | 33 | #### - 设定计划任务的频率。 34 | 35 | 注意:根据你的具体需求来设定。比如我的知乎爬虫脚本 2 小时一次,而统计分析脚本则每天一次即可。 36 | 37 | 对于每隔 2 小时一次的计划任务,也可以选择每天,后面可以增加多个时段。比如每天的 6,8,10,12,14 点等等分别执行。刚开始先设置一个时间点即可。之后再增加其它时间点。下文将详细说明。 38 | 39 | 对于 python 脚本来说,它的类型是:程序。 40 | 41 | ![image](https://user-images.githubusercontent.com/31027645/64669343-cd3b3000-d493-11e9-953f-37898b2e1504.png) 42 | 43 | - 程序和脚本:这里填写 python 的安装路径。点击浏览“浏览……”会自动弹出选择界面。 44 | - 添加参数(可选)A: 这里填写我的 python 爬虫脚本的绝对路径。比如我的脚本是: 45 | 46 | C:\Users\username\python_side_projects\crawler\crawler_base\zhihu_topic_monitor_exe.py 47 | 48 | ![image](https://user-images.githubusercontent.com/31027645/64669351-d62c0180-d493-11e9-91db-bef6b78fa27e.png) 49 | 50 | 系统默认打开的路径,并没有我想打开的 python.exe 怎么办?简单……往下看。 51 | 52 | ![image](https://user-images.githubusercontent.com/31027645/64669364-dd530f80-d493-11e9-93f6-b87287d4ae6d.png) 53 | 54 | 这里遇到一个小知识点: 55 | 56 | ## 知识点:如何查找 python 安装在哪里? 57 | 58 | 启动 cmd(命令行提示符),输入:`where python` 即可。下面看到,我的电脑上装了两个 python,选择你常用的那个版本即可。 59 | 60 | ![image](https://user-images.githubusercontent.com/31027645/64669371-e3e18700-d493-11e9-9d2f-81604f6e9218.png) 61 | 62 | 按照上述路径提示,打开对应文件夹,选中 `python.exe` 即可。 63 | 64 | ![image](https://user-images.githubusercontent.com/31027645/64669393-f6f45700-d493-11e9-88af-4bc3c29c6f18.png) 65 | 66 | 按照以上步骤设定好计划任务的属性,点击完成就行啦。等等……我刚才希望爬虫脚本每隔 2 小时就执行一次,如何设定呢? 67 | 68 | ## 小技巧:每隔 2 小时就运行一次,如何设定计划任务。 69 | 70 | 先新建一条普通的计划任务,或选择已有的计划任务,选择“属性”打开计划任务的属性界面。 71 | 72 | ![image](https://user-images.githubusercontent.com/31027645/64669421-17241600-d494-11e9-96ba-e1a2d70e22f3.png) 73 | 74 | 在“触发器”这个页签,按需求,添加更多时间点,然后提交完成即可。 75 | 76 | ![image](https://user-images.githubusercontent.com/31027645/64669443-2b681300-d494-11e9-96be-d39db509047a.png) 77 | 78 | ## 经验:遇到报错所指定的账户名称无效,怎么办? 79 | 80 | ![image](https://user-images.githubusercontent.com/31027645/64669499-5b171b00-d494-11e9-8637-af01eb818b99.png) 81 | 82 | 简单来说,在计划任务属性页面,点击“更改用户或组”,输入用户名(比如我的“75801”),然后点击“检查名称”,再点击“确定”提交,就可以了。详细的图文说明,请挪步我的另外一篇整理: 83 | 84 | > [https://juejin.im/post/5d7881a6e51d453bdb1d9bd9](https://juejin.im/post/5d7881a6e51d453bdb1d9bd9) -------------------------------------------------------------------------------- /articles_of_coding_learning/20190911_用 python 写个小爬虫监控某人的 CSDN 文章数据.md: -------------------------------------------------------------------------------- 1 | # 用 python 写个小爬虫监控某人的 CSDN 文章数据 2 | 3 | 用 `python` / `pandas` + `mysql` 写了一个简单的小爬虫,用来爬取 我的 csdn 文章基本数据。`python`代码如下。如果不用 `mysql`,把文件读写的部分改成 `pandas` 的 `read_csv` / `to_csv` 也 OK。 4 | 5 | 如果想监控某大佬,或某一组 csdn id 的数据,也可以这么干。不过需要在此基础上简单加工下。 6 | 7 | 如果想要持续采集数据,定时执行,可以用到操作系统自带的计划任务功能。 8 | 9 | 当数据量积累起来后,可以根据数据爬取与分析的目的,用 `pandas` 进一步统计分析。 10 | 11 | ```python 12 | 13 | import datetime 14 | import re 15 | import urllib.request 16 | import pandas as pd 17 | import random 18 | import pymysql 19 | import os.path 20 | 21 | from sqlalchemy import create_engine 22 | conn = create_engine('mysql+pymysql://root:password@localhost:3306/zhihuclawer',encoding='utf8') 23 | 24 | csdn_path = 'D:/crawler/output_csdn/' 25 | wf_log = open(csdn_path + 'log_csdn_my_article.txt', 'at') 26 | 27 | # 读取网页,把读取的数据返回为一个移除了换行空格等符号的 str 对象,供后续 re 处理调用 28 | def read_url(url): 29 | #header 库实现随机 header,一定程度上克制反爬 30 | headers_list = [ 31 | ("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.112 Safari/537.38"), 32 | ] 33 | rand = random.randint(1,len(headers_list)) 34 | opener = urllib.request.build_opener() 35 | opener.addheaders = headers_list.copy()[rand-1:rand] 36 | data = opener.open(url).read() 37 | html_text = str(data,encoding='utf-8') 38 | html_text = clean_str(html_text) 39 | return html_text 40 | 41 | def clean_str(str_obj): 42 | str_obj = str_obj.replace('\n','') 43 | str_obj = str_obj.replace('\t','') 44 | str_obj = str_obj.replace(' ','') 45 | str_obj = str_obj.replace(' ','') 46 | str_obj = str_obj.replace('\r','') 47 | return str_obj 48 | 49 | def read_a_page(url): 50 | html_text = read_url(url) 51 | attn = r'(.*?)(.*?)(.*?)

(.*?)

阅读数(.*?)

评论数(.*?)

' 52 | result = re.findall(attn,html_text,re.S) 53 | if result: 54 | article_df = pd.DataFrame(result,columns=['articlt_url','articlt_itype','articlt_type','articlt_title','articlt_url_2','articlt_desct','press_time','read_count','reply_count']) 55 | article_df['update_time'] = str(datetime.datetime.now()) 56 | pd.io.sql.to_sql(article_df, "csdn_my_article", conn, if_exists='append', index=False) 57 | print(datetime.datetime.now(),url,'is done.') 58 | wf_log.write(str(datetime.datetime.now()) + str(url) + 'is done.\n') 59 | return article_df 60 | 61 | def read_all_pages(pages=5,csdn_id='qiaoanlu'): 62 | print(datetime.datetime.now(),'read_all_pages ...') 63 | wf_log.write(str(datetime.datetime.now()) + 'read_all_pages ... args:' + str(pages) + ', ' + csdn_id+'\n') 64 | for i in range(1,pages+1): 65 | url = 'https://blog.csdn.net/' + csdn_id + '/article/list/' + str(i) + '?' 66 | try: 67 | read_a_page(url) 68 | except: 69 | print(datetime.datetime.now(),'some error happended',i) 70 | wf_log.write(str(datetime.datetime.now()) + str(i) +'some error happended') 71 | continue 72 | print(datetime.datetime.now(),'read_all_pages is done.') 73 | wf_log.write(str(datetime.datetime.now()) +'read_all_pages is done.\n') 74 | 75 | def output_file(): 76 | conn = pymysql.connect('localhost','root','789351','zhihuclawer') 77 | cursor = conn.cursor() 78 | sql_search = 'select * from csdn_my_article;' 79 | csdn_my_article = pd.read_sql(sql_search,conn) 80 | cursor.close() 81 | conn.close() 82 | 83 | rlt_url = csdn_path + 'csdn_my_article'+str(datetime.datetime.now())[:10]+'.csv' 84 | csdn_my_article.to_csv(rlt_url, encoding='utf_8_sig', index=False) 85 | 86 | print('文件已生成',rlt_url) 87 | wf_log.write(str(datetime.datetime.now()) + ' output_file is done.' + '\n') 88 | return csdn_my_article 89 | 90 | def main(): 91 | read_all_pages(pages=5,csdn_id='qiaoanlu') 92 | output_file() 93 | 94 | if __name__ == "__main__": 95 | main() 96 | ``` 97 | 如果大神路过,不妨指教下这个小爬虫脚本还有哪些可以改进的地方。感激不尽。 -------------------------------------------------------------------------------- /articles_of_coding_learning/20190912_python 字符串替换功能 string.replace()可以用正则表达式,更优雅.md: -------------------------------------------------------------------------------- 1 | # python 字符串替换功能 string.replace()可以用正则表达式,更优雅 2 | 3 | 说起来不怕人笑话,我今天才发现,`python` 中的`字符串替换操作`,也就是 `string.replace()` 是可以用`正则表达式`的。 4 | 5 | 之前,我的代码写法如下,粗笨: 6 | 7 | ![image](https://user-images.githubusercontent.com/31027645/64772646-8af11c00-d583-11e9-99ad-72ef214d1e1c.png) 8 | 9 | 自从发现了`正则表达式`也生效后,代码变得优雅简洁: 10 | 11 | ![image](https://user-images.githubusercontent.com/31027645/64772659-90e6fd00-d583-11e9-8e62-8ef10068237a.png) 12 | 13 | 备注:上图中的`base_info` 是 `pandas` 里的 `dataframe` 数据结构,可以用上述方法使用 `string` 的 `replace` 方法。 14 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20190927_整理总结我如何在python中实现与mysql的数据交互及常用sql语句.md: -------------------------------------------------------------------------------- 1 | # 【呕心总结】python 如何与 mysql 实现交互及常用 sql 语句 2 | 3 | 9 月初,我对 `python 爬虫` 燃起兴趣,但爬取到的数据多通道实时同步读写用`文件`并不方便,于是开始用起`mysql`。这篇笔记,我将整理近一个月的实战中最常用到的 `mysql` 语句,同时也将涉及到如何在`python3`中与 `mysql` 实现数据交换。 4 | 5 | 关于工具/库,特别说明下: 6 | 7 | 1、我安装了 `mysql` ,并直接采用管理员身份运行`命令行提示符(cmd)`查看 `mysql`,并没有安装任何 `mysql` 的可视化图形界面工具。 8 | 9 | 2、在 `python` 脚本中,我采用 `pymysql` 和 `sqlalchemy` 这两个库与 `mysql` 建立连接,用 `pandas` 来处理数据。 10 | 11 | ## 一、建立连接与数据交互 12 | 13 | 与 mysql 交互的方式,我目前共使用 4 种。其中采用管理员身份运行`命令行提示符(cmd)`查看 `mysql`,其操作图示可另写一篇。这里就不占篇幅了。mysql 的可视化图形界面工具,我目前并没有用到,也没有迫切使用它的需要。另外 3 种方式都是通过 python 脚本进行。 14 | 15 | ### 情境 A:python 演算得出数据,想要写入数据库 16 | 17 | python 脚本已得到表格类大量数据,想要一次性写入数据库,常用代码如下: 18 | 19 | ``` 20 | import pandas as pd 21 | # 与 mysql 建立连接 22 | from sqlalchemy import create_engine 23 | conn_eng = create_engine('mysql+pymysql://username:password@localhost:3306/databasename',encoding='utf8') 24 | 25 | # 调用 pandas 的方法,数据写入 mysql 26 | pd.io.sql.to_sql(your_df, "table_name", conn_eng, if_exists='append',index=False) 27 | 28 | ``` 29 | 表格类数据,我用的是 `pandas` 的 `dataframe` 结构。`pd.io.sql.to_sql()` 的参数还有许多其它用途,但上面这种是我个人使用最高频的。效果是:无需自己提前建表,将自动建新表。美中不足是:表的列属性自动生成,通常不合心意,还需检查和修改。 30 | 31 | 如果不想用 `pd.io.sql.to_sql()` 或者想更精细、复杂的操作,则用到下面的情境 C。 32 | 33 | ### 情境 B:python 脚本想从 mysql 拿到数据 34 | 35 | 如果已经存在某个表格,想要向该表格提交某条指令,需返回数据,我用的是 `pandas`的`read_sql 36 | ()` ,返回的数据类型是 `pandas` 的 `dataframe`。sql 查询语句挺好写的,具体总结在本文下方。 37 | 38 | ```python 39 | import pymysql 40 | # 与 mysql 建立连接 41 | conn = pymysql.connect('localhost','username','password','databasename') 42 | # sql 语句定义为一个字符串 43 | sql_search = 'select question_id from topic_monitor where is_title=0 ;' 44 | # 调用 pandas 的 read_sql() 方法拿到 dataframe 结构的数据 45 | question_ids = pd.read_sql(sql_search,conn) 46 | # 关闭连接 47 | conn.close() 48 | ``` 49 | 50 | ### 情境 C:python 脚本单方面向 mysql 发出指令,无需拿到数据 51 | 52 | 如果已经存在某个表格,想要向该表格提交某条指令而无需返回数据时,比如:建表、对数据的增改删、对列的名称、列的属性修改等,代码如下。 53 | 54 | 55 | ``` 56 | import pymysql 57 | # 与 mysql 建立连接 58 | conn = pymysql.connect('localhost','username','password','databasename') 59 | cursor = conn.cursor() 60 | # sql 语句定义为一个字符串,插入一行数据 61 | sql_insert = 'INSERT INTO questions(q_id,q_title,q_description,q_keywords,q_people,q_pageview,time) VALUES( "'\ 62 | + str(quesition_id) + '", "' + str(one[0])+ '", "' + str(one[1]) + '", "' + str(one[2]) + '", "' \ 63 | + str(one[3]) + '", "' + str(one[4]) + '", "' + str(datetime.datetime.now()) + '");' 64 | # sql 语句定义为一个字符串,修改某个数据(另一个表格) 65 | sql_update = 'update topic_monitor SET is_title="1" where question_id = "' + str(quesition_id) + '";' 66 | # 提交指令 67 | cursor.execute(sql_insert) 68 | cursor.execute(sql_update) 69 | conn.commit() 70 | 71 | # 插入一行数据;仅当该数据与表格已有数据不重复时才插入,否则就不会插入 72 | sql_insert = 'INSERT INTO `topic_monitor`(question_id,is_title,q_type,topic_id,time) SELECT "'\ 73 | + x[0] + '", "0", "0","' + str(topic_id) + '", "'+ str(now) + '" FROM DUAL WHERE NOT EXISTS(\ 74 | SELECT question_id FROM topic_monitor WHERE question_id = "' + x[0] + '")' 75 | cursor.execute(sql_insert) 76 | conn.commit() 77 | 78 | # 关闭连接 79 | cursor.close() 80 | conn.close() 81 | ``` 82 | 83 | 通过上面几种实用情况可以看到,`python` 与 `mysql` 实现交互的过程,通常分为:建立连接、把 sql 语句定义为字符串,提交指令、关闭连接。核心的技能在于 sql 语句;除了定义 sql 语句字符串,其余 3 个处理都是固定的写法。 84 | 85 | 我在最初一个月的实践中,最常出现的错误有: 86 | - 值的引用没有加上引号; 87 | - 符号错乱:多一个符号,少一个符号; 88 | - 值的类型不符合:不管 mysql 表格中该值是数,还是文本,在定义 sql 语句的字符串时,对每个值都需要转化为字符串; 89 | - 拷贝自己的代码时,忘记修改 databasename。 90 | 91 | 92 | ## 二、sql 语句:搜索查询 93 | 94 | 搜索是指在数据库的某个表格中查询符合特定条件的数据,并返回查询结果。其基本结构为: 95 | 96 | `SELECT 【范围】FROM table_name 【条件】;` 其中,范围是必须指定的,而条件可有可无。 97 | 98 | ### 变量 A:范围,是指返回查询结果的范围。 99 | 100 | 返回该表格的所有字段,用 * 表达: 101 | 102 | ```mysql 103 | SELECT * FROM table_name ; 104 | ``` 105 | ![image](https://user-images.githubusercontent.com/31027645/65767128-93d71580-e15f-11e9-8e4a-e3c52c4e4759.png) 106 | 107 | 108 | 仅返回该表格的某个字段: 109 | 110 | ```mysql 111 | SELECT column_name FROM table_name ; 112 | ``` 113 | 114 | 仅返回该表格的多个字段: 115 | 116 | ```mysql 117 | SELECT column_name_1,column_name_3,column_name_3 FROM table_name ; 118 | ``` 119 | 120 | ![image](https://user-images.githubusercontent.com/31027645/65767152-a2bdc800-e15f-11e9-8759-9479071f20af.png) 121 | 122 | 仅返回符合条件的数据个数: 123 | 124 | ```mysql 125 | SELECT count(*) FROM table_name ; 126 | ``` 127 | ![image](https://user-images.githubusercontent.com/31027645/65767216-cc76ef00-e15f-11e9-932c-1fa42fbde121.png) 128 | 129 | ### 变量 B:条件是指,期望返回的数据满足哪些条件。 130 | 131 | 不限定条件: 132 | 133 | ```mysql 134 | SELECT * FROM table_name ; 135 | ``` 136 | 数值类:某个字段(数值类型的,比如 double 或者 int),数值比较的操作符都可以使用比如,大于`>`,小于`<`,等于 `=` ,大于等于 `>=` ,小于等于 `<=` : 137 | 138 | ![image](https://user-images.githubusercontent.com/31027645/65767326-211a6a00-e160-11e9-9a82-902c35200d80.png) 139 | 140 | 141 | ```mysql 142 | SELECT * FROM table_name WHERE num_column_name >= 1; 143 | ``` 144 | 145 | 文本类:某个字段(字符串类型的,比如 char,text): 146 | 147 | ```mysql 148 | SELECT * FROM table_name WHERE str_column_name like “%your_str%”; 149 | ``` 150 | ![image](https://user-images.githubusercontent.com/31027645/65767368-4909cd80-e160-11e9-9cd2-83bc211d714f.png) 151 | 152 | 也可以表达多个条件,`and`,`or`等可用于表达条件之间的关系: 153 | 154 | ```mysql 155 | SELECT * FROM table_name WHERE num_column_name_1 >= 1 and str_column_name like “%your_str%” ; 156 | ``` 157 | ![image](https://user-images.githubusercontent.com/31027645/65767478-938b4a00-e160-11e9-906b-02ccddfbfad0.png) 158 | 159 | ## 三、sql 语句:修改表属性 160 | 161 | 横向的一整条数据,叫做行;竖向的一整条数据,叫作列。列的名字,叫做 `column`,这是通用的知识点。 162 | 163 | 这段时间的实战中,我完全没有用到修改表的名称、重设 index 等知识点。最常用的,就是对列进行操作。每个列具备:列的名称、列的属性、列的数值。 164 | 165 | 列的名称,需要留心不使用保留词。我的技巧是,尽量用一些`_`来表达该数据,比如 `article_title`,`press_date` 这种命名虽然稍长,但易读,也不会装上保留词。 166 | 167 | 列的属性包括:类型,最大长度,是否为空,默认值,是否重复,是否为索引。通常,直接通过 `pandas` 的 `pd.io.sql.to_sql()` 一次性创建表格并保存数据时,列的默认属性并不合需求。要么提前自己定义表的结构,设置好每列属性;要么事后检查列属性,并逐列修改。所以,列的属性设定、修改是高频基础知识点。 168 | 169 | 列的数值,即除了列名称外的、该列其它值。修改某个值,也是高频操作。不过我把这个知识点放到第四部分了。 170 | 171 | 对列的名称、列的属性进行修改,主要的关键词都是 `ALTER`,具体又分为以下几种情况。 172 | 173 | ### 情境 A:新增一列。关键词 `ADD` 174 | 175 | 在你所指定的 `column_name ` 后面定义列的属性。 176 | 177 | ```mysql 178 | ALTER TABLE table_name ADD COLUMN column_name char(20); 179 | ``` 180 | ### 情境 B:修改某列的名称。关键词 `CHANGE` 181 | 182 | 在修改列名的同时也可以重新指定列的属性。 183 | 184 | ```mysql 185 | ALTER TABLE table_name CHANGE old_column_name new_column_name char(50); 186 | ``` 187 | 188 | ### 情境 C:修改某列的属性。关键词是 `MODIFY` 189 | 190 | ```mysql 191 | ALTER TABLE table_name MODIFY column_name char(100); 192 | ``` 193 | 194 | 195 | ## 四、sql 语句:数据的增改删 196 | 197 | 通常提到数据库操作时,四字以蔽之:增删改查。 198 | - 查询,请看第二部分。关键词是 `SELECT`。 199 | - 对数据所依赖的属性的增、改,请看第三部分。关键词是 `ALTER`。 200 | - 数据的增加,在第一部分的数据交互中也给出实例,就不重复了。关键词是`INSERT`。 201 | - 数据的修改,关键词是 `UPDATE`。 202 | - 数据(甚至表格、库)的删除,关键词是`DELETE`。 203 | 204 | 数据的修改,副关键词是 `set` 。 205 | 206 | ```mysql 207 | UPDATE table_name SET columns_name = new_value 【条件】; 208 | ``` 209 | 210 | 新数值如果是数值类型的,则直接写数值即可;如果是文本类型的,必须要加上双引号,比如,`“your_new_value”`。 211 | 212 | 如果把【条件】部分不写,就相当于修改整列的值;想要修改特定范围,就要用到条件表达式,这和前面的查询部分是一致的,就不再重复。 213 | 214 | 数据的删除,对于新手来说,是必须警惕的操作。因为一旦误操作,你将无力挽回。即便是职业程序员,也可能犯下无疑删库的惨剧。其基本语句为: 215 | 216 | ```mysql 217 | DELETE FROM table_name【条件】; 218 | ``` 219 | 220 | 想要修改特定范围,就要用到条件表达式,这和前面的查询部分也是一致的,稍微啰嗦两句:不要对自己设定的条件太自信,最好先用搜索语句检查一下,然后再执行删除语句。 221 | 222 | - 删除单行数据:添加能唯一标识该行数据的条件语句。 223 | - 删除多行数据:添加能标识该范围的条件语句。 224 | - 删除整张表格:**你是认真的吗?没有写错表格名字吧?!** 做这项操作前,必须确认清楚自己的意图,毕竟一旦发生,无可挽回。 225 | 226 | 如果条件留空,将保留表结构,而删除所有数据行。想要删除整张表格,什么都不留下,则执行: 227 | 228 | ```mysql 229 | DELETE TABLE table_name; 230 | ``` 231 | 俗称的“删库”就是删掉整个数据库,虽然实战中几乎不会用到,但作为新手经常手误,在练习阶段安全起见,最好还是专门创建一个 database 用于练手,练完直接删掉整个练习库: 232 | 233 | ```mysql 234 | DELETE DATABASE database_name; 235 | ``` 236 | 237 | 如果简单总结下过去一个月,使用`mysql`的体验,那就是:除了 mysql 的安装激活太麻烦,数据的增删改查比操作文本方便太多了!!完全值得容忍安装激活的麻烦。另外 mysql 常用语法确实简单、非常有规律。 238 | 239 | 希望我的总结带给你帮助。鼓励我继续分享,那就请点个赞吧!勘误请留言,或挪步我的 github:[https://github.com/liujuanjuan1984/ucanuupnobb/issues](https://github.com/liujuanjuan1984/ucanuupnobb/issues) -------------------------------------------------------------------------------- /articles_of_coding_learning/20190928_整理总结 python 中时间日期类数据处理与类型转换(含 pandas).md: -------------------------------------------------------------------------------- 1 | d -------------------------------------------------------------------------------- /articles_of_coding_learning/20191009_24H玩转 Grafana 被工程师称相当专业,如何做到?.md: -------------------------------------------------------------------------------- 1 | # 24H 玩转 Grafana 被工程师称相当专业,如何做到? 2 | 3 | 国庆假期发生了两件小事,其一是我默默度过 `35` 周岁生日,其二是玩了下` grafana` `并在节后第一天被工程师 M 称赞:相当专业。 4 | 5 | ### 1、我为什么要玩 `grafana` 呢? 6 | 7 | 数月前我提交了一份数据后台需求给工程师 M,他选用和部署了 `grafana` 这个第三方开源的工具,仅用两三天就完成了这份需求。这效率相当快,令我对 M 和 `grafana` 印象深刻。但我仍不满足,M 提交的成品所有数据都图形化的而我更想要表格样式的数据。为了进一步整合其它数据进行统计分析,我还需手动导出数据,并写了复杂的 `python` 脚本用 `pandas` 做统计分析,每周至少运行一次。我常常冒出新的数据需求,它们并不大,但走一遍需求评审、排期开发验收的流程,似乎还挺麻烦的。 8 | 9 | 这些都还只算铺垫,真正的导火索是国庆假期前的 `sprint` 总结会上提及我们几个产品的数据将整合到 `grafana` 统一实现。 CTO 曾对我提及如果我懂些 sql 语句,可以自己写。——哈?我懂点 sql 语句的吖,这不刚整理了一份笔记[《【总结】python 如何与 mysql 实现交互及常用 sql 语句》](https://xue-posts.xue.cn/1e6fd5ffb16ee0dd66119466b2cdbf7860a9e8c5f4d980a20b1063beeda23749)嘛。我处于 “sql 不过如此,放马过来啊”的大无畏状态`-_-||` 10 | 11 | 国庆假期来了,那就玩玩儿看呗。 12 | 13 | ### 2、短时间如何上手 `grafana` ? 14 | 15 | M 之前为了开发我的需求,已经完成了 `grafana` 的部署,并设置好了`数据源`。这次他专门创建了一个练习用的 `dashboard` 并开通编辑权限给我。特别说明,我的编辑权限仅有数据源的查询权,没有增删改的权限,这对数据源是安全的。另外,M 已有的实现也让初次上手的我可以照葫芦画瓢。这些是 16 | 我比完全零准备的 grafana 新手占便宜的地方。 17 | 18 | 我并不想把 M 已经开发的需求重新实现一遍,我想要实现自己的数据需求。——想要什么数据,以什么样式呈现,我脑子里的需求俯拾即是。 19 | 20 | 学习过程具体分为三个部分: 21 | - A:熟悉和了解 `grafana` 在 dashboard 上如何添加、编辑图表等模块,就是了解这个工具如何使用。 22 | - B:熟悉和了解 数据源(我们产品的数据库),有哪些表,有哪些字段之类。 23 | - C:实现数据需求的 sql 语句该如何写。 24 | 25 | A 部分,搜了两篇 `grafana 如何使用`之类的文章,大概浏览下即可。总是照着别人整理的步骤图按部就班,学习体验不好。大部分时候,我都是直接鼓捣。这种开源的可视化的工具,自己尝试一下就能快速熟悉起来。 26 | 27 | B 部分,当个伸手党,让工程师帮忙把所有表格 describe 导出也 OK 的;M 给我的是一份表格的类定义文件。通过 A 部分的探索,我很快发现,在 dashboard 上创建一个模块,如果选择折线图类型,sql 语句编辑区可以任人挑选表格名称,这样有哪些数据表格就清楚了;如果选择表格类型,并使用`select * from table_name limit 50` ,就能呈现该表的部分数据,这样该表格有哪些字段也就清楚了。 28 | 29 | C 部分,我把 M 之前实现的 `sql` 语句单独拷贝到 `jupyter notebook` 里,自己拆解为更基础的知识点,然后一点点熟悉了解。一个小技巧是,对于新手来说 sql 语句的易读相当重要,能直接降低复杂度。所以我采用 `markdown` 语法如下,语法呈现就很清晰了: 30 | ![image](https://user-gold-cdn.xitu.io/2019/10/9/16daebdccd4a9eae?w=390&h=310&f=png&s=14775) 31 | 32 | 以上三个部分无需按顺序进行。自己对哪个模块更感兴趣,就先开始哪个;过程中也可交叉轮换进行。接下来就是通过实现自己的数据需求,反复重复巩固并深入 以上 3 个部分,直至产生令自己满意的产出。为此投入的时间开销`24~48H` 足够啦,完全不耽误假期陪家人、睡懒觉、看电影。 33 | 34 | ![image](https://user-gold-cdn.xitu.io/2019/10/9/16daebdccd563d63?w=1758&h=735&f=png&s=193121) 35 | 36 | ### 3、对职场分工保持清醒 37 | 38 | 最后需要强调一下,我很清楚自己并不想要取代工程师完成数据后台的开发。比如: 39 | 40 | 1. 一些复杂需求,我自己写`sql`,很难,学起来也慢。这些我会陆续收集罗列出来,走排期,请工程师帮忙,不会自己硬钻进去。 41 | 42 | 2. 即便最终我完成了非常多的图表,但实际上我只考虑实现,不考虑性能(也暂无能力考虑),所以即便是我写出来的功能,也需要工程师把关和优化。 43 | 44 | 即便如此,我直接接触数据源并动手用 `grafana` 实现,也有很显著的好处: 45 | 46 | 1. 我更清楚原始数据已采集了哪些,哪些指标是我可以定义和统计的,哪些是需要工程师进一步支持的。 47 | 48 | 2. 一些相对简单的、对业务有帮助的数据监控/统计,我能直接实现。无需整理描述需求-和工程师沟通-工程师理解后实现-我再验收这样复杂的过程。 49 | 50 | 3. 作为需求的发起者,我那些不成熟的需求,自己动手过程中迭代起来也会非常效率。 51 | 52 | 当然这些想法是需要和工程师、上级沟通清楚的,这样才不至于产生误解吖。如果我的笔记对你有帮助,那就点赞或留言告诉我吧! 53 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191012_能写数据后台,需要掌握哪些进阶的sql语句?.md: -------------------------------------------------------------------------------- 1 | # 能写数据后台,需要掌握哪些进阶的 sql 语句? 2 | 3 | P.S. 另外一个标题:提需求的人,自力更生写好数据后台,你却还不懂 sql? 4 | 5 | 国庆假期花了一些时间,首次尝试并玩转 `grafana`,这几天继续不断优化和完善,如今看着自己的成果,相当满意。——逐步接近我想要的理想后台啦。 6 | 7 | 需求是不停歇的。今天我又给自己发掘了一些新需求,比如变量、筛选框之类,都收集下来等有空继续玩。编程学习的过程中,对于自己尚未尝试的新技能点,本能直觉会感到困难,但动手经验告诉我:莫慌,用起来就懂了,瞧我自己每次都能很快上手吖。——善于让自己在学习的过程中感受良好,并确实持续进步,自我激励是一个特别实用的软技能。 8 | 9 | 然后我想着不妨把这几天玩转 `grafana` 时用到的进阶版的 `sql` 语句整理出来。所谓进阶版,是针对我个人的 `sql` 能力啦,确切地讲,是指在我[之前的笔记](https://xue-posts.xue.cn/1e6fd5ffb16ee0dd66119466b2cdbf7860a9e8c5f4d980a20b1063beeda23749)中未曾出现、且玩转 grafana 中我确实反复用到的。整理自己刚刚反复实践的新知识点,能很好地巩固新知。完成这件事,方能安心进入下一个阶段向未知冲刺。 10 | 11 | [之前写了一篇笔记,记录自己是为什么要玩 grafana ,以及如何在 24 H 做到被工程师称赞](https://xue-posts.xue.cn/b40841f91139bd509ec9f2aa2312ba83c1ef17ec467aa7223483c3633f74c191),文中提及我把工程师已经实现的 `sql`语句拷贝下来,拆解为元知识点,然后逐个理解:它是什么功能,如何用,然后直接用起来试试效果。 12 | 13 | ### 举个实例来拆解元知识点 14 | 15 | 在本篇笔记中,我也先举一个实例用作知识点拆解,如下,该述语句的作用是:统计每天具有学习行为的用户数。注:学习行为其实包含多种具体的行为,分布在两个表中。 16 | 17 | ```mysql 18 | with data as( 19 | select 20 | date(created_at) as time, 21 | user_id 22 | from user_comments 23 | union all 24 | select 25 | date(created_at) as time, 26 | user_id 27 | from user_activities 28 | ) 29 | select 30 | time, 31 | count(distinct user_id) as 每日学习用户数 32 | from data 33 | group by time 34 | order by time 35 | 36 | ``` 37 | 38 | 注意:sql 对大小写、换行、缩进之类都不敏感,这是和 `python`不同的地方。上面之所以要换行和缩进,只是为了易读性。 39 | 40 | 这一条 sql 语句看着挺长,其实是两个部分。`as` 前面的 data 是数据的名字,我们自定义的,后面 B 部分的`from` 数据源就是它。被 `with data as()` 括起来的 A 部分,用于生成数据,相当于先做一次检索统计得到一些数据命名为 data ,然后再对 data 进行检索统计。 41 | 42 | ```mysql 43 | with data as (【语句块 A】) 44 | 【语句块 B】 45 | ``` 46 | ### 可嵌套的 `with data as()` 47 | 48 | 短时间用 `with data as()` 用的比较多时,我就揣测:这玩意儿能嵌套吗?一试果然可行。嵌套只是让它看上去复杂点,本质没啥变化。如下所示,语句块 A 的数据源是原始数据,语句块 B 的数据源是 data,语句块 C 的数据源是 datax。 49 | 50 | ```mysql 51 | with datax as( 52 | with data as (【语句块 A】) 53 | 【语句块 B】 54 | ) 55 | 【语句块 C】 56 | ``` 57 | 实战中,我最多用过 3 层嵌套,且偶尔为之;双层嵌套用的多一些。而单层则相当常用。 58 | 59 | ### 用`union`合并数据行 60 | 61 | 上方实例被 `with data as()` 括起来的部分,其实是两个表满足条件的数据合并。抽象一下如下。 62 | 63 | ```mysql 64 | 【语句块 X】 65 | union all 66 | 【语句块 Y】 67 | ``` 68 | 69 | 处理表格数据的合并时,细分有以下三个情形: 70 | - 把多列或多行的数据,合并为单列或单行的数据 71 | - 把 A 表的数列,与 B 表的数列合并起来 72 | - 把 A 表的数行,与 B 表的数行合并起来 73 | 74 | `union` 处理的是基于行的合并。举例来说,如果语句块 X 的结果为 a 行,语句块 Y 的结果为 b 行,则通过`union all` 合并后的结果将有(a+b)行。而用 `union` 的结果是取 a 和 b 的并集,即 a、b 中都存在的数据行只保留一份。 75 | 76 | 相对应的,在`pandas` 通过 `pd.concat()` 的`axis`参数就能处理行、列的不同方式合并,还真是简约吖。 77 | 78 | ### 函数`data()`与`as`别名 79 | 80 | 上方举例中,语句块 X 和 Y 大体上是蛮基础的语句。但依然出现了我之前没有用过的方法。 81 | - `date(created_at) as time,` 和 `count(distinct user_id) as 每日学习用户数` 这两个片段中,`as` 之前是表达式语句,`as` 之后是该语句运算结果的别名。 82 | - `date()` 方法是把复杂的时间数据简化为年月日的日期数据。超高频使用。 83 | - `count(distinct user_id) ` 则表示:对 `user_id` 去重,然后统计 `user_id` 个数。超高频使用。 84 | 85 | ![image](https://user-images.githubusercontent.com/31027645/66698312-8e58fe00-ed0f-11e9-9e54-684d55720d49.png) 86 | 87 | 类似`count()`和`sum()`都是高频使用的基础函数。不过数据统计中,更常用到累加。语句是定番组合,就不再单独罗列啦: 88 | 89 | ``` 90 | sum(兑换用户数) over (order by 兑换日期 asc rows between unbounded preceding and current row) as 累计用户数 91 | ``` 92 | 93 | 而`count(1)`,`count(*) `和 `count(column_name)` 在不同情况下,运行效率不同。鉴于我暂时没有写出性能最好的 sql 语句之觉悟,暂不深究啦。 94 | 95 | ### 各种情况下的去重 96 | 97 | 上面提及`distinct` ,如何使用`distinct` 倒不复杂;复杂的是需求,对数据指标的定义要理解准确;不同的数据指标,对去重有不同的要求。 98 | 99 | #### 情境 A:不去重。 100 | 101 | 虽然 count 的是 user_id,但这个数据其实并不是每天留言的用户数,而是每天留言的条数。 102 | 103 | ```mysql 104 | select 105 | date(created_at) as time, 106 | count(user_id) as 每日留言条数 107 | from 108 | user_comments 109 | group by 110 | time 111 | order by 112 | time 113 | ``` 114 | 115 | #### 情境 B:当日去重。 116 | 117 | 在当天内去重,跨天不去重。用户在某一天有多条留言,最终也只能为当天留言用户数贡献计数 1 118 | 119 | ```mysql 120 | select 121 | date(created_at) as time, 122 | count(distinct user_id) as 每日留言用户数 123 | from 124 | user_comments 125 | group by 126 | time 127 | order by 128 | time 129 | ``` 130 | #### 情境 C:历史累积去重。 131 | 132 | 有过留言行为的累计用户数,则在全时段内去重。只要该用户曾有过留言行为,则计数 1,不再重复计数。 133 | 134 | ```mysql 135 | select 136 | count(distinct user_id) as 留过言的用户总数 137 | from 138 | user_comments 139 | ``` 140 | #### 情境 D:每日和历史累积同时去重。 141 | 142 | 假设我们想知道每日新增的留言用户数,即如果该用户以前曾留言则不计数,否则在首次留言当天计数 1,这个情境比前面三种复杂点,但同样相当高频使用。 143 | 144 | ```mysql 145 | 146 | with data as ( 147 | select 148 | distinct on (user_id) user_id, 149 | date(created_at) as time 150 | from 151 | user_comments 152 | ) 153 | 154 | select 155 | time, 156 | count(user_id) as 每日新增留言用户数, 157 | count(user_id) over (order by time asc rows between unbounded preceding and current row) as 累积留言用户总数 158 | from data 159 | group by time,user_id 160 | order by time 161 | 162 | ``` 163 | 164 | ### 几个常见的小知识点 165 | 166 | `limit`指定显示多少条数据。换言之,没有这个条件,就表示要显示查询结果的所有数据。我之前不知道这个知识点时,有时不小心直接在命令行提示符中查看某个表,会一下子打印很多很多行,以至于一直下翻都不见底……而在数据后台中,通常配合排序功能,用来显示“排行榜”数据。比如,学习次数排行榜、兑换总额排行榜之类。 167 | 168 | ```mysql 169 | select * from table_name limit 50; 170 | ``` 171 | 172 | ![image](https://user-images.githubusercontent.com/31027645/66697604-b6ddf980-ed09-11e9-90ff-3ed7854d53f8.png) 173 | 174 | `order by` 指定数据按哪些字段排序,默认顺序,可用`desc`倒序。 175 | 176 | ```mysql 177 | select * from table_name order by column_name; 178 | ``` 179 | ![image](https://user-images.githubusercontent.com/31027645/66697658-53a09700-ed0a-11e9-9333-abe1e5582de4.png) 180 | 181 | `group by `指定数据按哪些字段分组,很多报表按日统计。前面举例中无形中也用了该方法数次,就不单独举例啦。 182 | 183 | ### 多表联合查询 184 | 185 | 最后说明下,相对复杂的多表查询。从多个表格、或表格和自定义数据源如 data 中合并查询。一个相对简单的实例如下,根据输入变量 user_name 从 users_extra 查询到 user_id,然后用 user_id 去 user_activities 表查询。 186 | 187 | ```mysql 188 | with data as( 189 | select user_id,user_name from users_extra where user_name = '$user_name' 190 | ) 191 | select 192 | count(1) as 学习行为次数 193 | from 194 | user_activities,data 195 | where 196 | user_activities.user_id = data.user_id 197 | ``` 198 | 这种联合查询必要的条件是,多个数据源可以通过某个字段对应起来。更复杂的例子,其实都可以动用拆解的方式,拆解为更单元的知识点。这里就不展开啦。 199 | 200 | 顺便说,上面的 `user_name = '$user_name'` 语句是 grafana 中用于调用自定义变量,实现后可支持下拉框筛选。这也是刚开始写这篇文章时,我提到的新需求,结果文章修修改改写完,这个需求竟然被我实现了。还真是快! 201 | ![image](https://user-images.githubusercontent.com/31027645/66816747-2bfd3900-ef6d-11e9-9d8c-129a43f95f03.png) 202 | 203 | ### 小结 204 | 205 | 如果某天你和我一样开始接触一点进阶、复杂的 sql 语句或其它技能,千万别慌,找一些现成的实例(比如收藏我这篇笔记)来消化,逐块拆解为元知识点,然后再把它们拼装结合用起来,你会发现:也不过如此嘛。 206 | 207 | 这个过程多像玩儿积木吖!好玩好玩! 208 | 209 | 如果这篇笔记帮到了你,一定要留言告诉我吖;这将鼓励我整理和分享更多。 210 | 211 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191016_小结 python 实战中遇到的几种需要化名的情境.md: -------------------------------------------------------------------------------- 1 | # 小结 python 实战中遇到的几种需要化名的情境 2 | 3 | 笑来在《自学是门手艺》的《2.4.3 化名与匿名》中,讲到了函数的化名。经过几个月的实战,我发现,实际上化名无处不在。我有时也会称之为“别称”,意思一样。函数化名只是化名的一种应用场景,还有好几种使用化名的地方,本篇笔记将整理小结我所遇到的各种化名。 4 | 5 | ### 情境 A:导入时化名 6 | 7 | 导入其它模块时,直接化名为简约版,是我相当常用的,甚至有一些业界约定俗成的化名。无论是模块,模块中的函数或变量,都可以此种方式化名简化之。 8 | 9 | ```python 10 | # 业界约定俗成的一些化名 11 | import pandas as pd 12 | import numpy as np 13 | # 自定义模块与自定义函数的化名 14 | from zhihu_base import get_all_topics_detail as zhihu 15 | ``` 16 | 17 | 我编程时给函数或变量命名的习惯是,让人一看到名字就能知道该它是做什么的,如此以来名称就会挺长。函数因为要被调用,尤其是外部调用,写的复杂点倒能理解。但如果是一个不被外部调用的变量,为什么不直接在定义变量时就定义一个简约的名字呢? 18 | 19 | ### 情境 B:同一行语句多次调用名字,临时简化 20 | 21 | 这里有一种情境,调用该变量的大部分语句都相对简约,用全称更易读,但偶尔有一句复杂的语句,要多次调用该变量,导致该语句特别长,此时要临时要用一个变量化名,简化代码。 22 | 23 | ```python 24 | 25 | sql_search = 'select url_token,zhihu_name,lase_active_time from zhihu_whos_v;' 26 | df_topics_details = pd.read_sql(sql_search,conn) 27 | # 这里省略很多代码 28 | # 此时出现一条相对复杂冗长的语句,多次出现该变量名 29 | df_value_v = df_topics_details[(df_topics_details['upvotecount']>100000) & (df_topics_details['last_activity']>'2019-09-01') ] 30 | 31 | ``` 32 | 33 | 该语句是为了把 df_topics_details 这个数据集之中,符合条件 `upvotecount > 100000` 且 `last_activity >'2019-09-01' `的数据筛选出来,是 `pandas` 中相当常用的语句。后来我发现,在这种多次调用某个变量名或函数名的语句中,可以临时加一个化名,来简化该语句长度。像这样: 34 | 35 | ```python 36 | 37 | df_topics_details = dtd 38 | df_value_v = dtd[(dtd['upvotecount']>100000) & (dtd['last_activity']>'2019-09-01') ] 39 | 40 | ``` 41 | 42 | 但是这种化名,并不适合在定义该变量时就如此做。试想我一开始就把该变量定义为 `dtd`,其余许多行代码会极其不易读——我或者代码的其它读者完全无法理解`dtd`指代什么。如果更多变量都采用这种风格,代码的可读性将有多糟糕啊! 43 | 44 | ### 情境 C:文件对象化名 45 | 46 | 其实文件对象化名这个说法倒不准确,本质上是变量的赋值:把一个特定的文件对象赋值给一个变量来指代保管。单独拎出来,是因为它太高频使用了。类似`fw`或者`fr`,`writer`也是约定俗成的命名习惯。 47 | 48 | 实例 X: 49 | 50 | ```python 51 | fw = open("my_test.txt", "at") 52 | fw.write("xue.cn 月收费仅 15 元,对编程自学者相当友好。") 53 | fw.close() 54 | ``` 55 | 56 | 实例 Y: 57 | 58 | ```python 59 | with open("my_test.txt", "at") as fw: 60 | fw.write("xue.cn 可以在网页上一边阅读一边在线写代码。") 61 | ``` 62 | 63 | 实例 Z: 64 | 65 | ```python 66 | comms_file = output_path + 'xuecn_comments_statistics_' + str(datetime.datetime.now())[:10] + '.xlsx' 67 | with pd.ExcelWriter(comms_file) as writer: 68 | comms_counts_monthly.to_excel(writer, sheet_name='留言月报') 69 | comms_counts_weekly.to_excel(writer, sheet_name='留言周报') 70 | comms_counts_daily.to_excel(writer, sheet_name='留言日报') 71 | comms_by_reg_date.to_excel(writer, sheet_name='每日激活用户的留言情况') 72 | comms_by_reg_week.to_excel(writer, sheet_name='每周激活用户的留言情况') 73 | comms_counts_by_hour.to_excel(writer, sheet_name='留言活跃时段') 74 | vote_by_name.to_excel(writer, sheet_name='用户获赞') 75 | name_count_by_vote.to_excel(writer, sheet_name='用户获赞的分布') 76 | vote_by_content.to_excel(writer, sheet_name='留言获赞') 77 | content_count_by_vote.to_excel(writer, sheet_name='留言获赞的分布') 78 | ``` 79 | 80 | ### 情境 D:化名是通用的操作 81 | 82 | 如我[上一篇笔记](https://juejin.im/post/5da58ac4f265da5b8c03c338)提及,`sql` 语句也有“化名”的方法,用的关键词和 python 导入时所用到的 `as` 是一样的。 83 | 84 | ```mysql 85 | 86 | with data as( 87 | select 88 | date(created_at) as time, 89 | user_id 90 | from user_comments 91 | union all 92 | select 93 | date(created_at) as time, 94 | user_id 95 | from user_activities 96 | ) 97 | select 98 | time, 99 | count(distinct user_id) as 每日学习用户数 100 | from data 101 | group by time 102 | order by time 103 | 104 | def who_is_v_detail 105 | 106 | ``` 107 | 108 | ### 小结 109 | 110 | 我比较少细究某个化名,到底是对函数、变量或对象进行化名。核心在于,化名只是给名字复杂的东西,另外取了一个简单好记的指代他,不管名字如何,那东西的特性不变,所指代的总还是 ta。 111 | 112 | 好似某个人叫“因缺思厅·尼古拉斯·蒋·巴斯帝国五世·一品带刀侍卫·阿拉斯加·狗蛋·王”,你可以简称他:老王。 113 | 114 | “化名”是编程和日常生活中普遍存在的现象,只不过具体在某个语言中,它通过什么关键词或语法来实现而已。 -------------------------------------------------------------------------------- /articles_of_coding_learning/20191023_数据分析师如何自力更生统计用户行为频次?.md: -------------------------------------------------------------------------------- 1 | # 数据分析师如何自力更生统计用户行为频次? 2 | 3 | 不懂数据分析的 growth hacker 不是好运营。近日我想要统计我家产品 [xue.cn](https://xue.cn/) 用户的编程自学行为的频次,且在不给技术开发部门带来任何新需求的情况下自力更生。那么,我该如何定义并统计这个数据指标呢? 4 | 5 | ### 1、定义`学习`这个行为。 6 | 7 | 某些行为是单个事件,某些行为是多种事件的组合。 8 | 9 | [xue.cn](https://xue.cn/) 用户的编程自学行为包括:完成某书一个章节的阅读、完成一道习题、获得一个成就、提交一次评论,完成一次心得打卡等,未来还会有更多。不过,虽然我们有聊天室,但因为使用的是 gitter ,所以数据采集并不容易,这个行为就暂忽略。 10 | 11 | 以上编程自学行为事件数据分布在产品数据库的多个表中。 12 | 13 | ### 2、日志数据的初步筛选。 14 | 15 | 通过在多个表中联合查询 user_id,事件发生日期得到每个 user_id 有学习行为的日期数据,我的 sql 语句是这么写的: 16 | 17 | ```mysql 18 | with data_study as( -- 获取有学习行为的用户名单及学习事件发生时间 19 | select 20 | date(created_at) as time, 21 | user_id 22 | from user_comment 23 | union all 24 | select 25 | date(created_at) as time, 26 | user_id 27 | from user_activity 28 | union all 29 | select 30 | date(created_at) as time, 31 | user_id 32 | from study_card 33 | ) 34 | select -- 获取学习用户的学习日期数据 35 | user_id, 36 | min(time) -- 某天有多次学习行为,仅取一条即可 37 | from data_study 38 | group by user_id,time 39 | order by user_id 40 | ``` 41 | 42 | ### 3、统计的基准线 43 | 44 | 游客体验功能是近期刚上线的。已有的学习行为数据,属于较早版本,那时用户产生学习行为的前提是至少完成一次时长兑换或小额 RMB 充值,所以本次我以用户首次付费的日期作为统计的基准线。 45 | 46 | 从日志数据筛选获取用户的首次付费日期数据,我的 sql 语句是这么写的: 47 | 48 | ```mysql 49 | 50 | with data as( -- 获取用户付费日期 51 | select 52 | user_id, 53 | used_at as 付费日期 54 | from 55 | free_coupons 56 | where 57 | user_id is not null 58 | union all 59 | select 60 | user_id, 61 | created_at as 付费日期 62 | from 63 | rmb_order 64 | where order_status = 'PAY_SUCCESS' 65 | ) 66 | select -- 筛选付费用户的首次付费日期 67 | user_id, 68 | date(min(付费日期)) as reg_date 69 | from 70 | data 71 | group by 72 | user_id 73 | ``` 74 | 75 | ### 4、统计与分析 76 | 77 | 至此,有用的数据已从日志中初步筛选统计得到。接下来,用`学习日期 - 首次付费日期`得到血虚行为发生于`首次付费后的第 N 天`。其后统计: 78 | - A:首次付费后的第 N 天仍有学习行为的用户数。 79 | - B:首次付费后的第 N 周(取值 0 至 8),学习天数达到 M 天(取值 1 至 7)的的用户数。 80 | 81 | A 可作为付费版留存率数据。B 则是学习频次分布数据。 82 | 83 | 因为我对复杂的 sql 运算还不熟练,所以实操时把第 2 和 3 步的结果从 `grafana`导出为 csv 文件,然后采用`excel`,部分指标则采用 `python pandas`完成演算。 84 | 85 | ### 5、精细选择用户群体 86 | 87 | 虽然当前 [xue.cn](https://xue.cn/) 功能已经完善很多,其实我们是上半年刚立项,这半年多持续开发,某些学习功能在早期并未提供。于是,为了获取更可信、有效的数据,需要剔除早期批次的用户。 88 | 89 | 具体来说,根据用户首次付费日期,按月拆分用户批次,再拆分统计学习行为数据较为完善的近期批次数据。 90 | 91 | ### 6、小结 92 | 93 | 以上就是我完成 [xue.cn](https://xue.cn/) 用户学习频次指标的指定与统计分析的实操过程。这次数据洞察探索,帮我发现好几处增长线索。 94 | 95 | 笔记的第 4、5 步对于运营、市场人员都是常用操作,我就不详细贴步骤或演算方式啦。而前面的第 2、3 步,我是通过 grafana 直接用查询语句与我们家产品的数据库交互。之前我写过一篇 [grafana 的上手笔记](https://xue-posts.xue.cn/b40841f91139bd509ec9f2aa2312ba83c1ef17ec467aa7223483c3633f74c191),它还是相当简易的。——具体到我的本次需求来说,是否采用 grafana 不关键,grafana 只是一种工具,关键是要能与产品数据库交互拿到原始数据。 96 | 97 | 笔记虽然解决的是编程自学行为,是我家产品为用户所提供价值的核心表现,但思路也可借鉴用于其它产品、其它行为频次的统计。如果对你有帮助或启发,那就点赞或留言告诉我,鼓励我分享更多笔记吧! 98 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191024_mysql 数据分析如何实现日报、周报、月报和年报?.md: -------------------------------------------------------------------------------- 1 | # mysql 数据分析如何实现日报、周报、月报和年报? 2 | 3 | 以天为统计周期,是常见需求。周报、月报更是常见需求。长周期项目,甚至有年报需求。我已经掌握了`mysql`中按天统计,如何实现按年、按月、按周统计呢? 4 | 5 | ### 1、已掌握的技能:按天统计 6 | 7 | 实现以天为统计周期很简单。具体来说,`date()` 函数可返回时间数据的日期,即仅有年月日,没有时分秒信息。结合 `group by` 可实现按天统计。 8 | 9 | 以天为统计周期的数据指标非常多,随便举例,比如每日新增注册用户数。 10 | 11 | ```mysql 12 | select 13 | date(created_at) as 注册日期, 14 | count(user_id) as 用户数 15 | from 16 | users 17 | group by 18 | 注册日期 19 | order by 20 | 注册日期 21 | ``` 22 | ![image](https://user-images.githubusercontent.com/31027645/67449577-34303500-f64d-11e9-949c-776e850dd2d7.png) 23 | 24 | ### 2、从已知推理,拓展技能 25 | 26 | 既然`date()`函数可用,那么是否有对应的 `year`、`month`、`week` 等函数可用呢?这纯属我的推理,那试试看吧。 27 | 28 | ![image](https://user-images.githubusercontent.com/31027645/67449717-a739ab80-f64d-11e9-89d6-0d17c28e76e6.png) 29 | 30 | 果然可行。但美中不足的是,返回的周数和月数不带年份。当数据量跨年时,它会把每年相同周数或月数的数据加在一起。如何实现`某年某月`和`某年某周`呢?已有知识储备去推理,没找到答案,那就直接搜索吧! 31 | 32 | ### 3、搜索找答案 33 | 34 | 经过搜索和尝试发现,在 mysql 中用`date_format(column_name,'%Y-%m')`来代替`month()`就能拿到`年月`值。 35 | 36 | ![image](https://user-images.githubusercontent.com/31027645/67450105-eb797b80-f64e-11e9-9f76-d24ad15bad75.png) 37 | 38 | 如果把其中代表月 month 的关键字`m`换成周 week 呢?试试看。分别尝试: 39 | `date_format(column_name,'%Y-%w')` 和 `date_format(column_name,'%Y-%W')`。 40 | ![image](https://user-images.githubusercontent.com/31027645/67450200-2a0f3600-f64f-11e9-9a00-ff0e0db82077.png) 41 | 42 | 数据返回结果不对呀?并不是预期的今年第几周。小写的`w`返回的是本周第几天,大写的`W`返回的是周几的英文名。如何拿到`今年第几周`这个值,实现周报的统计周期呢? 43 | 44 | ### 4、觉察知识点欠缺,查漏补缺 45 | 46 | 我自学编程时,很喜欢从已知去推理,拓展自己的技能。通常推理能带来惊喜,当推理不够用时,那就搜索大法好。搜索特定问题的答案时,通常也能发现某块知识不足。比如我这里我就意识到自己不熟悉表达日期的关键字或常用语法。 47 | 48 | 恰好搜索时遇到[相濡以沫 66 的文章](https://www.cnblogs.com/smileFL/p/8473245.html),里面有很好的整理。 49 | 50 | MySQL 日期格式化(format)取值范围。 51 | 52 |  | | 值 | 含义 | 53 | |----- | ----- | ----- | 54 | |秒 | %S、%s | 两位数字形式的秒( 00,01, ..., 59) | 55 | |分 | %I、%i | 两位数字形式的分( 00,01, ..., 59) | 56 | |小时 | %H | 24 小时制,两位数形式小时(00,01, ...,23) | 57 | |%h | 12 小时制,两位数形式小时(00,01, ...,12) | 58 | |%k | 24 小时制,数形式小时(0,1, ...,23) | 59 | |%l | 12 小时制,数形式小时(0,1, ...,12) | 60 | |%T | 24 小时制,时间形式(HH:mm:ss) | 61 | |%r | 12 小时制,时间形式(hh:mm:ss AM 或 PM) | 62 | |%p | AM 上午或 PM 下午 | 63 | |周 | %W | 一周中每一天的名称(Sunday,Monday, ...,Saturday) | 64 | |%a | 一周中每一天名称的缩写(Sun,Mon, ...,Sat) | 65 | |%w | 以数字形式标识周(0=Sunday,1=Monday, ...,6=Saturday) | 66 | |%U | 数字表示周数,星期天为周中第一天 | 67 | |%u | 数字表示周数,星期一为周中第一天 | 68 | |天 | %d | 两位数字表示月中天数(01,02, ...,31) | 69 | |%e | 数字表示月中天数(1,2, ...,31) | 70 | |%D | 英文后缀表示月中天数(1st,2nd,3rd ...) | 71 | |%j | 以三位数字表示年中天数(001,002, ...,366) | 72 | |月 | %M | 英文月名(January,February, ...,December) | 73 | |%b | 英文缩写月名(Jan,Feb, ...,Dec) | 74 | |%m | 两位数字表示月份(01,02, ...,12) | 75 | |%c | 数字表示月份(1,2, ...,12) | 76 | |年 | %Y | 四位数字表示的年份(2015,2016...) | 77 | |%y | 两位数字表示的年份(15,16...) | 78 | |文字输出 | %文字 | 直接输出文字内容 | 79 | 80 | 把单个知识点,稍微提升到某块知识点,能让自己的知识技能再上一个台阶。 81 | 82 | ### 5、求助也是社交,问人附红包 83 | 84 | 上述表格相当实用,但依然没有解决如何获得“某年第几周”的需求。 85 | 86 | 虽然说主动检索找到答案,是很好的习惯。但自己耗费大量时间也没找到答案,又恰恰有目标相同的人一起互助,何不问问人看呢?学习么,本质上是个社交行为。在学一样技能时,我喜欢泡几个氛围好的学习群。经常在群里分享自己的心得笔记,也会主动力所能及地帮助别人,或者提出自己的疑问引发探讨。求助就是一种很好的社交行为啊。 87 | 88 | 此时我把疑问丢到编程学习群,并附上红包请教。经指点很快得到答案,用到了`concat()`函数来拼接。 89 | 90 | ![image](https://user-images.githubusercontent.com/31027645/67452605-524e6300-f656-11e9-8728-e52f430b2a62.png) 91 | 92 | 93 | 方便大家拷贝学习,放一下代码吧: 94 | ```mysql 95 | select 96 | concat(date_format(created_at,'%Y-'),week(created_at)) as 年周, 97 | count(user_id) as 用户数 98 | from 99 | users 100 | group by 101 | 年周 102 | order by 103 | 年周 104 | ``` 105 | 106 | ### 6、小结 107 | 108 | 总结一下,mysql 中可通过`date_format()` 和 `concat()`,`week()`等函数可完成数据分析中常用的月报、周报中按月、周统计的需求。关键语句为: 109 | - `date(column_name) as 年月日` 110 | - `date_format(column_name,'%Y-%m') as 年月` 111 | - `concat(date_format(column_name,'%Y-'),week(column_name) as 年周` 112 | 113 | 这篇笔记除了知识点,我也放了自己探索扩展技能的思路。是否对你有启发呢?如果有,记得留言或点赞告诉我,鼓励我多多分享。 114 | 115 | 特别申明:这篇笔记图中数据为本地数据库,仅供本人练习使用,并非任何产品网站的正式数据。 -------------------------------------------------------------------------------- /articles_of_coding_learning/20191024_告别硬编码,mysql 如何实现按某字段的不同取值进行统计.md: -------------------------------------------------------------------------------- 1 | # 告别硬编码,mysql 如何实现按某字段的不同取值进行统计 2 | 3 | 上周我突然意识到,我在`grafana`上写的 sql 语句存在多处`硬编码`。这篇笔记将记录如何实现没有硬编码的 sql 语句,以及自学编程过程中如何应对自己的笨拙代码和难题不断的状况。 4 | 5 | ### 1、有效但粗笨的硬编码 6 | 7 | 所谓`硬编码`,大意是指代码中出现很多具体的取值,每个取值都是手动赋值的。比如: 8 | 9 | ```mysql 10 | -- 达成某个成就的用户数 11 | select 12 | count(user_id) as 用户数 13 | from 14 | achivement_table 15 | where 16 | achivement_name= '牛刀小试' 17 | ``` 18 | 19 | 以我家产品 [xue.cn](https://xue.cn/) 的成就系统为例,我们首个版本仅有 10 个成就,我要拷贝粘贴修改成就名称达 10 次。最近成就升级到 V2 版本,有 17 个成就,未来还会有更多成就。再比如习题和章节,每本书的章节数和习题数,都是几十个起。至于统计每本书的阅读用户数,每个章节的留言数,每个成就的达成用户数……这类实现太频繁了。 20 | 21 | 如果全部采用硬编码,我意识到这将低效粗笨。 22 | 23 | 在初学编程时,你我总会写出一些低效但**生效**的代码。随着编程水平提升或需求变得复杂,我们将有机会迭代自己的代码。迭代是好事,但这不意味着之前的低效但有效的代码是坏事。——**接纳自己早期的笨拙,并追求持续的进步。咱们不需要为自己初学阶段的代码感到不好意思或羞愧,而是要视之为提升的机会。**这个心态令我在自学编程的路上几乎无所畏惧。 24 | 25 | ### 2、知道,但用时忘 26 | 27 | 如何实现代码自动获取每个取值,并按该值分别统计呢?我搜索到一些代码,却看不懂: 28 | 29 | ![image](https://user-images.githubusercontent.com/31027645/67061374-b8d50c00-f192-11e9-844a-2bbd5c996168.png) 30 | 31 | 不得已,我准备好问题描述,并发红包在编程学习群里请教。群友给出的答案让我哭笑不得: 32 | > 特么这方法我不是会吗!?鬼打墙啦。 33 | 34 | 这种现象在初学技能时,是不是挺常见的!?知道,但不熟练。知道知识点,但实战时可能想不起来。或者知道某一种实战情境,换到其它实战情境就忘了……嗯,本质上还是重复的不够,熟练度不行啊。 35 | 36 | ![image](https://user-images.githubusercontent.com/31027645/67475050-087e7080-f688-11e9-9aa5-4d78bad531a2.png) 37 | 38 | 既然是我已知的知识点,立即实操吧。 39 | 40 | #### 情境 A:字段取值范围在同一表格 41 | 42 | 想要统计的原数据,和该字段的所有取值范围,在同一张数据表时,代码简单如下。 43 | 44 | ```mysql 45 | -- 所有成就的完成用户数 46 | select 47 | achivement_name as 成就名称, 48 | count(user_id) as 用户数 49 | from 50 | achivement_table 51 | group by 52 | 成就名称 53 | order by 54 | 成就名称 55 | ``` 56 | 57 | #### 情境 B:字段取值范围在另一表格 58 | 59 | 想要统计的原数据,和该字段的所有取值范围,不在同一张数据表时,代码仅稍微复杂一点点。 60 | 61 | ```mysql 62 | -- 所有成就的完成用户数 63 | select 64 | achivements.name as 成就名称, 65 | count(achivement_event.user_id) as 用户数 66 | from 67 | achivement_event,achivements 68 | where 69 | achivement_event.name = achivements.name 70 | group by 71 | 成就名称 72 | order by 73 | 成就名称 74 | ``` 75 | ### 3、解决一个难题,新的困惑到来 76 | 77 | 硬编码的问题现在倒是解决了,但实现数据可视化时,又有新的情况产生。 78 | 79 | 之前的硬编码风格,在 `grafana` 上通过 `add query` 完成,该操作是新增数据列,使得数据结果是一行多列,每个成就名就是一列。 80 | 81 | ![image](https://user-images.githubusercontent.com/31027645/67475805-7d05df00-f689-11e9-9e60-cfce8ea6cc29.png) 82 | 83 | ![image](https://user-images.githubusercontent.com/31027645/67475687-36b08000-f689-11e9-9dfd-0b4f5e673cd8.png) 84 | 85 | 这种数据,用 `grafana` 的 `bar gauge` 图表类型展示效果很不错。 86 | 87 | ![image](https://user-images.githubusercontent.com/31027645/67476339-70ce5180-f68a-11e9-997d-32fc5fd9e229.png) 88 | 89 | 之后没有硬编码的 sql 语句,得到的数据结果是多行 2 列,首列是成就名,次列是用户数。相当于之前数据结果的倒置。 90 | 91 | 行列倒置在 `python pandas`中,就是对`dataframe`数据一个`T`操作而已。但在 grafana 上如何灵活地操作行列,我还有不少困惑要解决。——这并非我的不足,这是我将要提升的机会,对不? 92 | 93 | ### 小结 94 | 95 | 在这篇笔记中,我不仅记录了自己如何完成按某个字段的取值范围进行统计的需求,既有早期的硬编码风格,也有升级版的语句。我还分享了自己如何看待初学编程时的笨拙代码,如何应对一个难题接着一个难题的编程自学过程。希望我的笔记,带给你启发和力量。 -------------------------------------------------------------------------------- /articles_of_coding_learning/20191109_闯缸鱼:看懂python如何实现整数加和,再决定是否自学编程.md: -------------------------------------------------------------------------------- 1 | # 闯缸鱼:看懂 python 如何实现整数加和,再决定是否自学编程 2 | 3 | 玩鱼缸的新手都知道有一种鱼叫“闯缸鱼”,皮实好养,帮助新手判断鱼缸环境是否准备好。这篇笔记,最初用来解答一个编程新手的疑问,后来我发现,整理一下也可当做有兴趣自学 python 编程朋友们的“闯缸鱼”。 4 | 5 | **看懂本文,再决定要不要自学 python 编程吧!** 6 | 7 | ## 想要实现需求与写代码的环境 8 | 9 | 你想用 python 实现整数加和。这个需求是如何产生的,已经不再重要。你只想知道 python 代码是如何实现这个需求的。 10 | 11 | 下面我提供 3 种实现方法,并分别称之为: 12 | - A:路人都会,有点笨拙。 13 | - B:超级简约,仅一句代码。很好掌握的 python 基础功。 14 | - C:重复发明轮子。其实也是 python 基础功。 15 | 16 | 下面的代码及运行结果,是我直接在 [xue.cn](https://xue.cn/) 网页上敲出来的,它能让零基础编程自学者无需安装任何环境,网页上就能写代码,运行代码。如果你想试试自学 python 编程,找我微信 qiaoanlu 拿邀请码。 17 | 18 | ## 实现方法 A:路人都会,但很笨拙 19 | 20 | 我直接输入算式,然后回车,就能运行得到结果。简单到令人怀疑: 21 | > 这是 python 编程吗?! 22 | 23 | ![image](https://user-images.githubusercontent.com/31027645/68521917-aefd7f00-02e0-11ea-85a6-5ec5f760bc93.png) 24 | 25 | 其实,可以增加一句变量赋值,然后再把保存了加和结果的变量用 `print()` 打印出来。 26 | 27 | ![image](https://user-images.githubusercontent.com/31027645/68521951-f08e2a00-02e0-11ea-8550-d8885c681d1f.png) 28 | 29 | 直接输入算式,运行得到结果,是简单好用粗暴有效的技能。但为啥说这个方法笨拙呢?试想,当你想要计算 1 到 100 的加法,手动敲入 1 至 100 的整数 …… 想想都好累啊。不是说好学会编程能解放人力嘛? 30 | 31 | 由此可知:直接运行的方法,仅能适用于计算次数少的算式。 32 | 33 | ## 实现方法 B:超级简约,仅一句代码 34 | 35 | 这个方法中`sum()` 和 `range()` 是新手必须掌握的基础函数,简单好用。python 自带许多基础函数,功能强大,直接使用即可。 36 | 37 | - 使用`range()` 来表达 1 至 100 的整数,其中`range(1,101)` 包含左侧 1,不包含右侧 101,所以刚好代表 1 至 100 的整数。 38 | - 使用 `sum()` 实现加和。 39 | 40 | ![image](https://user-images.githubusercontent.com/31027645/68522042-e6b8f680-02e1-11ea-9548-4a01e1f835f1.png) 41 | 42 | ## 实现方法 C:重复发明轮子 43 | 44 | 如果不使用 `sum()` 和 `range() `,代码还能怎么写呢?现在和我一起重复制造轮子,咱们写代码实现内置函数 `sum()` 和 `range() `的功能。不难,条件控制语句而已。 45 | 46 | ```python 47 | # 计算整数 start 到 end 的和,不使用 sum 和 range 48 | start = 1 49 | end = 100 50 | result = 0 51 | while start <= end: 52 | result += start 53 | start += 1 54 | print(result) 55 | ``` 56 | 57 | ![image](https://user-images.githubusercontent.com/31027645/68522070-3dbecb80-02e2-11ea-8158-7c8a5b2fed9a.png) 58 | 59 | 其实你可以留意到,我把整数加和的起点和终点,都赋值给变量,这样简单改一下最上面 2 行赋值语句的值,就可以计算其它整数到整数的加和。 60 | 61 | 稍微改写一下,把它封装为一个函数,供以后重复使用。——瞧,最重要的基础功,自定义函数,也没那么难。 62 | 63 | ![image](https://user-images.githubusercontent.com/31027645/68522378-980d5b80-02e5-11ea-93c6-70cf61ce4dfb.png) 64 | 65 | ## 运算量非常大会怎样? 66 | 67 | 无论是 1 到 100,还是 1 到 10000,人脑算起来吃力,电脑却很简便快速。不管电脑多么善于快速计算,也总是有时耗。 68 | 69 | 下面我简单增加几句代码,用来记录代码的运算时间。这里我用到了一个 time 模块,需要 import 导入它。 70 | 71 | 计算 1 到 100 加和,用了 0.0012 秒。 72 | 73 | ![image](https://user-images.githubusercontent.com/31027645/68522132-c3427b80-02e2-11ea-8f79-0c49608943a1.png) 74 | 75 | 计算 1 到 10000 加和,用了 0.09 秒。 76 | 77 | ![image](https://user-images.githubusercontent.com/31027645/68522138-df461d00-02e2-11ea-9fe0-3df574ed8c17.png) 78 | 79 | 计算 1 到 1000000 加和,用了 1.3 秒。 80 | 81 | ![image](https://user-images.githubusercontent.com/31027645/68522144-f5ec7400-02e2-11ea-87cf-d067f7fbf7c5.png) 82 | 83 | 嗯,有意思~ 电脑果然就是比人脑在大量运算方面强劲不怠哇! 84 | 85 | ## “闯缸鱼” 86 | 87 | 玩鱼缸的新手都知道有一种鱼叫“闯缸鱼”,皮实好养,帮助新手判断鱼缸环境是否准备好。这篇笔记,最初用来解答一个编程新手的疑问,后来我发现,整理一下也可当做有兴趣自学 python 编程朋友们的“闯缸鱼”。 88 | 89 | 如果你没学过编程,居然也能有兴趣看完全文,甚至看懂大部分内容,那你就牛逼啦,python 可以考虑学起来,让电脑帮你解放部分重复性劳动吧。 90 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191110_Python 刷题笔记:math.floor() 的用法.md: -------------------------------------------------------------------------------- 1 | # Python 刷题笔记:math.floor() 的用法 2 | 3 | ## 1、刷题遇到知识盲区 4 | 5 | 今天继续在 [xue.cn](https://xue.cn/) 刷题,发现知识盲点:math 模块的 floor() 方法未曾听闻。我有个通用解决办法,搜索:`floor site:python.org` —— python 官方文档,是自学 python 编程最好的资料。这个意识相当重要,我拥有这个意识,完全来自于[《自学是门手艺》](https://xue.cn/)。 6 | 7 | 题目倒也简单,如下: 8 | 9 | > What gets printed by the code snippet below? 10 | 11 | ```python 12 | 13 | import math 14 | print(math.floor(5.5)) 15 | ``` 16 | 17 | ## 2、搜索 python 官方文档 18 | 19 | 搜索结果稍微有点麻烦,推荐链接是 python 2.X 版本,且是英文的: 20 | > math.floor(x) 21 | > Return the floor of x as a float, the largest integer value less than or equal to x. 22 | 23 | 好在这个英文也不困难,能大概读懂,意思是说,输入 float 类型的 x,返回 x 的取整数,该取整数将小于等于 x。 24 | 25 | 有时对自己的英语阅读理解能力不自信,又不想借助翻译工具,我会直接在 xue.cn 上敲入代码并运行,看看结果是否和自己的猜测相符: 26 | 27 | ![image](https://user-images.githubusercontent.com/31027645/68541668-72637d80-03dd-11ea-9a10-c1618e4500b3.png) 28 | 29 | ## 3、正确解题 30 | 31 | 理解了 math.floor() 的作用,现在答案就容易知晓啦。5.5 取整数为 5,正确答案是整数 5。 32 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191110_Python 刷题笔记:这很不python,官方大大能改下吗?.md: -------------------------------------------------------------------------------- 1 | # Python 刷题笔记:这很不 python,官方大大能改下吗? 2 | 3 | 惊讶:数值相等的整数或浮点数作为 dict 字典的键将指向同一项?! 4 | 5 | ## 1、刷题遇到知识盲区 6 | 7 | 今天继续在 [xue.cn](https://xue.cn/) 刷题,意外发现:整数和浮点数先后设为字典的键,会有奇怪的现象! 8 | 9 | 题目如下: 10 | ```python 11 | What gets printed? 12 | 13 | confusion = {} 14 | confusion[1] = 1 15 | confusion['1'] = 2 16 | confusion[1.0] = 4 17 | 18 | sum = 0 19 | for k in confusion: 20 | sum += confusion[k] 21 | 22 | print(sum) 23 | 24 | ``` 25 | ## 2、我的理解 VS 正确答案 26 | 27 | 暂时找不到精准词汇来描述这一现象,我于是选择写点代码,尝试确认该现象。 28 | 29 | 30 | 答题时我的理解是,整数 1 ,字符串 '1' 和浮点数 1.0 是不同类型,所以它们会成为该字典的三个键,字典中 3 项的值加和 1 + 2 +4 为 7。但正确答案却是 2 + 4 为 6。由此推论,这是把字典的键 整数 1 和 浮点数 1.0 所指向的视为同一项! 31 | 32 | 这个推论准确吗?如何验证推论是否准确? 33 | 34 | 首先,确认整数和浮点数都可以作为字典的键存在。 35 | 36 | ![image](https://user-images.githubusercontent.com/31027645/68541892-2108bd80-03e0-11ea-897f-93616846539c.png) 37 | 38 | 其次,数值相等的整数和浮点数先后作为字典的键时,会如何?写写代码试试看。 39 | 40 | ![image](https://user-images.githubusercontent.com/31027645/68541930-983e5180-03e0-11ea-9985-403f21dd8f30.png) 41 | 42 | 仔细观察发现,字典的键不会发生改变,字典的值发生覆盖:最先设为字典的键的类型,如果是整数,则总是整数,如果是浮点数,则总是浮点数。只有字典的值会发生覆盖。 43 | 44 | 这个观察准确吗?再写点代码,检查下字典的键的类型是否发生变化。 45 | 46 | ![image](https://user-images.githubusercontent.com/31027645/68541962-2a465a00-03e1-11ea-8ad6-9c93fb3c91c2.png) 47 | 48 | ![image](https://user-images.githubusercontent.com/31027645/68541964-30d4d180-03e1-11ea-8556-64bdba24263b.png) 49 | 50 | 经过上面的探索可知,数学意义上数值相等的整数或浮点数先后设为字典的键时,键的类型会与最初保持一致;但在调用该键时,整数或浮点数都可以,指向的是该字典的同一项! 51 | 52 | ![image](https://user-images.githubusercontent.com/31027645/68541992-bce6f900-03e1-11ea-978b-907919e81450.png) 53 | 54 | ## 3、小结与未完成困惑 55 | 56 | 这实在诡异。我虽然暂时不明白为什么,但总算确定该现象的存在了!整理好这篇笔记,发出来给高手们指点一下,看看能否找到为什么吧! 57 | 58 | BTW,这个现象不符合认知惯性啊,明明整数 1 ,字符串 '1' 和浮点数 1.0 是不同类型,为什么它们不会成为该字典的三个键??希望未来 python 能升级改掉这种情况…… -------------------------------------------------------------------------------- /articles_of_coding_learning/20191110_python刷题笔记:内建函数 getattr与setattr.md: -------------------------------------------------------------------------------- 1 | # Python 刷题笔记:内建函数 getattr 与 setattr 2 | 3 | ## 1、刷题遇到知识盲区 4 | 5 | 今天继续在 [xue.cn](https://xue.cn/) 刷题,发现知识盲点:getattr 与 setattr 未曾听闻。我有个通用解决办法,搜索:`getattr site:python.org` —— python 官方文档,是自学 python 编程最好的资料。这个意识相当重要,我拥有这个意识,完全来自于[《自学是门手艺》](https://xue.cn/)。 6 | 7 | 暂时难住我的题目如下: 8 | 9 | > What gets printed? 10 | ```python 11 | class A: 12 | def __init__(self, a, b, c): 13 | self.x = a + b + c 14 | 15 | a = A(1,2,3) 16 | b = getattr(a, 'x') 17 | setattr(a, 'x', b+1) 18 | print(a.x) 19 | 20 | ``` 21 | 22 | ## 2、搜索 python 官方文档 23 | 24 | 搜索结果表明,getattr, setattr, hasattr, delattr 这四个相关函数都是 [python 的内置函数](https://docs.python.org/3/library/functions.html)。如果英文不太好,可在 python 官网左上角选择简体中文。以下摘抄自 python 官方文档: 25 | 26 | ### **getattr(object, name[, default])** 27 | 28 | > 返回对象命名属性的值。name 必须是字符串。如果该字符串是对象的属性之一,则返回该属性的值。例如, getattr(x, 'foobar') 等同于 x.foobar。如果指定的属性不存在,且提供了 default 值,则返回它,否则触发 AttributeError。 29 | 30 | ### **hasattr(object, name)** 31 | 32 | > 该实参是一个对象和一个字符串。如果字符串是对象的属性之一的名称,则返回 True,否则返回 False。(此功能是通过调用 getattr(object, name) 看是否有 AttributeError 异常来实现的。) 33 | 34 | ### **setattr(object, name, value)** 35 | 36 | > 此函数与 getattr() 两相对应。 其参数为一个对象、一个字符串和一个任意值。 字符串指定一个现有属性或者新增属性。 函数会将值赋给该属性,只要对象允许这种操作。 例如,setattr(x, 'foobar', 123) 等价于 x.foobar = 123。 37 | 38 | ### **delattr(object, name)** 39 | 40 | > setattr() 相关的函数。实参是一个对象和一个字符串。该字符串必须是对象的某个属性。如果对象允许,该函数将删除指定的属性。例如 delattr(x, 'foobar') 等价于 del x.foobar 。 41 | 42 | ## 3、正确解题 43 | 浏览 python 官方文档 以上 四个函数的说明后,就很好理解啦。 44 | 45 | ```python 46 | 47 | #定义一个类,并设置初始化方法 48 | class A: 49 | def __init__(self, a, b, c): 50 | self.x = a + b + c 51 | 52 | #生成一个实例 53 | a = A(1,2,3) 54 | # 获取对象 a 的属性 x 的值,根据类定义,应为 1 + 2 + 3 即 6 55 | b = getattr(a, 'x') 56 | # 设置对象 a 的属性 x 的值为 b+1,b 上面计算得出为 6,所以 x 被设置为 6+1 即 7 57 | setattr(a, 'x', b+1) 58 | # 打印对象 a 的属性 x ,值为 7 59 | print(a.x) 60 | ``` 61 | 62 | 所以,正确答案为 7 ~ -------------------------------------------------------------------------------- /articles_of_coding_learning/20191110_刷题翻车:python 布尔运算操作符的优先级.md: -------------------------------------------------------------------------------- 1 | # 刷题翻车:python 布尔运算操作符的优先级 2 | 3 | 前两天在 [xue.cn](https://xue.cn/) 体验答题挑战,我有道题做错了,却不明白错在哪里。题目大概如下,代码运行后将打印什么? 4 | 5 | ```python 6 | if True or False and False: 7 | print('1') 8 | else: 9 | print('2') 10 | ``` 11 | 12 | 这个题目考察两个简单的知识点,一个是布尔运算,另一个是流程控制语句。结果是 1,我则选了 2。 13 | 14 | 复盘我的解题思路。先是布尔运算部分,我把 `True or False and False` 的结果算成 `False`,于是代码简化为: 15 | 16 | ```python 17 | if False: 18 | print('1') 19 | else: 20 | print('2') 21 | ``` 22 | 我短暂发懵,后来回过神来,整理了一篇笔记《和 35 岁刘阿姨一起自测 Python 流程控制基本功》用于巩固基础功。 23 | 24 | 流程控制之 if 分支控制语句,仅会执行条件为真的那个分支,所以上述代码段的结果为 2。然后这才发现,我错在布尔运算部分。在 xue.cn 网页上直接输入并运行`True or False and False` ,显示结果为 `True`。 25 | 26 | ![true](https://user-images.githubusercontent.com/31027645/68540363-e8f77f80-03cb-11ea-930b-8843c5e60e0e.png) 27 | 28 | 29 | 但我心算答案是 `False`。 30 | 我是如何心算的呢? 31 | - `True or False` 等于 `True` 32 | - `True and False` 等于 `False` 33 | 34 | 布尔值仅有 `True` 和 `False` 两个,布尔值操作符也仅有 `与 and`, `或 or`, `非 not` 三个。我本来以为自己全部掌握,怎么还做错,而且还不知道错在哪儿? 35 | 36 | 最简单的运算,自测一下,我均已掌握,并无错漏。 37 | ![true1](https://user-images.githubusercontent.com/31027645/68540360-dd0bbd80-03cb-11ea-883b-f55d25b1553b.png) 38 | 39 | 太奇怪了,错在哪儿?想不明白,那就打开《自学是门手艺》的“入口”和“值及相应的运算” 两个章节,重复读布尔运算操作符部分,才发现关键是: 40 | 41 | > **优先级最低的是或 or,然后是与 and, 优先级最高的是非 not** 42 | 43 | 而上述心算时,我把 `and` 、 `or` 视为同等优先级,并从左往右顺序计算。——务必留意:这个认识是错误的!这俩优先级不同! 44 | 45 | `True or False and False` 的计算顺序,应该是: 46 | - 没有括号,也没有`not`,那就先算`and` 47 | - `False and False` 等于 `False`,现在语句是 `True or False` 48 | - 最后算 or,`True or False` 等于 `True` 49 | 50 | 再找个题目`True and False or not True` 自测一下: 51 | - 没有括号,最先算 `not`,`not True` 等于 `False` ,现在语句是`True and False or False ` 52 | - 其次算 `and`,`True and False` 等于` False`,现在语句是 `False or False` 53 | - 最后算 `or`,`False or False`结果是`False` 54 | 55 | 现在想想真的很奇怪,当初我是如何想当然地把 `and` 和 `or` 视为同等优先级呢!——幸好还有机会能通过刷题发现自己的知识点错漏! 56 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191110_和35岁刘阿姨一起自测 Python 流程控制基本功.md: -------------------------------------------------------------------------------- 1 | # 和 35 岁刘阿姨一起自测 Python 流程控制基本功 2 | 3 | ## 0、突然降临的困惑 4 | 5 | 流程控制语句、布尔值、布尔值操作符都属于 `python` 的基础功。大好周末我写这篇笔记,不是为了整理这些基础知识点,而是记录几个令我突然迷惑的代码段。——代码本身很简单,但即便已经掌握了基础功,陡然看到其中某个代码段,编程初学者还是容易困惑! 6 | 7 | 你,要不要随我一起读完全文,检查下自己是否牢牢掌握了 `python` 的流程控制语句?现在开始吧。 8 | 9 | ## 1、流程控制语句之 if 分支控制 10 | 11 | ### 1.1 开胃小菜:几段简单的代码 12 | 13 | 运行下面代码段,将打印什么呢? 14 | 15 | **代码段 A** 16 | 17 | ```python 18 | if 1 + 2 == 3 : 19 | print('1') 20 | else: 21 | print('2') 22 | ``` 23 | 24 | **代码段 B** 25 | 26 | ```python 27 | if 1 + 3 == 3 : 28 | print('1') 29 | else: 30 | print('2') 31 | ``` 32 | 33 | 上述 `python` 代码简单,且写法都很常见。`A` 的结果是 `1`,`B` 的结果是 `2`。你答对了吧? 34 | 35 | ### 1.2 见证奇迹:抽象一下 36 | 37 | 接下来见证奇迹的时刻……再抽象一下,把上述语句中的布尔值的算式改成布尔值。下面两段运行代码后,将打印什么呢? 38 | 39 | **代码段 C** 40 | ```python 41 | if True: 42 | print('1') 43 | else: 44 | print('2') 45 | ``` 46 | 47 | **代码段 D** 48 | 49 | ```python 50 | if False: 51 | print('1') 52 | else: 53 | print('2') 54 | ``` 55 | 56 | 你是毫不犹豫、脱口而出的说出正确答案的吗?`C` 的结果是 `1`,`D` 的结果是` 2`。这次你依然都答对了吗? 57 | 58 | ### 1.3 原则:多理解,少死记硬背 59 | 60 | 我的真实情况是,前两天做 xue.cn 的答题挑战时,看到代码段 `D`这种代码,突然思维打结。你会不会也遇到过**明明早就掌握,但突然对某个知识点又理解无能**的返祖情况? 61 | 62 | 我知道这是常见现象,所以没有焦虑感。我苦思冥想,尝试用理解而非死记硬背来彻底掌握这个知识点。 63 | 64 | 我是这样理解的。代码段 `D` 首个分支是 `False` ,其它分支被放到 `else` ,其它分支相当于首个分支的补集,即 `not False` 也就是 `True`,于是代码段 `D` 等同于: 65 | 66 | **代码段 E** 67 | 68 | ```python 69 | if False: 70 | print('1') 71 | elif True: 72 | print('2') 73 | ``` 74 | 75 | 如法炮制,代码段 `C` 等同于: 76 | 77 | **代码段 F** 78 | 79 | ```python 80 | if True: 81 | print('1') 82 | elif False: 83 | print('2') 84 | ``` 85 | 86 | 从中可发现: **`if` 分支控制语句,只会触发 条件为 `True` 的那个分支,条件为 `False` 的语句不会触发。** 87 | 88 | 本来,这篇笔记整理到这里似乎也能收尾。但我立即联想到:流程控制语句,除了 `if` 这个分支控制,还有 `while` 和 `for` 两个循环控制,在循环控制语句中,会有怎样的规律呢? 89 | 90 | 打铁要趁热,不能停,我们继续检查自己的基础功是否牢靠,然后梳理一下吧!——认知心理学有个结论是,知识点之间的联想对照,具备非常好的学习效果。 91 | 92 | ## 2、流程控制语句之 while 与 for 循环控制 93 | 94 | ### 2.1 上菜:读代码,自测基础功 95 | 96 | **代码段 G**: 97 | 98 | ```python 99 | while False: 100 | print('1') 101 | break # 测试代码,加这句是为了用于跳出循环,避免无限循环 102 | else: 103 | print('2') 104 | ``` 105 | 106 | **代码段 H**: 107 | 108 | ```python 109 | while True: 110 | print('1') 111 | break # 测试代码,加这句是为了用于跳出循环,避免无限循环 112 | else: 113 | print('2') 114 | ``` 115 | 116 | **代码段 I**: 117 | ```python 118 | a = 1 119 | while a < 4: 120 | print(a) 121 | a = a + 1 122 | else: 123 | print('haha') 124 | ``` 125 | 126 | 代码段 `G` 的结果为 `2`,代码段 `H` 的结果为 `1`。代码段 `I` 的结果为 `1 2 3 haha`。 127 | 128 | 现在再看看 `for` 循环。 129 | 130 | **代码段 J**: 131 | 132 | ```python 133 | for True: 134 | print(‘1’) 135 | else: 136 | print('2') 137 | ``` 138 | 139 | **代码段 K**: 140 | 141 | ```python 142 | for i in range(4): 143 | print(i) 144 | else: 145 | print('aha') 146 | ``` 147 | 148 | 代码段 `J` 将报错,提示语法错误。代码段 `K` 结果为 `0 1 2 3 aha` 149 | 150 | ### 2.2 整理总结:基于理解,整理加深印象 151 | 152 | 结合之前用《自学是门手艺》学 python 基础功的印象,——如果印象很淡,说明自己的复习间隔太久,最好能调整下使之符合记忆曲线;整理时,最好立即翻到书中对应章节复习;再结合前面自测代码,有多种代码实现,现在我可以试着总结: 153 | 154 | - 在 `for` 和 `while` 循环控制语句中,`else` 并非必备部分。 155 | - `while` 的循环体,仅在条件为 `True` 时触发,条件一直为 `True` 就一直执行;条件为 `False` 或条件变成 `False` 时该部分才执行完毕。 156 | - `for` 的循环体,条件部分通常用于控制循环的次数或范围,并不能使用布尔值。 157 | - 循环控制语句有时包含`else` 部分,该 `else` 属于 `while` 整个循环控制的一部分。通常,`else`是当循环部分执行完毕后才触发。例外情况是,如果循环部分包含 `break` 语句并被触发,将跳出整个循环控制,即不执行 `else` 部分的代码。 158 | 159 | ## 3. 简短总结 160 | 161 | 对我个人而言,`for` 和 `while` 循环控制语句,自测与复习都很轻松,暂时没有发现什么疑虑。最初令我迷惑的分支控制语句: `if False` 的条件为`False`,不为真,故该分支将不被执行。——如果流程控制语句中包含布尔运算,那么仅在条件为真时才触发对应语句块。 162 | 163 | 你和我一起读到这里,是否检测到自己哪些地方存有困惑?如有,不妨参考我的做法,试试代码的不同写法,立即运行它,发现和总结规律吧!最后刘阿姨再叮嘱两句:多理解,少死记硬背,遵循记忆曲线,及时复习,用归纳整理的方式巩固加深影响哟~ 164 | 165 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191120_grafana 连接mysql 和 postgresql,如何查看数据库所有表格及表格字段?.md: -------------------------------------------------------------------------------- 1 | # grafana 连接 mysql 和 postgresql,如何查看数据库所有表格及表格字段? 2 | 3 | 以 grafana 连接以上不同数据源,mysql 和 postgresql 的处理不同。这是基础操作,简单整理如下。 4 | 5 | 查看数据库的所有表格: 6 | 7 | ```mysql 8 | --mysql 9 | show tables; 10 | 11 | ``` 12 | 13 | ```postgresql 14 | --postgresql 15 | select * from pg_tables; 16 | 17 | ``` 18 | 19 | 查看某个表格的所有字段: 20 | ```mysql 21 | --mysql 22 | describe tablename; 23 | ``` 24 | 25 | ```postgresql 26 | --postgresql 27 | select * from tablename limit 10; 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /articles_of_coding_learning/20191127_如何批量添加中文和英文数字之间的空格?用正则表达式吧.md: -------------------------------------------------------------------------------- 1 | # 如何批量添加中文和英文数字之间的空格?用正则表达式吧 2 | 3 | ## 1、中文与英文数字混合使用,排版有规范 4 | 5 | 写作中,我们经常遇到以下中文与英文、数字混用的情况。 6 | 7 | > 我自学python编程,是在xue.cn上进行的。时耗方面,基础功仅需50多小时,加上很多实战,包括初步运用pandas和爬虫处理业务需求,加在一起也才200多小时而已。 8 | 9 | 其实,中文和数字、英文之间有一个空格会更美观。 10 | 11 | > 我自学 python 编程,是在 xue.cn 上进行的。时耗方面,基础功仅需 50 多小时,加上很多实战,包括初步运用 pandas 和爬虫处理业务需求,加在一起也才 200 多小时而已。 12 | 13 | 但我们可能尚未养成这样的输入习惯,以至于要么全部没有空格,要么部分加了空格,部分没有。当然您可以不在乎这个文本规范。对于那些在意这个文本规范的人,想要规范格式,要么人工逐项修改,偶尔写写短文时这么操作貌似并不麻烦。但日积月累,这也将是一项不菲的时间开销。 14 | 15 | 要么,可以试试用正则匹配批量处理。——正是我这篇笔记想要分享的。你无须懂编程,也可使用特定工具快速完成批量添加中文和英文数字之间的空格。 16 | 17 | 我掌握这个技能,最初并非源于我个人写作排版,而是近日处理很多文字内容编辑时的一个刚需。掌握这个技能,帮我显著提高了工作效率,把重复性肌肉劳动大幅度降低。 18 | 19 | ## 2、正则表达式省掉千次万次机械操作 20 | 21 | 我的电脑中可以没有微软或金山的任何办公软件,但不可以没有 vscode 和 jupyter lab。vscode 不仅可以用于写代码,还可用于写文章。工作中需基于 github 协作时,我也采用 vscode 操作。 22 | 23 | 在 vscode 中存在以下搜索页签,展开具有以下选项: 24 | 25 | ![image](https://user-images.githubusercontent.com/31027645/69719927-7cf77400-114c-11ea-9869-2dfafc97b994.png) 26 | 27 | 第一行 search 填入所应匹配的样式。搜索支持三种模式。普通模式可直接复制粘贴你想要的样式,即便它有换行也是 OK 的。——在常见的办公软件中通常不支持复制粘贴换行,这足见 vscode 的强大实用。 28 | 29 | ![image](https://user-images.githubusercontent.com/31027645/69720207-0ad35f00-114d-11ea-8533-39258ea550c0.png) 30 | 31 | 想要搜索任意中文和数字或英文字母的组合,需要用到以下正则表达式,并启动正则匹配搜索模式: 32 | - 中文在左,数字或英文字母在右 `([\u4e00-\u9fa5]+)([\da-zA-Z]+)` 33 | - 数字或英文字母在左,中文在右 `([\da-zA-Z]+)([\u4e00-\u9fa5]+)` 34 | 35 | 然后 replace 行填写 `$1 $2`用于定义格式。 36 | 37 | ![image](https://user-images.githubusercontent.com/31027645/69720925-b335f300-114e-11ea-96cc-bbf3bdc381a4.png) 38 | 39 | 如果文件非常多,想要对指定文件范围内实施,可以在第 3、4 行分别定义文件范围,所支持的语法当然也是正则表达式啦。 40 | 41 | vscode 非常棒的一点在于,此时我已经可以预览修改后的效果,待确认无误后,再点击执行全部替换即可。 42 | 43 | 回到最初的需求,想要在中文紧挨着英文数字之间增加空格,分别处理中文在左、中文在右两个情况即可完成。是不是很简单呢? 44 | 45 | ## 3、背后的原理?10 分钟系统理解正则表达式 46 | 47 | 这背后的知识点,就是正则表达式。——这并非某种编程语言所特有的,而是几乎所有的编程语言都支持的一种处理。它采用了一些字符构成的语法来描述规则,然后便于对文本实施搜索、捕获、替换等操作。 48 | 49 | 如果你想要对正则表达式来个 10 分钟系统了解,可访问 xue.cn 以游客模式直接阅读《自学是门手艺》的第 3 章“3.2.4 正则表达式”即可。 50 | 51 | 这个 [github 链接](https://github.com/liujuanjuan1984/ucanuupnobb/commit/0572bc577d5651527c8b59f644b060cea6a1f8c0),你将看到我采用这一技巧对自己的编程学习笔记所作出的批量修改。——是的,这么大量的修改,只需一分钟。 -------------------------------------------------------------------------------- /articles_of_coding_learning/readme.md: -------------------------------------------------------------------------------- 1 | 与 python 编程学习 相关的笔记、文章。 -------------------------------------------------------------------------------- /code_of_practise/cipin.py: -------------------------------------------------------------------------------- 1 | def cipin_x(content,dic1,dic2): 2 | rlts = {} 3 | for i in dic1.keys(): 4 | for j in dic2.keys(): 5 | if dic2[j] <= dic1[i]: 6 | ci = i + j 7 | cix = j + i 8 | if ci in content and ci not in rlts.keys() : 9 | num = content.count(ci) 10 | if cix in content and ci not in rlts.keys() : 11 | numx = content.count(cix) 12 | if num > 1: 13 | rlts[ci]=num 14 | if numx > 1: 15 | rlts[cix]=numx 16 | #rlts = sorted(rlts.items(),key=lambda x:x[1],reverse=True) 17 | return rlts 18 | 19 | def cipin_1(content): 20 | from string import punctuation,whitespace 21 | atext = punctuation + whitespace 22 | rlts = {} 23 | for ci in content: 24 | if ci not in atext and ci not in rlts.keys(): 25 | num = content.count(ci) 26 | if num > 1: 27 | rlts[ci]=num 28 | #rlts = sorted(rlts.items(),key=lambda x:x[1],reverse=True) 29 | return rlts 30 | 31 | def main(): 32 | from content import book_x as content #加载想要统计的内容,string type 33 | import datetime 34 | import os.path 35 | 36 | x = str(datetime.datetime.now()) 37 | rlt_url = 'D:/rlts' + x[-6:] + '.txt' 38 | 39 | with open(rlt_url,'at') as f: 40 | f.write('\n'+str(datetime.datetime.now())+'\n') 41 | 42 | rlt1s = cipin_1(content) 43 | with open(rlt_url,'at') as f: 44 | f.write(str(rlt1s)) 45 | f.write('\n'+str(datetime.datetime.now())+'\n') 46 | 47 | rlt2s = cipin_x(content,rlt1s,rlt1s) 48 | with open(rlt_url,'at') as f: 49 | f.write(str(rlt2s)) 50 | f.write('\n'+str(datetime.datetime.now())+'\n') 51 | 52 | rlt3s = cipin_x(content,rlt1s,rlt2s) 53 | with open(rlt_url,'at') as f: 54 | f.write(str(rlt3s)) 55 | f.write('\n'+str(datetime.datetime.now())+'\n') 56 | 57 | rlt4s = cipin_x(content,rlt1s,rlt3s) 58 | with open(rlt_url,'at') as f: 59 | f.write(str(rlt4s)) 60 | f.write('\n'+str(datetime.datetime.now())+'\n') 61 | 62 | #rlt5s = cipin_x(content,rlt1s,rlt4s) 63 | #rlt6s = cipin_x(content,rlt1s,rlt5s) 64 | #rlt7s = cipin_x(content,rlt1s,rlt6s) 65 | 66 | 67 | if __name__ == "__main__": 68 | main() 69 | print('词频统计完成。\n结果前往 D:/rlt.txt') -------------------------------------------------------------------------------- /code_of_practise/creat_todo_list_from_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | 4 | """ 5 | 功能:采用模板便捷地生成指定日期的待办清单。 6 | """ 7 | 8 | MyToToPath = 'D:/liujuanjuan/vscode/records/todo/' 9 | 10 | 11 | #指定日期,并创建该日期的文件。 12 | whichDAY = input('请输入日期,格式为:20190228\n\n') 13 | yy=whichDAY[:4] 14 | mm=whichDAY[4:6] 15 | dd=whichDAY[6:] 16 | thisDAY = str(yy) + '年' + str(mm) + '月' + str(dd) + '日:\n' 17 | 18 | 19 | whenFile = MyToToPath + str(whichDAY) + '.md' 20 | sampleFile = MyToToPath + 'todosample.md' 21 | sf = open(sampleFile,'rt', encoding='utf-8') 22 | f = open(whenFile,'at', encoding='utf-8') 23 | 24 | f.write(thisDAY) 25 | 26 | for line in sf.readlines(): 27 | f.write(line) 28 | 29 | f.close() 30 | sf.close() 31 | 32 | 33 | -------------------------------------------------------------------------------- /code_of_practise/spider_crawler_csdn_user_homepage.py: -------------------------------------------------------------------------------- 1 | """ 2 | 一个简单的爬虫脚本,爬取指定用户的个人主页。比如可用于监测自己csdn文章的阅读、回复等数据变化。 3 | 4 | author:liujuanjuan1984 5 | date:2019-09-11 6 | 7 | """ 8 | 9 | import datetime 10 | import re 11 | import urllib.request 12 | import pandas as pd 13 | import random 14 | import pymysql 15 | import os.path 16 | 17 | from sqlalchemy import create_engine 18 | conn = create_engine('mysql+pymysql://root:password@localhost:3306/zhihuclawer',encoding='utf8') 19 | 20 | csdn_path = 'D:/crawler/output_csdn/' 21 | wf_log = open(csdn_path + 'log_csdn_my_article.txt', 'at') 22 | 23 | # 读取网页,把读取的数据返回为一个移除了换行空格等符号的 str 对象,供后续 re 处理调用 24 | def read_url(url): 25 | #header库实现随机header,一定程度上克制反爬 26 | headers_list = [ 27 | ("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.112 Safari/537.38"), 28 | ] 29 | rand = random.randint(1,len(headers_list)) 30 | opener = urllib.request.build_opener() 31 | opener.addheaders = headers_list.copy()[rand-1:rand] 32 | data = opener.open(url).read() 33 | html_text = str(data,encoding='utf-8') 34 | html_text = clean_str(html_text) 35 | return html_text 36 | 37 | def clean_str(str_obj): 38 | str_obj = str_obj.replace('\n','') 39 | str_obj = str_obj.replace('\t','') 40 | str_obj = str_obj.replace(' ','') 41 | str_obj = str_obj.replace(' ','') 42 | str_obj = str_obj.replace('\r','') 43 | return str_obj 44 | 45 | def read_a_page(url): 46 | html_text = read_url(url) 47 | attn = r'(.*?)(.*?)(.*?)

(.*?)

阅读数(.*?)

评论数(.*?)

' 48 | result = re.findall(attn,html_text,re.S) 49 | if result: 50 | article_df = pd.DataFrame(result,columns=['articlt_url','articlt_itype','articlt_type','articlt_title','articlt_url_2','articlt_desct','press_time','read_count','reply_count']) 51 | article_df['update_time'] = str(datetime.datetime.now()) 52 | pd.io.sql.to_sql(article_df, "csdn_my_article", conn, if_exists='append', index=False) 53 | print(datetime.datetime.now(),url,'is done.') 54 | wf_log.write(str(datetime.datetime.now()) + str(url) + 'is done.\n') 55 | return article_df 56 | 57 | def read_all_pages(pages=5,csdn_id='qiaoanlu'): 58 | print(datetime.datetime.now(),'read_all_pages ...') 59 | wf_log.write(str(datetime.datetime.now()) + 'read_all_pages ... args:' + str(pages) + ', ' + csdn_id+'\n') 60 | for i in range(1,pages+1): 61 | url = 'https://blog.csdn.net/' + csdn_id + '/article/list/' + str(i) + '?' 62 | try: 63 | read_a_page(url) 64 | except: 65 | print(datetime.datetime.now(),'some error happended',i) 66 | wf_log.write(str(datetime.datetime.now()) + str(i) +'some error happended') 67 | continue 68 | print(datetime.datetime.now(),'read_all_pages is done.') 69 | wf_log.write(str(datetime.datetime.now()) +'read_all_pages is done.\n') 70 | 71 | def output_file(): 72 | conn = pymysql.connect('localhost','root','789351','zhihuclawer') 73 | cursor = conn.cursor() 74 | sql_search = 'select * from csdn_my_article;' 75 | csdn_my_article = pd.read_sql(sql_search,conn) 76 | cursor.close() 77 | conn.close() 78 | 79 | rlt_url = csdn_path + 'csdn_my_article'+str(datetime.datetime.now())[:10]+'.csv' 80 | csdn_my_article.to_csv(rlt_url, encoding='utf_8_sig', index=False) 81 | 82 | print('文件已生成',rlt_url) 83 | wf_log.write(str(datetime.datetime.now()) + ' output_file is done.' + '\n') 84 | return csdn_my_article 85 | 86 | def main(): 87 | read_all_pages(pages=5,csdn_id='qiaoanlu') 88 | output_file() 89 | 90 | if __name__ == "__main__": 91 | main() -------------------------------------------------------------------------------- /file_sample/afiledata.txt: -------------------------------------------------------------------------------- 1 | 序号 名字 分数 备注 2 | 1 小丽 34 3 | 2 天天 89 排名上升 4 | 3 多多 12 糟糕! 5 | -------------------------------------------------------------------------------- /homework/homework_A.md: -------------------------------------------------------------------------------- 1 | ## 准备 vscode + github,并熟悉 git 的最少必要操作。 2 | 3 | 至于你为什么要开始自学编程,咱就不多说了。直接开干吧! 4 | 5 | ### 第1次:初次见面,vscode 请多关照。 6 | 7 | 1、请在你的电脑上安装软件 vscode 。 8 | 9 | > vscode 是编辑器的一种。如你所知,excel 和 word 是文本编辑器,而 vscode 是写代码用的编辑器,当然你也能用 vscode 来写txt或markdown的文件,工具嘛是给人用的,你想怎么用就怎么用。 10 | 11 | > 不装 vscode ,装了别的编辑器可以吗?当然可以吖。作为初学者,用什么编辑器都OK,但关键是,你在跟谁一起学?用同样的“编程环境”,可以帮助你在遇到问题时更快地获得答案。 12 | 13 | 请选择官网下载安装: https://code.visualstudio.com/ 14 | 15 | > 不用害怕 vscode 的英文界面,也不建议安装插件改成中文界面。反正就那么几个单词,用多了自然熟,完全不用硬记。 16 | 17 | 2、熟悉下vscode各个按钮和菜单都是干什么的。然后试着操作。不用硬记,你看着它眼熟即可。 18 | 19 | 3、创建一个markdown文件(即以.md为后缀的新文件),然后在文件中写下你遇到的困难以及如何解决的。 20 | 21 | 以后你总是要记录学习过程,而记录方式嘛:要么在该文件中添加,要么创建新的文件添加。都OK。 22 | 23 | ----- 24 | 25 | ### 第2次:初次见面,github 请多关照。 26 | 27 | 1、注册github账号。 28 | 29 | 官网地址:https://github.com/ 30 | 31 | 2、创建一个新仓库 Create a new repository 。操作入口在右上角你的头像旁边,有个+号。 32 | 33 | 3、在新创建的仓库页面,简单熟悉它的 Readme 与 issues 的使用。 34 | 35 | > readme 是这个仓库的实名说明书;issues 可以当做一个小的论坛使用。你以后可能用得着,也可能用不着;简单熟悉下新朋友即可。 36 | 37 | 4、复习一下 vscode 的各个按钮和菜单。不用硬记,反正只能你眼熟它,它不会眼熟于你。 38 | 39 | > 当你头一次用一个工具或一个网站,到处翻翻看,能让你增加熟悉感,以后不容易发怵。更何况,一回生二回熟嘛。 40 | 41 | 5、继续在vscode上增加你的学习记录。 42 | 43 | ------ 44 | 45 | ### 第3次:vscode 克隆了 github 的仓库。 46 | 47 | 1、在github 你的仓库页面 <>code 页找到 绿色按钮:clone or download,点击它并复制你的仓库的 url。 48 | 49 | 2、在你的本地创建一个新的文件夹: 50 | 51 | 2.1 选择你本地电脑的一处地方,建立一个文件夹,比如:codingstudy 作为代码学习专用。 52 | 53 | 2.2 在vscode中选择file - open folder 打开上述文件夹。 54 | 55 | > 这个操作也可以直接在 vscode 中通过 explorer 分页来操作。看看自己是否能找到并掌握这种方式? 56 | 57 | > 以后你会反复发现:解决同一个问题的方法有好些个,而不是仅仅只有一个。初学时,你只要会用一个就行。至于其它方法嘛,你可以探索做到心中有数,也可以先扔到一边不管。 58 | 59 | > 第一回追求够用,第二回追求好用。这样啃下第一周目,就容易很多。等未来二周目或N周目(指你完成一轮学习后,再回过头重新学一遍;一个周目就是完成一轮)时,再捡起来其它方法,或比较多种方法中哪个更好。 60 | 61 | 3、在 vscode 中,打开 terminal ,并确保 terminal 的光标所在位置刚好在上述文件夹。然后练习以下几个指令: 62 | 63 | `cd ..` 返回上一层文件夹 64 | 65 | `ls` 显示当前目录下的文件/文件夹 66 | 67 | `cd 文件夹` 进入当前目录下的某个文件夹 68 | 69 | > 这几个操作很常用,也很通用。在 dos,或者 linux shell 你都可能会用到。不如本次直接练习多次并掌握。 70 | 71 | 4、在上述文件下使用git clone指令,即可把你的新仓库,克隆到你的本地并呈现在你vscode的目录树中。 72 | 73 | `git clone url ` 74 | 75 | > 这个指令基本上只用了一次。以后虽然会用,但不常用。所有的指令都不用刻意记忆。你知道它是做什么的,你用多了就有印象了。如果没记住,再翻出来看,或者按用途去搜即可。保证使用频率,比死记硬背管用多了。 76 | 77 | 5、完成后,你可以在左侧文件树结构中看到你的仓库目录,你可以添加更多文件夹比如创建一个文件夹存放你的学习记录。 78 | 79 | 主文件夹 `/codingstudy/` 80 | 81 | 你的第1个仓库地址 `/codingstudy/yours/` 82 | 83 | 你将提交到第1个仓库上的学习记录 `/codingstudy/yours/notes/` 84 | 85 | > 上面的目录结构,仅仅是一个示意,你完全可以自己起其它名字。 86 | 87 | 6、你可以直接在左侧文件树中拖拽来管理文件,也可以在电脑中打开对应文件夹来剪切粘贴来完成文件管理。 88 | 89 | > 有些很简单的操作,就可能卡住一枚无基础的大汉。如果你遇到困难,请通过搜索引擎解决,解决不了的在互助小组请教。 90 | 91 | > 使用搜索引擎时,请留意你用什么关键词能更快找到优质的答案。可以记录到你的学习记录中。 92 | 93 | 7、继续在 vscode 上增加你的学习记录。 94 | 95 | ---- 96 | 97 | ### 第4次:vscode 向 github 推送并存管。 98 | 99 | 1、在 vscode 中,打开 terminal,并进入到你的仓库。 100 | 101 | > 如何打开 terminal ?如何在 terminal 进入到你的仓库目录地址,复习昨天的作业。 102 | 103 | 2、采用以下指令,把你的学习记录上传到 github 上。 104 | 105 | > 依次在 terminal 执行下面三条指令;可以访问github你的主页,查看是否产生新的commit记录。 106 | 107 | `git add 文件名/文件夹 ` 上传指定文件/文件夹 或者 `git add -A` 上传当前目录下所有 108 | 109 | `git commit -m "你的注释"` 110 | 111 | `git push origin master ` 112 | 113 | 3、你可以对 vscode 上的文件做小幅度更改,反复练习以上操作。因为以后你都将在 vscode 通过 git 指令来上传,而不直接在github 上操作。 114 | 115 | 4、如果你对文件目录相关的指令不熟悉,也可以继续反复练习。 116 | 117 | 5、继续在 vscode 上增加你的学习记录。并在 vscode 的 terminal 用 git 指令来提交上传到github上。 118 | 119 | > 因为按照作业建立的仓库是你的公开仓库,即别人也能访问并查看。所以,在提交前,请留意下你的学习记录有没有敏感、隐私信息吖?! 120 | 121 | ---- 122 | 123 | ### 第5次:是时候盘点一下自己已经掌握的技能了! 124 | 125 | 1、复习以上,并把 `work_A` 所有的学习记录,整理提交到自己的 github 上。 126 | 127 | 2、重点复习(通过反复练习而熟悉): 128 | 129 | - 文件目录操作; 130 | 131 | - 在 vscode 中打开 terminal,并采用 git 指令推送你的内容到github存管。 132 | 133 | ### 恭喜你!通关了 homework_A 系列! 134 | 135 | 目前你初步掌握了: 136 | 137 | 1、通过 git 版本管理工具,把你的学习记录提交和上传到 github 上保管。(目前是公开仓库)你的所有记录,都将有迹可循。 138 | 139 | 2、熟悉了 vscode 这个编辑器,这是一个很好用的编码环境。下面的作业中,我们总是用到它。 140 | 141 | 3、熟悉了 vscode 中如何打开 terminal 并对工具发出指令。下面的作业中,你将频繁用到它来帮你调试与验证你的代码。 142 | 143 | **你准备好接下来的探险了吗??** 144 | -------------------------------------------------------------------------------- /homework/homework_B.md: -------------------------------------------------------------------------------- 1 | ## hello python,我们一起携手上路吧。 2 | 3 | 为什么选择 python 来学,而不是其它?或许只是因为恰好笑来的新书,也是以 python 作为举例吧! 4 | 5 | ### 第1次:安装 python 并获取多本参考书,拥有随时可用且可靠的知识源。 6 | 7 | 1、通过vscode的插件,安装并确认你的 python 版本,建议为 3.X 版本。 8 | 9 | > vscode最左侧栏有多个标签页,比如:Explorer 用来管理文件目录,Search 用来跨文件搜索,Extensions 用来从vscode 的插件商店检索和安装各类工具与拓展应用。这3个标签页使用频率很高。 10 | 11 | 2、通过 google、kindle 或微信阅读 等,获取至少 5 份电子书 or 在线教程 or 实体书。 12 | 13 | > 一下子准备好几本书,不是为了制造更大的沉没成本让自己不愿意放弃学习Python,仅仅是为了让自己越发重视“检索”能力。答案除了在 google 中,也在很多前人的书中。作业不是“教程”,不教知识点,知识点需要你在完成作业的过程中串联起来并做一个验证。 14 | 15 | 3、快速翻阅以上教程,大概了解它们的目录和结构。 16 | 17 | ### 第2次:完成第1个最简版脚本,并让它运行起来! 18 | 19 | 1、在你的vscode的github仓库目录下,创建一个新的文件夹/mypython,作为python编程练习目录;并在该文件下创建第1个.py文件。 20 | 21 | 2、在该文件中写下你的第一句代码: 22 | 23 | ```python 24 | 25 | print('hello python,hello world') 26 | 27 | ``` 28 | 29 | 3、在目录树结构中,点击该文件名,右键选择“在终端中运行python文件”,来检查terminal的输出结果。 30 | 31 | hello python,hello world 32 | 33 | 4、了解并练习使用 print() 和 #注释 。 34 | 35 | 5、所有练习推送提交到github。 36 | 37 | ### 第3次:熟悉布尔值、逻辑操作符。 38 | 39 | 1、阅读相关电子书,对照参考,熟悉布尔值与布林运算相关概念。 40 | 41 | 2、创建1个新的py文件,并把所有的布林运算的情况,都写在脚本中,并执行运算你观察结果。比如: 42 | 43 | ```python 44 | True and True 45 | True or False 46 | not True 47 | 48 | ``` 49 | 50 | 3、然后再次回顾书中相关介绍。 51 | 52 | 4、熟练使用 print() 和 #注释 ,来帮助自己理解今日脚本中的每一句。 53 | 54 | 5、所有练习推送提交到github。 55 | 56 | 注:最初,你只用写自己的简版笔记即可。也可以参阅更多人的,看看还有哪些花样玩法。比如我写的 [boolean sample](https://github.com/liujuanjuan1984/ucanuupnobb/blob/master/homework_sample/boolean.py) 57 | 58 | ### 第4次:熟悉if条件语句。 59 | 60 | 1、阅读相关电子书,对照参考,熟悉 if 的各种用法。 61 | 62 | 2、创建1个新的py文件,并把 if 的各种用法,都写在脚本中,并执行运算你观察结果。 63 | 64 | > 你可以对if的各种用法进行初步整理。可能你熟悉了很多种用法,也可能仅熟悉了最基本的一两种,都没关系,初来乍到,掌握自己能掌握的程度,以后回头再来第二轮时继续补充即可。 65 | 66 | > 你的经验或总结部分,可以用注释来标注。比较大段或多段注释,可以采用三个引号来进行。具体用法请自行搜索。 67 | 68 | 3、然后再次回顾书中相关介绍。 69 | 70 | 4、熟练使用 print() 和 注释 ,来帮助自己理解今日脚本中的每一句。 71 | 72 | 5、所有练习推送提交到github。 73 | 74 | ### 第5次:把你自学编程的动力与阻力,用编程这门语言来表达。 75 | 76 | 1、复习前面的所有知识点,回过头看看自己有无新知。 77 | 78 | 2、尝试运用所学,把你在自我介绍时提到的动力与阻力,用if条件语句表达出来。类似于: 79 | 80 | ```python 81 | 82 | mystatus = '' 83 | 84 | def stop_my_study(): 85 | print('我居然停止自学 python了……') 86 | 87 | def i_love_coding(): 88 | print('和大家一起自学 python 很有意思,我已欲罢不能。') 89 | 90 | if mystatus == "阻力1" or "阻力2" or "阻力3" : 91 | stop_my_study() 92 | else: 93 | i_love_coding() 94 | 95 | ``` 96 | 97 | 3、请至少尝试2种方式来表达。包括上述示例。(但示例并不完善,还需要你完善)。 98 | 99 | 4、请试着理解代码只是一种语言表达方式,于是通过阅读其它人作业中的代码,并指出他们的问题,或给出优化建议,能帮助你验证和提高这种表达能力。 100 | 101 | 5、代码并没有100%的标准写法,有很多写法。如同表达“我喜欢你”,有很多种方式。从以上练习中,感知这一点。 102 | 103 | > 我想强调的是,你的代码写的和别人不同,并不是问题。你能把代码跑起来,得到你想要的正确结果,就OK。 104 | 105 | 106 | -------------------------------------------------------------------------------- /homework/homework_C.md: -------------------------------------------------------------------------------- 1 | 1、通读[《how-to-ask-questions-the-smart-way》中文翻译版](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md) 或者 英文原版。 2 | 3 | 2、 -------------------------------------------------------------------------------- /homework/homework_X.py: -------------------------------------------------------------------------------- 1 | import urllib2 2 | 3 | #目标:写个爬虫玩,把掘金沸点最近1年的热门推荐都收录到文档中。 4 | 5 | ''' 6 | # 方法:关键词搜“python3 爬虫”,找别人的代码试用。 7 | 8 | https://www.cnblogs.com/linshuhe/p/5733333.html 9 | 疑问:我没有 urllib2 库 10 | 11 | Python3 安装bulitwith 和urllib2包 12 | https://blog.csdn.net/qq_27657429/article/details/52653164 13 | 14 | 我不太能理解vscode,python3语言,与urllib2的库的关系。 15 | 16 | ''' 17 | 18 | def getHtml(url): 19 | response = urllib2.urlopen(url) 20 | html = response.read() 21 | return html 22 | 23 | print(getHtml("http://www.baidu.com")) 24 | -------------------------------------------------------------------------------- /homework/homework_sample/boolean.py: -------------------------------------------------------------------------------- 1 | """ 2 | 布尔值:True False 首字母必须大写。Python对大小写敏感。 3 | 4 | 布尔运算: 5 | 一维:not 6 | 二维:and or 7 | 二维运算从左到右执行,一维运算优先级高于二维。 8 | 9 | 布尔运算的返回结果是布尔值。 10 | 11 | sample功能:因为挨个写公式,并通过print()来断点很麻烦(要重复写/粘贴很多次print()),所以干脆写了个列表来遍历。 12 | 13 | 初学者只需关心布尔运算的表达式的返回值是什么,而不必掌握该文件内的写法。虽然不必掌握,但其实你也可以读懂! 14 | 15 | """ 16 | 17 | #把布尔运算的所有表达式,写在列表中。 18 | alist = [ 19 | True, #True 1 20 | False, #False 2 21 | True == 1, #True 3 22 | True == 0, #False 4 23 | False == 0, #True 5 24 | False == 1, #False 6 25 | True and True, #True 7 26 | True and False, #False 8 27 | True or True, #True 9 28 | True or False, #True 10 29 | False and True, #False 11 30 | False and False, #False 12 31 | False or True, #True 13 32 | False or False, #False 14 33 | not True, #False 15 34 | not False, #True 16 35 | True and not True, #False 17 36 | False or not False, #True 18 37 | True and True or not False and True] #True 19 38 | 39 | #通过for循环遍历列表,来检查每个表达式的输出值是什么。 40 | i = 1 41 | for a in alist[:]: 42 | if a == True : 43 | print(i,a,'is True.') 44 | else: 45 | print(i,a,'is false.') 46 | i += 1 47 | 48 | """ 49 | 走过的弯路&未解决的疑问: 50 | 51 | 我期待通过遍历列表元素并打印的方式,来阐述计算结果。但: 52 | 53 | print(str(a),'is True.') 54 | print(a,'is True.') 55 | 56 | 无论上述哪个语句, 57 | 又或者把what表达式先转换为str复制给另一个变量, 58 | 都无法打印出what的表达式,只能打印出它的返回值。 59 | 60 | 即便 通过alist[:].index(a) 获取index来标记的方式也仅能取到头2个元素。 61 | 62 | 所以只好设置了一个变量来记录所处理到哪个元素。 63 | 64 | """ 65 | -------------------------------------------------------------------------------- /homework/homework_sample/file.py: -------------------------------------------------------------------------------- 1 | #获取文件地址 2 | import os 3 | import os.path 4 | 5 | a_file_data_path = 'D:/liujuanjuan/vscode/ucanuupnobb/file_sample/afiledata.txt' 6 | 7 | def main(): 8 | for x in range(100): 9 | check_readline(x) 10 | 11 | 12 | 13 | 14 | #检查文件是否存在 15 | 16 | 17 | 18 | 19 | #读取文件内容,并处理 20 | 21 | #用with语句无需file.close() 22 | """ 23 | with open(a_file_data_path,'rt',encoding = 'utf-8') as f: 24 | x = f.readline() 25 | print(x) 26 | y = f.readlines() 27 | print(y) 28 | pass 29 | 30 | """ 31 | 32 | 33 | def check_readline(x): 34 | with open(a_file_data_path,'rt',encoding = 'utf-8') as f: 35 | y = f.readline(x) 36 | print(x,y) 37 | 38 | 39 | def check_readlines(x): 40 | with open(a_file_data_path,'rt',encoding = 'utf-8') as f: 41 | y = f.readlines() 42 | print(y) 43 | 44 | 45 | #读取指定行 46 | 47 | 48 | #写入文件(覆盖写,不覆盖写,每次写入前清空之前的内容) 49 | 50 | 51 | main() -------------------------------------------------------------------------------- /homework/homework_sample/list.py: -------------------------------------------------------------------------------- 1 | 2 | alist = ['liu','juan','juan'] 3 | 4 | for a in alist: 5 | print(a,alist.index(a)) 6 | for x in a: 7 | print(x,a,a.index(x)) 8 | 9 | acount = alist.count("juan") 10 | print('次数是',acount) 11 | 12 | 13 | 14 | """ 15 | #这就是无限循环本尊了。可以拷贝这段去新建一个.py文件运行试试。 16 | alist = ['liu','juan','juan'] 17 | for y in alist : 18 | alist.append('@') 19 | print(y,alist) 20 | """ 21 | 22 | #列表不切片,直接对列表操作,导致了列表被改变。 23 | #此段代码很容易陷入无限循环,只有通过breakTag来实现循环次数控制。 24 | breakTag = 4 25 | for y in alist : # 原本以为列表有3个元素,会遍历3次 26 | breakTag = breakTag - 1 27 | if breakTag > 0 : 28 | alist.append('@') #但这个操作让每一次遍历就会增加1个元素,并回归到 for 那句判断,从而导致无限循环。 29 | print(y,alist) 30 | print("\n开始演示切片控制列表被改变所带来的影响\n") 31 | dlist = ['liu','juan','juan'] 32 | blist = dlist[:] 33 | for y in dlist:#并没有操作dlist,所以无需担心无限循环。 34 | dlist[:].append('@') 35 | blist.append("$") 36 | print(y,':此时dlist是',dlist) 37 | print(y,':此时dlist[:]是',dlist[:]) 38 | print(y,':此时blist是',blist) 39 | -------------------------------------------------------------------------------- /homework/homework_sample/string.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | """ 4 | String的各种骚操作: 5 | 6 | https://docs.python.org/3/tutorial/inputoutput.html 7 | 8 | """ 9 | 10 | #字符串的赋值与操作 11 | astr = 'Python' 12 | bstr = " " 13 | cstr = '\n' 14 | dstr = astr + 'Good Job!' 15 | estr = 'LiuJuanjuan' 16 | fstr = astr + bstr * 2 + cstr * 3 + dstr * 2 + estr 17 | 18 | 19 | #打印字符串,同时输出该字符串的长度(有多少个字符) 20 | print('astr的值是:',astr,len(astr)) 21 | print('bstr的值是:',bstr,len(bstr)) 22 | print('cstr的值是:',cstr,len(cstr)) 23 | print('dstr的值是:',dstr,len(dstr)) 24 | print('estr的值是:',estr,len(estr)) 25 | print('fstr的值是:',fstr,len(fstr)) 26 | 27 | #遍历字符串: 28 | print('开始演示遍历字符串\n\n') 29 | for i in astr: 30 | print(i,astr.index(i)) 31 | 32 | print('开始演示遍历字符串,并做替换\n\n') 33 | for j in dstr: 34 | dstr.replace(j,'d') 35 | print(dstr,j) 36 | print(dstr,"还是原来的它吗?\n是的,dstr没有改变。\n\n") 37 | 38 | print('再次演示替换,但我们采用了赋值') 39 | for j in dstr: 40 | dstr = dstr.replace(j,'×') 41 | print(dstr,j) 42 | print(dstr,"还是原来的它吗?\n不是,dstr被改变了。\n\n") 43 | 44 | 45 | #字符串替换: 46 | print('开始演示字符串替换\n\n') 47 | print('dstr的初始值是:',dstr) 48 | print('estr的初始值是:',estr) 49 | dstr = estr 50 | print('经过 dstr = estr后,dstr是:', dstr) 51 | print('经过 dstr = estr后,dstr是:', estr) 52 | 53 | #检索字符串 54 | afind = estr.find('ua') #仅返回最近一次的,并不会返回所有 55 | acount = estr.count('u') 56 | acount = estr.count('U') 57 | aindex = estr.index('u') #并不算常规方法? 58 | aupper = estr.upper() 59 | alower = estr.lower() 60 | 61 | print(afind,'发现\'u\'的位置') 62 | print(acount,'发现\'u\'的次数') 63 | print(aindex,'发现\'u\'的位置') 64 | print(aupper,'字符串全部大写') 65 | print(alower,'字符串全部小写') 66 | 67 | 68 | 69 | #字符串的“切片” 70 | print('开始演示字符串的切片\n\n') 71 | print('estr的初始值是:',estr) 72 | print('estr[:]的值是:',estr[:]) #为了避免影响原字符串,有时候会采用切片的方式来拷贝一个新的字符串? 73 | print('estr[0:2]的值是:',estr[0:2])#[]的规律是:左包括,右不包括 74 | print('estr[:2]的值是:',estr[:2]) 75 | print('estr[2:4]的值是:',estr[2:4]) 76 | print('estr[-4:-1]的值是:',estr[-4:-1])#倒数第四位,到倒数第一位但不包括倒数第一位 77 | 78 | 79 | #字符串切片的应用,其实我的感受还不深,只是知道可以这么玩儿。 80 | for x in estr[:]: 81 | estr[:].replace(x,'√') 82 | print(estr) 83 | print(estr[:]) #无论是否切片,目前这种方式都不会改变字符串。 84 | 85 | #操作列表导致列表被改变而带来的问题,可以查看list.py 86 | 87 | 88 | #尚未不了解的方法还有很多…… 89 | 90 | #往字符串指定位置插入新的字符串 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /homework/testyourself/test_yourself_001.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | 4 | """ 5 | 题目: 6 | 文章统计所有字符(统计英文[大小写不敏感],数字;其他符号不计算)的出现次数,并按照次数倒序输出 7 | 8 | a:1001 9 | c:888 10 | 1:12 11 | 3:5 12 | 13 | """ 14 | 15 | testFile ='D:/liujuanjuan/vscode/ucanuupnobb/testyourself/test_yourself_001.txt' 16 | 17 | def main(): 18 | with open(testFile,'rt',encoding='UTF-8') as f: 19 | blines = f.readlines() 20 | 21 | aList = get_chars(blines) 22 | muchtimesDic = count_chars(aList,blines) 23 | 24 | keys = muchtimesDic.keys() 25 | vals = muchtimesDic.values() 26 | rlist = [(key,val) for key,val in zip(keys,vals)] 27 | 28 | Rlist = sorted(rlist,key = lambda x:x[1],reverse = True) 29 | for i in Rlist: 30 | print(i[0],i[1]) 31 | print(Rlist) 32 | 33 | def get_chars(blines): 34 | """ 35 | 功能:获取待检索的字符列表。通过遍历文本,把所有出现的字符列举出来。(大小写不敏感) 36 | """ 37 | aList = [] 38 | 39 | for aline in blines: 40 | aline = aline.lower() 41 | bline = aline[:] 42 | for i in bline: 43 | if i not in aList : 44 | aList.append(i) 45 | return aList 46 | 47 | 48 | def count_chars(aList,blines): 49 | """ 50 | 功能:统计字符出现的次数,并返回字典。 51 | """ 52 | muchtimesDic = {} 53 | 54 | for i in aList: 55 | howmanytimes = 0 56 | for aline in blines: 57 | aline = aline.lower() 58 | bline = aline[:] 59 | if i in bline: 60 | howmanytimes = bline.count(i) + howmanytimes 61 | muchtimesDic[i] = howmanytimes 62 | return muchtimesDic 63 | 64 | 65 | main() -------------------------------------------------------------------------------- /homework/testyourself/test_yourself_001.txt: -------------------------------------------------------------------------------- 1 | 'His instincts have been right': Amid Trump's bluster on North Korea, a strategy takes shape 2 | Some - with deeper knowledge into North Korea than most - say Trump's willingness to rip up the foreign policy rule book might - just might - be an advantage 3 | 4 | Estonian construction workers saved a frozen animal from an icy river, then realized it wasn't a dog 5 | US, South Korean diplomats meet ahead of Trump-Kim summit 6 | Daily horoscope for Wednesday, February 27, 2019 7 | Hanoi summit nightmare scenario: Bad deals and little change 8 | Mother and daughter, 19, charged with murder of five family members, including three children 9 | HANOI, Vietnam – When President Donald Trump boasts of his wonderful relationship with North Korean supreme leader Kim Jong Un, or claims that there would have been war if he hadn’t been elected, many people cringe. 10 | 11 | But behind Trump’s boasting and bluster, a small band of experts in North Korean affairs see a strategy taking shape. 12 | 13 | Making Kim feel respected and secure, they say, offers a possible way to persuade him to give up – or at least scale back – his nuclear arsenal in return for economic and diplomatic rewards. 14 | 15 | “I am not a Trump supporter on 99 percent of what he does. But, strangely enough, his instincts have been right about North Korea,” Joel Wit, a senior fellow at the Stimson Center in Washington who was involved in past negotiations with the North Koreans while at the State Department. 16 | 17 | So far, Trump’s goals for his second summit with Kim have been a moving target. 18 | 19 | 20 | Donald J. Trump 21 | ✔ 22 | @realDonaldTrump 23 | The Democrats should stop talking about what I should do with North Korea and ask themselves instead why they didn’t do “it” during eight years of the Obama Administration? 24 | 25 | 142K 26 | 9:36 PM - Feb 26, 2019 27 | Twitter Ads info and privacy 28 | 55.9K people are talking about this 29 | In advance of Wednesday’s initial talks, he has flattered and cajoled Kim, described the North as an “economic powerhouse” in waiting, and – to the surprise of many – said he was in “no rush” to find a deal that would dismantle Kim’s nuclear program. 30 | 31 | Even the definition of “denuclearization” hasn’t been hammered out between U.S. and North Korean negotiators – with Kim’s regime indicating that it could entail a significant rollback of U.S. defense arrangements with allies in the region. 32 | 33 | Still, supporters of Trump’s outreach, such as Wit, cite North Korea’s tension-easing suspension of nuclear and missile tests as an important step forward. 34 | 35 | Yet Wit’s view is a minority one in the polarized world of Washington. Trump’s Democratic foes – and some Republican hawks – see dangerous signs of a president without much grasp of foreign policy who could be played by North Koreans. Even Trump’s own intelligence chief, Daniel Coats, testified last month that Kim isn’t likely to give up his nuclear weapons. 36 | 37 | But there are others – with deeper knowledge into North Korea than most – who say Trump’s approach is the best game in town at the moment. They say his willingness to rip up the foreign policy rule book on a gut instinct might – just might – be an advantage. 38 | 39 | They include Robert Carlin, a visiting scholar at Stanford University who was involved in U.S.-North Korea talks from 1992 to 2000, and Siegfried Hecker, a leading nuclear scientist who visited North Korea’s main Yongbyon nuclear complex in 2010. 40 | 41 | Kim Yo-jong holds an ashtray for brother Kim Jong-un’s smoke break en route to Hanoi 42 | As Kim’s car passes, North Korean defector cries and shouts 43 | Trump lowers expectations for North Korea summit as Kim Jong Un arrives in Vietnam 44 | At Stanford, Hecker, Carlin and researcher Elliot Serbin have been charting the degree of risk on the Korean Peninsula since 1992, using a range of indicators ranging from diplomacy to various aspects of North Korea’s nuclear and missile program. 45 | 46 | On their color-coded chart, bright green is the safest classification, bright red the riskiest. 47 | 48 | When Barack Obama took office, the boxes were a mixture of pinks and light reds. By the time he left office, eight out of 11 boxes were bright red, with North Korea testing missiles and bombs. 49 | 50 | By 2017 – with Trump’s bombastically calling Kim “Little Rocket Man”– nine boxes were bright red. 51 | 52 | “The risk of war was high,” Hecker said. 53 | 54 | Since then, though, the diplomacy box has shifted to green. With North Korea suspending nuclear and missile tests, other boxes have returned to a more reassuring mid-red or pink. 55 | 56 | “Rapid North/South rapprochement and the Singapore Summit in 2018 dramatically lowered tensions and the threat of war on the Korean Peninsula,” the trio says in a report, “creating space and time to pursue diplomatic solutions.” 57 | 58 | Before leaving office, Obama told Trump that he had pushed his military to develop plans for a pre-emptive strike to destroy North Korea’s missiles, Wit said, although those plans were never drawn up. Wit said his conclusions were drawn from 150 interviews with Trump and Obama administration officials over the past year as part of research for a book. 59 | 60 | 61 | U.S. President Donald Trump talks with reporters before a meeting with Vietnamese Prime Minister Nguyen Xuan Phuc, Feb. 27, 2019 in Hanoi. Evan Vucci/AP 62 | Even Wit – who likes Trump’s approach – says the president’s iconoclastic style and resistance to criticism might also work against him. Combine that with a lack of attention to details, and “that leaves him open to making big mistakes,” Wit said in a breakfast meeting with a group of South Korean lawmakers and experts. 63 | 64 | After Trump landed in Hanoi aboard Air Force One on Tuesday, his motorcade passed thousands of onlookers, many recording the moment on their cellphones. People waved, and some held flower bouquets or Vietnamese flags, featuring a gold star on a red background. 65 | 66 | Earlier, Kim arrived at the Dong Dang train station at Vietnam’s border with China after a 65-hour, 2,500-mile train journey from Pyongyang. Kim, wearing a dark Mao-style suit, disembarked from his personal armored train at 8:22 a.m. under cold, drizzly skies. 67 | 68 | By now, Trump’s negotiating strategy is becoming familiar, from NAFTA to the trade talks with China: Go in with all guns blazing, dial up the rhetoric and then finally let officials quietly seek a reasonable compromise. 69 | 70 | The risk with North Korea, many experts say, is Trump’s rush to make a deal when talks resume this week. 71 | 72 | He could end up granting Kim the diplomatic recognition and economic relief he craves without forcing him to surrender his weapons, allowing North Korea to take its place as a de facto nuclear power, critics fear. He may also undermine U.S. alliances with Japan and South Korea. 73 | 74 | 75 | North Korean leader Kim Jong Un waves upon arrival by train in Dong Dang in Vietnamese border town, Feb. 26, 2019, ahead of his second summit with U.S. President Donald Trump. Minh Hoang/AP 76 | But Trump is defiantly sure he’s on the right track. 77 | 78 | “So funny to watch people who have failed for years, they got NOTHING, telling me how to negotiate with North Korea. But thanks anyway,” Trump tweeted Monday, before leaving for Hanoi. 79 | 80 | South Korean President Moon Jae-in, who has been the strongest advocate of engagement with the North, struck a similar note. 81 | 82 | “Even after overcoming difficulties to get this far, some people are still displeased with improvements in inter-Korean and North Korea-U. S. relations and are trying to drag them down,” he said in a statement. “I urge all of them to discard such biased perspectives, and let’s do our best to seize the opportunity approaching us.” 83 | 84 | North Korea’s state-run Korean Central News Agency joined the pushback against Trump’s critics. 85 | 86 | Democrats in the United States, it said, are trying to “overtly and covertly disrupt the talks,” using “all sorts of groundless stories and misinformation,” KCNA wrote. 87 | 88 | “Opposition just for the sake of opposition,” the news agency added. 89 | 90 | And the KCNA’s take on the U.S. intelligence community? 91 | 92 | “It is absolutely as foolhardy as expecting to see a chicken turning into a phoenix to expect proper comment from the U.S. intelligence agencies,” KCNA wrote, “as they have it as their basic mission to claim white to be black, and lies to be truth, out of their skepticism toward others.” 93 | 94 | 95 | In Hanoi this week, the broad outline of a possible deal began to take shape, involving a declaration to end the 1950-1953 Korean War, the opening of liaison offices in each country’s capital, the closure of the Yongbyon nuclear complex and some marginal sanctions relief. 96 | 97 | But experts said it remains far from clear whether Trump and Kim will find enough common ground to get it over the line. 98 | 99 | The outreach with North Korea is “clearly better off” with Trump’s top-down summit-driven approach, said Joseph Yun, who served as the U.S. special representative for North Korea from October 2016 to March 2018, spanning Obama and Trump. 100 | 101 | “There is no talk of war, so everyone is supportive of engagement of North Korea, political, diplomatic, economic engagement,” he said 102 | 103 | “The question that remains: ‘Has it made a big difference in nuclear weapons development?’ So far the answer is no,” he added. “So this is the question that this summit has to answer.” 104 | -------------------------------------------------------------------------------- /test-for-you.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liujuanjuan1984/ucanuupnobb/f083dffbfa154805ddf49ee8e6bd460493a7b25c/test-for-you.md --------------------------------------------------------------------------------