Commit 0a4d03f9 authored by jackfrued's avatar jackfrued

更新了更新日志

parent 6eb9ffc5
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> 作者:骆昊 > 作者:骆昊
> >
> 说明:最近有很多想学习Python的小伙伴申请单独加我微信和QQ,因为我自己平时也很忙,没办法一一解答大家的问题,我创建了**Python100天学习交流7群**(之前的三个2000人群1群、2群、6群、三个1000人群3群、4群、5群已经全部满员),群号为**784430256**,二维码在下方。我的同事和朋友也在这个群里,他们很多都是优秀的Python开发者,有丰富的商业项目经验,我们在闲暇的时候会为大家解答问题,内容包括但不限于Python语言基础、Web后端开发、网络数据采集、数据分析和机器学习。我们希望这个群能够慢慢汇集资深人士和行业大咖,营造一个相对纯粹的技术社区。以后我们争取每周做一次视频直播,以专题的形式分享Python开发的点点滴滴,同时还会不定期的举办线上和线下的技术交流和分享活动,小伙伴们可以加群进行交流。创作不易,感谢各位小伙伴的打赏支持,这些钱不会用于购买咖啡而是捐赠给支教组织。感谢**北京千锋互联科技有限公司Python教学部**对[公开课](https://ke.qq.com/course/406954)的支持。 > 最近有很多想学习Python的小伙伴申请单独加我微信和QQ,因为我自己平时也很忙,没办法一一解答大家的问题,我创建了**Python100天学习交流7群**(之前的6个群已经基本满员),群号为**784430256**,二维码在下方。我的同事和朋友也在这个群里,他们很多都是优秀的Python开发者,有丰富的商业项目经验,我们在闲暇的时候会为大家解答问题,内容包括但不限于Python语言基础、Web后端开发、网络数据采集、数据分析和机器学习。我们希望这个群能够慢慢汇集资深人士和行业大咖,营造一个相对纯粹的技术社区。以后我们争取每周做一次视频直播,以专题的形式分享Python开发的点点滴滴,同时还会不定期的举办线上和线下的技术交流和分享活动,小伙伴们可以加群进行交流。创作不易,感谢各位小伙伴的打赏支持,这些钱不会用于购买咖啡而是捐赠给支教组织([点击](./更新日志.md)了解捐赠情况)。感谢**北京千锋互联科技有限公司Python教学部**对[公开课](https://ke.qq.com/course/406954)的支持。
![](./res/qq_group.png) ![](./res/qq_group.png)
......
## 更新日志 ## 更新日志
### 2019年7月11日
1. 今天终于结束了出差的日子,回来先把最近收到的打赏全部捐赠给了绿之叶,总共捐出了111笔打赏。
![](./res/donation.png)
### 2019年7月9日 ### 2019年7月9日
1. 最近出差,项目一直处于停更状态。交流群的很多初学者反馈从第8天开始内容就有一定难度,最近本来也打算把语言基础部分和爬虫的部门重新整理一次,这次争取将文字和案例做得更加通俗易懂,而且更具实用性,这个事情从今天已然开始了,最终的目标是要将这部分的内容整理成一本书,希望大家到时候能够一如既往的支持。 1. 最近出差,项目一直处于停更状态。交流群的很多初学者反馈从第8天开始内容就有一定难度,最近本来也打算把语言基础部分和爬虫的部门重新整理一次,这次争取将文字和案例做得更加通俗易懂,而且更具实用性,这个事情从今天已然开始了,最终的目标是要将这部分的内容整理成一本书,希望大家到时候能够一如既往的支持。
2. 最近1周多的时间一共收到60笔以上的打赏,最多的一天收到了14笔打赏,还是要再次谢谢大家为知识付费的行为,当然加交流群是不用付费的,这些打赏费用在年底会捐赠出去,到时候会公开捐赠情况 2. 最近1周多的时间一共收到60笔以上的打赏,最多的一天收到了14笔打赏,还是要再次谢谢大家为知识付费的行为,当然加交流群是不用付费的,您支付的费用会用于支持山区儿童教育
3. 今天重新翻译了*Zen of Python*,这次的版本我自己都比较喜欢,所以也分享给大家。 3. 今天重新翻译了*Zen of Python*,这次的版本我自己都比较喜欢,所以也分享给大家。
### 2019年6月30日 ### 2019年6月30日
...@@ -24,6 +30,6 @@ ...@@ -24,6 +30,6 @@
### 2019年6月18日 ### 2019年6月18日
1. 在朋友的建议下,给首页加了一个打赏的二维码,看看有多少愿意为知识付费。今天一共收到了7位小伙伴的打赏,在此表示感谢。打赏获得的收入在年底将全部捐赠给**绿之叶公益**[点击了解](<https://baike.baidu.com/item/%E7%BB%BF%E4%B9%8B%E5%8F%B6%E5%85%AC%E7%9B%8A>))。之前每年都会试着为这个公益组织做一些自己能做的事情,这次当然也不能例外。 1. 在朋友的建议下,给首页加了一个打赏的二维码,看看有多少愿意为知识付费。今天一共收到了7位小伙伴的打赏,在此表示感谢。打赏获得的收入将全部捐赠给**绿之叶公益**[点击了解](<https://baike.baidu.com/item/%E7%BB%BF%E4%B9%8B%E5%8F%B6%E5%85%AC%E7%9B%8A>))。之前每年都会试着为这个公益组织做一些自己能做的事情,这次当然也不能例外。
2. Django部分(第41天到第55天)更新到第47天,最新上线的部分包括报表、日志、ORM查询优化以及中间件相关的内容,并将投票应用的完成代码同步到github。 2. Django部分(第41天到第55天)更新到第47天,最新上线的部分包括报表、日志、ORM查询优化以及中间件相关的内容,并将投票应用的完成代码同步到github。
...@@ -34,7 +34,6 @@ def main(): ...@@ -34,7 +34,6 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()
``` ```
上面代码的部分运行结果如下图所示,出现这个结果的原因是Python出于对性能的考虑所做的一项优化。对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫`small_ints`的链表中,在Python的整个生命周期内,任何需要引用这些整数对象的地方,都不再重新创建新的对象,而是直接引用缓存中的对象。Python把频繁使用的整数对象的值定在[-5, 256]这个区间,如果需要这个范围的整数,就直接从`small_ints`中获取引用而不是临时创建新的对象。因为大于256或小于-5的整数不在该范围之内,所以就算两个整数的值是一样,但它们是不同的对象。 上面代码的部分运行结果如下图所示,出现这个结果的原因是Python出于对性能的考虑所做的一项优化。对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫`small_ints`的链表中,在Python的整个生命周期内,任何需要引用这些整数对象的地方,都不再重新创建新的对象,而是直接引用缓存中的对象。Python把频繁使用的整数对象的值定在[-5, 256]这个区间,如果需要这个范围的整数,就直接从`small_ints`中获取引用而不是临时创建新的对象。因为大于256或小于-5的整数不在该范围之内,所以就算两个整数的值是一样,但它们是不同的对象。
...@@ -44,7 +43,6 @@ if __name__ == '__main__': ...@@ -44,7 +43,6 @@ if __name__ == '__main__':
当然仅仅如此这个坑就不值一提了,如果你理解了上面的规则,我们就再看看下面的代码。 当然仅仅如此这个坑就不值一提了,如果你理解了上面的规则,我们就再看看下面的代码。
```Python ```Python
import dis
a = 257 a = 257
...@@ -58,17 +56,15 @@ def main(): ...@@ -58,17 +56,15 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()
``` ```
程序的执行结果已经用注释写在代码上了。够坑吧!看上去`a``b``c`的值都是一样的,但是`is`运算的结果却不一样。为什么会出现这样的结果,首先我们来说说Python程序中的代码块。所谓代码块是程序的一个最小的基本执行单位,一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫做一个代码块。上面的代码由两个代码块构成,`a = 257`是一个代码块,`main`函数是另外一个代码块。Python内部为了进一步提高性能,凡是在一个代码块中创建的整数对象,如果值不在`small_ints`缓存范围之内,但在同一个代码块中已经存在一个值与其相同的整数对象了,那么就直接引用该对象,否则创建一个新的对象出来,这条规则对不在`small_ints`范围的负数并不适用,对负数值浮点数也不适用,但对非负浮点数和字符串都是适用的,这一点读者可以自行证明。所以 `b is c`返回了`True`,而`a``b`不在同一个代码块中,虽然值都是257,但却是两个不同的对象,`is`运算的结果自然是`False`了。 程序的执行结果已经用注释写在代码上了。够坑吧!看上去`a``b``c`的值都是一样的,但是`is`运算的结果却不一样。为什么会出现这样的结果,首先我们来说说Python程序中的代码块。所谓代码块是程序的一个最小的基本执行单位,一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫做一个代码块。上面的代码由两个代码块构成,`a = 257`是一个代码块,`main`函数是另外一个代码块。Python内部为了进一步提高性能,凡是在一个代码块中创建的整数对象,如果值不在`small_ints`缓存范围之内,但在同一个代码块中已经存在一个值与其相同的整数对象了,那么就直接引用该对象,否则创建一个新的对象出来,这条规则对不在`small_ints`范围的负数并不适用,对负数值浮点数也不适用,但对非负浮点数和字符串都是适用的,这一点读者可以自行证明。所以 `b is c`返回了`True`,而`a``b`不在同一个代码块中,虽然值都是257,但却是两个不同的对象,`is`运算的结果自然是`False`了。
为了验证刚刚的结论,我们可以借用`dis`模块(听名字就知道是进行反汇编的模块)从字节码的角度来看看这段代码。如果不理解什么是字节码,可以先看看[《谈谈 Python 程序的运行原理》]((http://www.cnblogs.com/restran/p/4903056.html))这篇文章。可以先用`import dis`导入`dis`模块并按照如下所示的方式修改代码。 为了验证刚刚的结论,我们可以借用`dis`模块(听名字就知道是进行反汇编的模块)从字节码的角度来看看这段代码。如果不理解什么是字节码,可以先看看[《谈谈 Python 程序的运行原理》]((http://www.cnblogs.com/restran/p/4903056.html))这篇文章。可以先用`import dis`导入`dis`模块并按照如下所示的方式修改代码。
```Python ```Python
if __name__ == "__main__": import dis
main()
dis.dis(main)
dis.dis(main)
``` ```
代码的执行结果如下图所示。可以看出代码第6行和第7行,也就是`main`函数中的257是从同一个位置加载的,因此是同一个对象;而代码第9行的`a`明显是从不同的地方加载的,因此引用的是不同的对象。 代码的执行结果如下图所示。可以看出代码第6行和第7行,也就是`main`函数中的257是从同一个位置加载的,因此是同一个对象;而代码第9行的`a`明显是从不同的地方加载的,因此引用的是不同的对象。
...@@ -82,20 +78,14 @@ if __name__ == "__main__": ...@@ -82,20 +78,14 @@ if __name__ == "__main__":
Python中有一种内置的数据类型叫列表,它是一种容器,可以用来承载其他的对象(准确的说是其他对象的引用),列表中的对象可以称为列表的元素,很明显我们可以把列表作为列表中的元素,这就是所谓的嵌套列表。嵌套列表可以模拟出现实中的表格、矩阵、2D游戏的地图(如植物大战僵尸的花园)、棋盘(如国际象棋、黑白棋)等。但是在使用嵌套的列表时要小心,否则很可能遭遇非常尴尬的情况,下面是一个小例子。 Python中有一种内置的数据类型叫列表,它是一种容器,可以用来承载其他的对象(准确的说是其他对象的引用),列表中的对象可以称为列表的元素,很明显我们可以把列表作为列表中的元素,这就是所谓的嵌套列表。嵌套列表可以模拟出现实中的表格、矩阵、2D游戏的地图(如植物大战僵尸的花园)、棋盘(如国际象棋、黑白棋)等。但是在使用嵌套的列表时要小心,否则很可能遭遇非常尴尬的情况,下面是一个小例子。
```Python ```Python
def main(): names = ['关羽', '张飞', '赵云', '马超', '黄忠']
names = ['关羽', '张飞', '赵云', '马超', '黄忠'] subjs = ['语文', '数学', '英语']
subjs = ['语文', '数学', '英语'] scores = [[0] * 3] * 5
scores = [[0] * 3] * 5 for row, name in enumerate(names):
for row, name in enumerate(names):
print('请输入%s的成绩' % name) print('请输入%s的成绩' % name)
for col, subj in enumerate(subjs): for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': ')) scores[row][col] = float(input(subj + ': '))
print(scores) print(scores)
if __name__ == '__main__':
main()
``` ```
我们希望录入5个学生3门课程的成绩,于是定义了一个有5个元素的列表,而列表中的每个元素又是一个由3个元素构成的列表,这样一个列表的列表刚好跟一个表格是一致的,相当于有5行3列,接下来我们通过嵌套的for-in循环输入每个学生3门课程的成绩。程序执行完成后我们发现,每个学生3门课程的成绩是一模一样的,而且就是最后录入的那个学生的成绩。 我们希望录入5个学生3门课程的成绩,于是定义了一个有5个元素的列表,而列表中的每个元素又是一个由3个元素构成的列表,这样一个列表的列表刚好跟一个表格是一致的,相当于有5行3列,接下来我们通过嵌套的for-in循环输入每个学生3门课程的成绩。程序执行完成后我们发现,每个学生3门课程的成绩是一模一样的,而且就是最后录入的那个学生的成绩。
...@@ -110,41 +100,29 @@ b = ['apple', 'pitaya', 'grape'] ...@@ -110,41 +100,29 @@ b = ['apple', 'pitaya', 'grape']
知道了这一点,我们可以回过头看看刚才的程序,我们对列表进行`[[0] * 3] * 5`操作时,仅仅是将`[0, 0, 0]`这个列表的地址进行了复制,并没有创建新的列表对象,所以容器中虽然有5个元素,但是这5个元素引用了同一个列表对象,这一点可以通过`id`函数检查`scores[0]`和`scores[1]`的地址得到证实。所以正确的代码应该按照如下的方式进行修改。 知道了这一点,我们可以回过头看看刚才的程序,我们对列表进行`[[0] * 3] * 5`操作时,仅仅是将`[0, 0, 0]`这个列表的地址进行了复制,并没有创建新的列表对象,所以容器中虽然有5个元素,但是这5个元素引用了同一个列表对象,这一点可以通过`id`函数检查`scores[0]`和`scores[1]`的地址得到证实。所以正确的代码应该按照如下的方式进行修改。
```Python ```Python
def main(): names = ['关羽', '张飞', '赵云', '马超', '黄忠']
names = ['关羽', '张飞', '赵云', '马超', '黄忠'] subjs = ['语文', '数学', '英语']
subjs = ['语文', '数学', '英语'] scores = [[]] * 5
scores = [[]] * 5 for row, name in enumerate(names):
for row, name in enumerate(names):
print('请输入%s的成绩' % name) print('请输入%s的成绩' % name)
scores[row] = [0] * 3 scores[row] = [0] * 3
for col, subj in enumerate(subjs): for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': ')) scores[row][col] = float(input(subj + ': '))
print(scores) print(scores)
if __name__ == '__main__':
main()
``` ```
或者 或者
```Python ```Python
def main(): names = ['关羽', '张飞', '赵云', '马超', '黄忠']
names = ['关羽', '张飞', '赵云', '马超', '黄忠'] subjs = ['语文', '数学', '英语']
subjs = ['语文', '数学', '英语'] scores = [[0] * 3 for _ in range(5)]
scores = [[0] * 3 for _ in range(5)] for row, name in enumerate(names):
for row, name in enumerate(names):
print('请输入%s的成绩' % name) print('请输入%s的成绩' % name)
scores[row] = [0] * 3 scores[row] = [0] * 3
for col, subj in enumerate(subjs): for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': ')) scores[row][col] = float(input(subj + ': '))
print(scores) print(scores)
if __name__ == '__main__':
main()
``` ```
如果对内存的使用不是很理解,可以看看[PythonTutor网站](http://www.pythontutor.com/)上提供的代码可视化执行功能,通过可视化执行,我们可以看到内存是如何分配的,从而避免在使用嵌套列表或者复制对象时可能遇到的坑。 如果对内存的使用不是很理解,可以看看[PythonTutor网站](http://www.pythontutor.com/)上提供的代码可视化执行功能,通过可视化执行,我们可以看到内存是如何分配的,从而避免在使用嵌套列表或者复制对象时可能遇到的坑。
...@@ -168,18 +146,9 @@ class Student(object): ...@@ -168,18 +146,9 @@ class Student(object):
return self.__name + ': ' + str(self.__age) return self.__name + ': ' + str(self.__age)
def main(): stu = Student('骆昊', 38)
stu = Student('骆昊', 38) print(stu._Student__name)
# 'Student' object has no attribute '__name' print(stu._Student__age)
# print(stu.__name)
# 用下面的方式照样可以访问类中的私有成员
print(stu._Student__name)
print(stu._Student__age)
if __name__ == '__main__':
main()
``` ```
Python为什么要做出这样的设定呢?用一句广为流传的格言来解释这个问题:“We are all consenting adults here”(我们都是成年人)。这句话表达了很多Python程序员的一个共同观点,那就是开放比封闭要好,我们应该自己对自己的行为负责而不是从语言层面来限制对数据或方法的访问。 Python为什么要做出这样的设定呢?用一句广为流传的格言来解释这个问题:“We are all consenting adults here”(我们都是成年人)。这句话表达了很多Python程序员的一个共同观点,那就是开放比封闭要好,我们应该自己对自己的行为负责而不是从语言层面来限制对数据或方法的访问。
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment