第052讲:像极客一样去思考

0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!

大家可能还不知道,在Python的社区里有句俗话:“Python自己带着电池(Batteries included)”,什么意思呢?要从Python的设计哲学说起,Python的设计哲学是:优雅、明确和简单。因此,Python开发者演变出来的哲学就是,用一种方法,最好是只有一种方法来做一件事。虽然我们常常努力大家多思考,条条大路通罗马,那是为了训练大家的发散式思维,但是在正式编程中,如果有完善、并且经过严密测试过的模块可以直接实现,那么我的建议是使用现成的模块来工作。

所以Python附带安装的有Python标准库,一般我们说的电池就是Python标准库中的模块,这些模块都极其有用,Python标准库中包含一般任务所需要的模块,不过呢,Python标准库包含的模块有100多个之多,一个个单独来讲那着实是不科学的,所以这一讲,我们将学习如何独立的来探索模块。

对于Python来说,学习资料其实一直都在身边(Python不仅带着电池,还带着充电器…),我们这里给大家分析,遇到问题,我们应该如何去找答案,其实90%的答案你都可以通过我们以下的方式来找到解决的方法。

首先要做的就是打开Python的文档,IDLE-Help-Python Docs(F1),如图:

在这里插入图片描述
看不懂怎么办,不会的话当然是学啊,说实话,对于一个程序员来说,还是需要一定的英语基础的,因为对于经济全球化的今天,最新最全的文档基本上都是鸟文的,所以你一点都不懂英语真的是很被动。不过大家也不要气馁,对于变成来说,只需要掌握基本的单词就行。

我们接着讲,那这个文档的基本部分包括哪些呢?

(1)What’s new in Python3.5?

介绍了相比Python2.0来说的新的变动。

(2)Tutorial

简易的Python教程,简单介绍了Python的语法。

(3)Liberary Reference

Python的整编书,这里详细列举了Python所有内置函数和标准库的各个模块的用法,非常详细,但是,你从头到尾是看不完的,当做字典来查就可以了。

(4)Inatalling Python Modules

教你如何安装Python的第三方模块

(5)Distuributing Python Modules

教你如何发布Python的第三方模块,你需要知道,Python除了标准库的几百个官方模块之外,还有一个叫做 pypi 的社区,网站为:https://pypi.python.org/pypi 搜集了全球Python爱好者贡献出来的模块,你自己也可以写一个模块发布到pypi社区,分享给全世界。

关于第三方模块,我将会在后面的笔记中为大家整理,

(6)language reference

讨论Python的语法和设计哲学

(7)Python setup and usage

谈论Python如何在不同平台上安装和使用

(8)Python HOWTOs

针对一些特定的主题进行深入并且详细的探讨

(9)Extending and Embedding

介绍如何用 C和 C++ 来开发Python的扩展模块,还有开发对应所需要的API

关于用 C和 C++ 为Python开发扩展,也会在后面的笔记中谈到。

(10)FAQs

常见问题解答

另外大家可能经常会看到的就是类似于这个 PEP 这个词语

在这里插入图片描述
PEP是Python Enhancement Proposals 的缩写,翻译过来就是Python增强建议书的意思。它是用来规范与定义Python的各种加强和延伸功能的技术规格,好让Python开发社区能有共同遵循的依据。

每一个PEP都有一个唯一的编号,这个编号一旦给定就不会再改变。例如,PEP 3000 就是用来定义 Python 3.0 的相关技术规格;而PEP 333 则是 Python 的 Web 应用程序界面 WSGI (Web Server Gateway Interface 1.0)的规范。关于PEP 本身的相关规范定义在 PEP 1,而PEP 8 则定义了 Python 代码的风格指南。

有关 PEP 的列表大家可以参考 PEP 0 :https://www.python.org/dev/peps/

接下来就来举个实例,说说我遇到问题是怎么自救的,前阵子,我们不是举了一个计时器的例子吗,后来在第44课的课后作业的最后面,我们说,现实编程中,计时器工具千万不要自己动手写,因为有很多未知的因素会影响到你的数据,所以我们建议使用现成的模块,这个模块叫做 timeit,来对你的代码来进行计时。假设我们现在不知道 timeit 模块的用法,我应该如何入手呢?

那我们就开始来翻刚才这个文档了,我们可以使用它的搜索、索引功能,一般给出的第一个都是你需要的

在这里插入图片描述

如果你认为快速学习一个模块都要读这么长一篇长篇大论,那你真是 too young too simple
了,快速掌握一个模块的用法,事实上可以使用IDLE 交互界面,首先 import 该模块,然后可以调用 __doc__属性,这样就可以查看到这个模块的简介,如图:

在这里插入图片描述
事实上你对于这个方法应该很熟悉了,这跟我们之间讲过的函数文档是一样的,就是写在模块最开头的那个字符串,这个字符串是带格式的,我们可以使用 print() 把这个格式打印出来。会更好看一点:

在这里插入图片描述

然后你可能需要知道这个模块里面定义了哪些变量,哪些函数,哪些类,你可以用 dir() 内置方法把它显示出来:

>>> dir(timeit)
['Timer', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_globals', 'default_number', 'default_repeat', 'default_timer', 'dummy_src_name', 'gc', 'itertools', 'main', 'reindent', 'repeat', 'sys', 'template', 'time', 'timeit']

它返回给我们的依然是一个列表,但是相比上面的来说,只有其中的4个成员,如果你有看前面的关于 timeit 的文档的话,你会发现,Timer是一个类,timeit、repeat、default_timer 是3个接口函数。所以,我们这个 all 属性显示出来的就是这个模块可以供外界调用的所有东西。

这里有两点需要注意的,首先,不是所有的模块都有 all 属性,有 all
的话,这个属性里面包含的内容就是作者希望外部调用的名字,其它的就是不希望外部调用的了。其次,第二点就是,如果一个模块设置了 all
属性,那么使用 from ‘模块名’ import * 语句导入到命名空间的操作,只有 all 属性这里面的名字才能被导入。例如:

>>> from timeit import *
>>> Timer
<class 'timeit.Timer'>
>>> gc
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    gc
NameError: name 'gc' is not defined

找 Timer 就可以找到,但是找 gc 就找不到。

但是如果你没有设置这个 all 属性的话,from ‘模块名’ import * 就会把所有不以下划线开头的名字都导入到当前命名空间,所以,我们建议,你再编写模块的时候,对外提供接口函数和类都设置到 all 属性的列表中去,这样子是比较规范的做法。

还有一个属性叫做 file 属性,这个属性是指明了该模块的源代码所在的位置


>>> import timeit
>>> timeit.__file__
'D:\\ProgramFiles\\Anaconda3\\lib\\timeit.py'

我们说过,快速提高编程能力有三大法宝,一个就是不断地编写代码,第二个就是阅读高手的代码。
这里提供了源代码的路径,我们就可以去找到它,并通过阅读它的源代码,吸取它的精华。 最后我们还可以使用 help() 函数
在这里插入图片描述

在本节课的最后,我需要提一点的就是,timeit 这个模块真的是太有用了,所以呢,我这里有对应的文档的中文详解 -> timeit 模块详解。大家有空的话,建议通读一下。

测试题(笔试,不能上机哦~)

  • 总共 16 道题,不上机的情况下答中 14 道以下请自觉忏悔!
  • 注:题目虽然简单,但有陷阱,反正这一讲也没什么要测试的,就考考大家常识_

0. 请问以下代码会打印什么内容?

>>> def func():
    pass

>>> print(type(func()))

A. <type ‘function’>
B. <type ‘tuple’>
C. <type ‘NoneType’>
D. <type ‘type’>

答:C

1. 请问以下代码会打印什么内容?

>>> print(type(1J))

A. <type ‘unicode’>
B. <type ‘int’>
C. <type ‘str’>
D. <type ‘complex’>

答:D

2. 请问以下代码会打印什么内容?

>>> print(type(lambda:None))

A. <type ‘NoneType’>
B. <type ‘function’>
C. <type ‘int’>
D. <type ‘tuple’>

答:B

3. 请问以下代码会打印什么内容?

>>> a = [1, 2, 3, "FishC", ('a', 'b', 'c'), [], None]
>>> print(len(a))

A. 13
B. 7
C. 6
D. 5

答:B

4. 请问以下代码会打印什么内容?

class A:
def __init__(self, x):
    x = x + 1
        self.v1 = x
 
class B(A):
    def __init__(self, x):
        x = x + 1
        self.v2 = x
 
>>> b = B(8)
>>> print("%d %d" % b.v1, b.v2)

A. 9 10
B. 9 9
C. 10 10
D. 抛出异常
答:D, B的构造方法会覆盖A的构造方法,v1属性未定义

5. 请问以下代码会打印什么内容?

class A:
    def __init__(self, x):
        self.x = x
        x = 666
 
>>> a = A()
>>> a = A(888)
>>> a.x

A. 666
B. 888
C. None
D. 抛出异常

答:B,不解释了,搞清楚形参和对象属性之间的关系

6. 请问以下代码会打印什么内容?

values = [1, 1, 2, 3, 5]
nums = set(values)
 
def checkit(num):
    if num in nums:
        return True
    else:
        return False
 
for i in filter(checkit, values):
print(i, end=' ')

A. 1 2 3 5
B. 1 1 2 3 5
C. 1 2 3 4 3 2 1
D. 抛出异常

答:B,nums=[1,2,3,5]
filter是过滤器,遍历values,满足checkit的元素留下,可以发现values过滤后和原values相同,结果也相当于打印values

7. 请问以下代码会打印什么内容?

values = [1, 1, 2, 3, 5]
def transform(num):
    return num ** 2
 
for i in map(transform, values):
    print(i, end=' ')

A. 1 1 4 9 25
B. 1 1 2 3 5
C. 0.5 0.5 1 1.5 2.5
D. 2 2 4 6 10

答:A

利用map()函数,可以把一个 list 转换为另一个 list,只需要传入转换函数。

8. 请问以下代码会打印什么内容?

class A:
    def __init__(self, x):
        self.x = x
 
a = A(100)
a.__dict__['y'] = 50
print(a.y + len(a.__dict__))

A. 2
B. 50
C. 51
D. 52

答:D

a.__dict__是a对象的属性列表

  1. 请问以下代码会打印什么内容?
class A:
    def __init__(self):
        pass
    def get(self):
        print(__name__)
 
>>> a = A()
>>> a.get()

A. A
B. a
C. main
D. _A__a

答:C
当前运行的程序__name__的值为__main__

10. 请问以下代码会打印什么内容?

country_counter = {}
 
def addone(country):
    if country in country_counter:
        country_counter[country] += 1
    else:
        country_counter[country] = 1
 
addone('China')
addone('Japan')
addone('China')
addone("American")
 
print(len(country_counter))

A. 0
B. 1
C. 2
D. 3

答:D

11.请问以下代码会打印什么内容?

dict1 = {}
dict1[1] = 1
dict1['1'] = 2
dict1[1.0] = 3
 
result = 0
for each in dict1:
    result += dict1[each]
 
print(result)

A. 2
B. 3
C. 5
D. 6

答:C
1和1.0相同,dict1[1.0] = 3把键为1的值修改为3
整个字典为{1:3,2:2}

12. 请问以下代码会打印什么内容?

def dostuff(param1, *param2):
    print type(param2)
 
dostuff('apples', 'bananas', 'cherry', 'dates')

A. <type ‘int’>
B. <type ‘str’>
C. <type ‘tuple’>
D. <type ‘dict’>

答:C
居然是C. <type ‘tuple’>

13. 请问以下代码会打印什么内容?

class A:
    def __init__(self, a, b, c):
        self.x = a + b + c
 
a = A(1,2,3)
b = getattr(a, 'x')
setattr(a, 'x', b+1)
print a.x

A. 1
B. 2
C. 6
D. 7

答:D
setattr和getattr是系统自带函数,用于给去对象的属性值和设置对象的属性值

14. 请问以下代码会打印什么内容?

list1 = [1, 2]
list2 = [3, 4]
 
dict1 = {'1':list1, '2':list2}
dict2 = dict1.copy()
 
dict1['1'][0] = 5
 
result = dict1['1'][0] + dict2['1'][0]
print(result)

A. 5
B. 6
C. 8
D. 10

答:D

dict2 的父对象(既: 前面的序列)进行了深拷贝,不会随dict1 修改而修改,子对象是浅拷贝所以随 dict1的修改而修改。

15. 请问以下代码会打印什么内容?

import copy
 
list1 = [1, 2]
list2 = [3, 4]
 
dict1 = {'1':list1, '2':list2}
dict2 = copy.deepcopy(dict1)
 
dict1['1'][0] = 5
 
result = dict1['1'][0] + dict2['1'][0]
print(result)

A. 5
B. 6
C. 8
D. 10

答:B

深拷贝,相当于复制出一个相同的对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值