岁月如歌


  • 首页

  • 归档

  • 分类

  • 标签

  • Android

  • Python

  • Notes

  • Links

  • 关于

  • 搜索
close
Python资源汇总

基础知识

Python学习笔记

Python Docs

  • Python 3.5.0 documentation
  • Python标准库中文版.pdf

实用代码

简易Web服务

终端输入:python -m http.server 8000
浏览器打开localhost:8000即可当FTP使用

获取脚本所在的目录

1
2
3
4
5
6
7
8
9
# 确切地说,__file__是模块所在的文件
# 如果该模块从其他文件中导入,则显示其他文件的目录
print(__file__) # F:\hexo\test.py
print(os.path.dirname(__file__)) # F:\hexo

# 始终显示主执行文件的目录
print(sys.path[0]) # F:\hexo\test.py
print(os.path.dirname(sys.path[0])) # F:\hexo
print(sys.argv[0]) # F:\hexo

拖曳文件到Python脚本图标上,获取文件名

1
2
3
4
5
6
if __name__ == '__main__':
# sys.argv[0]为脚本本身,sys.argv[1:]为其他文件
if len(sys.argv) == 1:
print("请将文件拖曳到本脚本!")
sys.exit(0)
files = sys.argv[1:]

解析csv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import csv  # 标准库

# 由于csv库有自己的换行符,需要把open方法的newline设置为空,否则在Excel中会出现数据隔行。

# 写入
with open(filename, 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerow(row)

# 读取
with open(filename, 'r', encoding='utf-8', newline='') as f:
reader = csv.reader(f)
for _ in reader:
print(_)

# 不使用csv标准库,自己解析
with open('t.csv', 'r') as f:
rows = [line.strip().split(',') for line in f.readlines()]

如果文件已存在,则删除

1
2
if os.path.exists(save_file):
os.remove(save_file)

打开文件

1
2
import subprocess # 自带模块
subprocess.call(fileName, shell=True) # 打开文件

性能分析使用cProfile模块

命令行输入:

1
python -m cProfile your.py

一维数组变二维

1
2
3
4
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
g = iter(a)
res = [[next(g) for _ in range(n)] for _ in range(n)]
# [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24]]

二维矩阵转置

1
2
3
4
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[row[col] for row in a] for col in range(len(a[0]))] # 方法一
list(map(list,zip(*a))) # 方法二
# 结果都是:[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

使用zip合并相邻的列表项

1
2
3
4
5
6
7
a = [1, 2, 3, 4, 5, 6]
list(zip(*([iter(a)] * 2))) # [(1, 2), (3, 4), (5, 6)]
list(zip(a[::2], a[1::2])) # [(1, 2), (3, 4), (5, 6)]
list(zip(a[::3], a[1::3], a[2::3])) # [(1, 2, 3), (4, 5, 6)]
# 通用公式
f1 = lambda a, k: zip(*([iter(a)] * k))
f2 = lambda a, k: zip(*(a[i::k] for i in range(k)))

使用zip反转字典

1
2
m = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
list(zip(m.values(), m.keys())) # [(4, 'd'), (1, 'a'), (3, 'c'), (2, 'b')]

random.sample(list, n)通常用来产生不重复的n位数字

1
2
print int(''.join(map(str, random.sample(range(10), 10))))
#3571490628

enumerate会将数组或列表组成一个索引序列

1
2
for index,text in enumerate(list)):
print index ,text

判断一个数是不是素数

1
lambda x:not[x%i for i in range(2,x/2+1) if x%i == 0]

多序列同时迭代

注:Iterator指惰性序列,list、turple等是Iteratable,但不是Iterator

1
2
3
4
5
6
7
8
9
10
11
a = [1, 2, 3, 4]
b = ['a', 'b', 'c']

### 以下都是Iterator,可作用于二个或以上序列
zip(a, b) # (1,'a'), (2, 'b'), (3, 'c')

from itertools import zip_longest
zip_longest(a, b) # (1, 'a'), (2, 'b'), (3, 'c'), (4, None)

from itertools import chain
chain(a, b) # [1, 2, 3, 4, 'a', 'b', 'c']

嵌套序列变平

1
2
3
4
5
6
7
8
9
10
11
12
from collections import Iterable

def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x)
else:
yield x

items = [1, 2, [3, 4, [5, 6], 7], 8]
for x in flatten(items):
print(x)

迭代多个有序排列数组(多路归并排序)

1
2
3
4
5
import heapq
from collections import Iterator
a = [1, 4, 7, 10]
b = [2, 5, 6, 11]
heapq.merge(a, b) # 1, 2, 4, 5, 6, 7, 10, 11

一行筛质数

1
filter(lambda x: all(map(lambda p: x % p != 0, range(2, x))), range(2, n))

对 array 按照第二列降序排序并取前 10 个

1
sorted(array, key=lambda x: x[1], reverse=True)[:10]

对两个字符串(这里假设等长)做异或操作

1
"".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])

转置矩阵

1
2
m = [[1,2],[3,4]]
zip(*m) # *是把list中的项当成可选参数传进去

链式比较:

1
2
3
a = 3
b = 1
1 <= b <= a < 10 #True

真值测试

1
2
3
4
5
6
name = 'Tim'
langs = ['AS3', 'Lua', 'C']
info = {'name': 'Tim', 'sex': 'Male', 'age':23 }

if name and langs and info:
print('All True!') #All True!

字典默认值

1
2
3
4
dic = {'name':'Tim', 'age':23}

dic['workage'] = dic.get('workage',0) + 1
#dic = {'age': 23, 'workage': 1, 'name': 'Tim'}

技术博客

  • gaga salamer
  • 创e 一个运维工程师的python自动化运维实践。
  • cwyalpha的博客 Python爬虫学习记录系列
  • xlzd
  • 小信’Blog
  • 离别歌:乌云核心白帽子、混迹于各大社区的伪装程序猿,喜欢各种代码与审计、linux运维与内网、python web开发。

练习资源

  • 黑板客爬虫闯关
  • 能利用爬虫技术做到哪些很酷很有趣很有用的事情
  • 你是如何开始能写python爬虫?
  • Python 有哪些一千行左右的经典练手项目?
  • 有哪些网站用爬虫爬取能得到很有价值的数据?

学习资料

  • Python快速教程
  • Python爬虫学习系列教程
  • Python正则表达式指南
  • pythoner.cn视频课程 截至2015年9月30号,上面发布了7个相关视频教程, 内容覆盖了面向对象知识体系, Flask入门, Django入门, 多线程开发, 文件处理,网络爬虫,图形开发的内容。
  • Python项目构建实践 Python项目构建最佳实践。 用Python开发项目的童鞋可以看看别人的实践, 有一些指导意义。
  • Flask 教程
  • Flask开发文档
  • Flask大型教程 本系列是作者平时使用 Flask 微框架编写应用的经验之谈
  • Tornado入门教程
  • Python中文学习大本营
  • 《编写高质量代码 改善Python程序的91个建议.pdf》
  • 聊聊python面试这件事儿
  • Python开发入门与实战 Django教程
  • Python 3 CookBook

常用库

  • Python Package Index 检索各种Python库
  • Python Extension Package For Windows:编译好的Python库

可以直接根据下面的名字用pip命令安装 eg:

pip install BeautifulSoup4

批量安装第三方库:

pip install -r requirements.txt --allow-all-external

其中,requirments.txt的内容为:

Flask==0.9
Jinja2==2.7.2
Werkzeug==0.8.3
gunicorn==0.17.2
  • BeautifulSoup4:从HTML或XML文件中提取数据
  • lxml:HTML/XML的解析器,可与BeautifulSoup配套使用。如果安装出错请看这里:Python 3 安装 lxml
  • pyquery:使用jquery语法解析HTML,需要先安装lxml。用法:python数据抓取之pyquery包
  • requests:比python自带的urllib更人性化
  • xlrd,xlwt:分别用于读、写Excel
  • selenium:用于Web应用程序测试
  • ipython,pyreadline:ipython能够逐行显示python代码的运行结果,能够更好的调试python代码,并且有tab自动补全功能。后者是配色
  • html2text:从HTML中提取易于阅读的文本
  • pandas:数据分析。CookBook
  • jieba:中文分词
  • pypinyin:将汉语转为拼音。可以用于汉字注音、排序、检索。
  • sh:可以用 Python 函数的语法去调用 shell 命令
  • Watchdog:监视文件系统改动
  • Path:简化文件系统相关操作
  • Sphinx:爱上写文档
  • flask:Web框架
  • WeRoBot:微信机器人框架
  • tqdm:在长循环中添加一个进度提示信息,用户只需要封装任意的迭代器 tqdm(iterator)。

pip 常用命令

pip --help                        # 帮助文档
pip install SomePackage           # 安装最新版本
pip install SomePackage==1.0.4    # 安装指定版本
pip install 'SomePackage>=1.0.4'  # 限制最低版本
pip uninstall SomePackage         # 卸载
pip list                          # 查看已安装
pip list --outdated               # 查看可升级
pip install --upgrade SomePackage # 升级
pip show --files SomePackage      # 相关文件及路径等信息
pip freeze > F:\requirements.txt  # 导出所有第三方库到文件
pip install -r requirements.txt   # 根据文件安装对应的软件包
# 下面是批量升级所有可更新的第三方库,需要在git bash中运行
pip list --outdated | grep '^[a-z]* (' | cut -d " " -f 1 | xargs pip install -U

IDE与编辑器

  • PyCharm
  • Sublime Text 3 插件:
    代码自动完成Anaconda 。安装后代码会因PEP 8格式检查而出现白框,在Sublime > Preferences > Package Settings > Anaconda > Settings User 中添加如下代码即可解决:{"anaconda_linting": false}。

《SublimeText3 运行Python控制台不能输出中文的解决方法》


论坛与网站

  • Python爱好者
  • PythonTip Python主题网站

经验教训

os 库

  • os.path.isdir()方法应该传入带绝对路径的文件名,如:r'e:\java',如果只是传入文件名,如'java',该方法只会在当前工作目录(可以用os.getcwd()查看)下查找有没有同名文件夹,有则返回true
  • os.listdir()方法只返回文件名,需要自己用os.path.join()方法拼接出绝对路径。
  • os.path.realpath()获取绝对路径,该方法会将传入的文件名与当前工作目录拼接出绝对路径。如果要使用这个方法,必须先用os.chdir()改变当前工作目录!建议优先用os.path.join()。
  • os.path.relpath()获取相对路径,如果不传入命名关键字参数start,如start = r'C:\python',则该方法会与根据当前工作目录计算相对路径,目录不同则报错。

面试宝典

网上搜集的面试题

到底什么是Python?

为什么提这个问题:如果你应聘的是一个Python开发岗位,你就应该知道这是门什么样的语言,以及它为什么这么酷。以及它哪里不好。

关键点:

  • Python是一种解释型语言。这就是说,与C语言和C的衍生语言不同,Python代码在运行之前不需要编译。其他解释型语言还包括PHP和Ruby。
  • Python是动态类型语言,指的是你在声明变量时,不需要说明变量的类型。你可以直接编写类似x=111和x=”I’m a string”这样的代码,程序不会报错。
  • Python非常适合面向对象的编程(OOP),因为它支持通过组合(composition)与继承(inheritance)的方式定义类(class)。Python中没有访问说明符(access
    specifier,类似C++中的public和private),这么设计的依据是“大家都是成年人了”。
  • 在Python语言中,函数是第一类对象(first-class objects)。这指的是它们可以被指定给变量,函数既能返回函数类型,也可以接受函数作为输入。类(class)也是第一类对象。
  • Python代码编写快,但是运行速度比编译语言通常要慢。好在Python允许加入基于C语言编写的扩展,因此我们能够优化代码,消除瓶颈,这点通常是可以实现的。numpy就是一个很好地例子,它的运行速度真的非常快,因为很多算术运算其实并不是通过Python实现的。
  • Python用途非常广泛——网络应用,自动化,科学建模,大数据应用,等等。它也常被用作“胶水语言”,帮助其他语言和组件改善运行状况。
  • Python让困难的事情变得容易,因此程序员可以专注于算法和数据结构的设计,而不用处理底层的细节。

补充缺失的代码

为什么提这个问题?

  • 说明面试者对与操作系统交互的基础知识
  • 递归真是太好用啦
def print_directory_contents(sPath):
    """
    这个函数接受文件夹的名称作为输入参数,
    返回该文件夹中文件的路径,
    以及其包含文件夹中文件的路径。

    """
    # 补充代码

答案:

def print_directory_contents(sPath):
    import os
    for sChild in os.listdir(sPath):
        sChildPath = os.path.join(sPath,sChild)
        if os.path.isdir(sChildPath):
            print_directory_contents(sChildPath)
        else:
            print sChildPath

特别要注意以下几点:

  • 命名规范要统一。如果样本代码中能够看出命名规范,遵循其已有的规范。
  • 递归函数需要递归并终止。确保你明白其中的原理,否则你将面临无休无止的调用栈(callstack)。
  • 我们使用os模块与操作系统进行交互,同时做到交互方式是可以跨平台的。你可以把代码写成sChildPath = sPath + '/' + sChild,但是这个在Windows系统上会出错。
  • 熟悉基础模块是非常有价值的,但是别想破脑袋都背下来,记住Google是你工作中的良师益友。
  • 如果你不明白代码的预期功能,就大胆提问。
  • 坚持KISS原则!保持简单,不过脑子就能懂!

阅读下面的代码,写出A0,A1至An的最终值

为什么提这个问题?

  • 列表解析(list comprehension)十分节约时间,对很多人来说也是一个大的学习障碍。
  • 如果你读懂了这些代码,就很可能可以写下正确地值。
  • 其中部分代码故意写的怪怪的。因为你共事的人之中也会有怪人。
A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
A1 = range(10)
A2 = [i for i in A1 if i in A0]
A3 = [A0[s] for s in A0]
A4 = [i for i in A1 if i in A3]
A5 = {i:i*i for i in A1}
A6 = [[i,i*i] for i in A1]

答案:

A0 = {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4} # 顺序不固定
A1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A2 = []
A3 = [1, 3, 2, 5, 4]
A4 = [1, 2, 3, 4, 5]
A5 = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]

Python的多线程是个好主意吗?

为什么提这个问题?

因为GIL就是个混账东西(A-hole)。很多人花费大量的时间,试图寻找自己多线程代码中的瓶颈,直到他们明白GIL的存在。

答案:

Python并不支持真正意义上的多线程。Python中提供了多线程包,但是如果你想通过多线程提高代码的速度,使用多线程包并不是个好主意。Python中有一个被称为Global Interpreter Lock(GIL)的东西,它会确保任何时候你的多个线程中,只有一个被执行。线程的执行速度非常之快,会让你误以为线程是并行执行的,但是实际上都是轮流执行。经过GIL这一道关卡处理,会增加执行的开销。这意味着,如果你想提高代码的运行速度,使用threading包并不是一个很好的方法。

不过还是有很多理由促使我们使用threading包的。如果你想同时执行一些任务,而且不考虑效率问题,那么使用这个包是完全没问题的,而且也很方便。但是大部分情况下,并不是这么一回事,你会希望把多线程的部分外包给操作系统完成(通过开启多个进程),或者是某些调用你的Python代码的外部程序(例如Spark或Hadoop),又或者是你的Python代码调用的其他代码(例如,你可以在Python中调用C函数,用于处理开销较大的多线程工作)。

你如何管理不同版本的代码?

为什么提这个问题?

因为没有版本控制的代码,就像没有杯子的咖啡。有时候我们需要写一些一次性的、可以随手扔掉的脚本,这种情况下不作版本控制没关系。但是如果你面对的是大量的代码,使用版本控制系统是有利的。版本控制能够帮你追踪谁对代码库做了什么操作;发现新引入了什么bug;管理你的软件的不同版本和发行版;在团队成员中分享源代码;部署及其他自动化处理。它能让你回滚到出现问题之前的版本,单凭这点就特别棒了。还有其他的好功能。怎么一个棒字了得!

答案:

版本管理!被问到这个问题的时候,你应该要表现得很兴奋,甚至告诉他们你是如何使用Git(或是其他你最喜欢的工具)追踪自己和奶奶的书信往来。我偏向于使用Git作为版本控制系统(VCS),但还有其他的选择,比如subversion(SVN)。

下面代码会输出什么?

def f(x,L=[]):
    for i in range(x):
        L.append(i*i)
    print L

f(2)
f(3,[3,2,1])
f(3)

答案

[0, 1]
[3, 2, 1, 0, 1, 4]
[0, 1, 0, 1, 4]

第三个函数使用了之前内存地址中存储的旧列表。

猴子补丁(monkey patching)是什么?这种做法好吗?

为什么提这个问题?

答对这个问题说明你对单元测试的方法有一定了解。你如果提到要避免“猴子补丁”,可以说明你不是那种喜欢花里胡哨代码的程序员(公司里就有这种人,跟他们共事真是糟糕透了),而是更注重可维护性。还记得KISS原则码?答对这个问题还说明你明白一些Python底层运作的方式,函数实际是如何存储、调用等等。

另外:如果你没读过mock模块的话,真的值得花时间读一读。这个模块非常有用。

答案:

“猴子补丁”就是指,在函数或对象已经定义之后,再去改变它们的行为。

举个例子:

import datetime
datetime.datetime.now = lambda: datetime.datetime(2012, 12, 12)

大部分情况下,这是种很不好的做法 - 因为函数在代码库中的行为最好是都保持一致。打“猴子补丁”的原因可能是为了测试。mock包对实现这个目的很有帮助。

解释*args,**kwargs的含义与用途

为什么提这个问题?

有时候,我们需要往函数中传入未知个数的参数或关键词参数。有时候,我们也希望把参数或关键词参数储存起来,以备以后使用。有时候,仅仅是为了节省时间。

答案

如果我们不确定要往函数中传入多少个参数,或者我们想往函数中以列表和元组的形式传参数时,那就使要用*args;如果我们不知道要往函数中传入多少个关键词参数,或者想传入字典的值作为关键词参数时,那就要使用**kwargs。args和kwargs这两个标识符是约定俗成的用法,你当然还可以用*bob和**billy,但是这样就并不太妥。

下面是具体的示例:

def f(*args,**kwargs): print args, kwargs

l = [1,2,3]
t = (4,5,6)
d = {'a':7,'b':8,'c':9}

f()
f(1,2,3)                    # (1, 2, 3) {}
f(1,2,3,"groovy")           # (1, 2, 3, 'groovy') {}
f(a=1,b=2,c=3)              # () {'a': 1, 'c': 3, 'b': 2}
f(a=1,b=2,c=3,zzz="hi")     # () {'a': 1, 'c': 3, 'b': 2, 'zzz': 'hi'}
f(1,2,3,a=1,b=2,c=3)        # (1, 2, 3) {'a': 1, 'c': 3, 'b': 2}

f(*l,**d)                   # (1, 2, 3) {'a': 7, 'c': 9, 'b': 8}
f(*t,**d)                   # (4, 5, 6) {'a': 7, 'c': 9, 'b': 8}
f(1,2,*t)                   # (1, 2, 4, 5, 6) {}
f(q="winning",**d)          # () {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
f(1,2,*t,q="winning",**d)   # (1, 2, 4, 5, 6) {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}

def f2(arg1,arg2,*args,**kwargs): print arg1,arg2, args, kwargs

f2(1,2,3)                       # 1 2 (3,) {}
f2(1,2,3,"groovy")              # 1 2 (3, 'groovy') {}
f2(arg1=1,arg2=2,c=3)           # 1 2 () {'c': 3}
f2(arg1=1,arg2=2,c=3,zzz="hi")  # 1 2 () {'c': 3, 'zzz': 'hi'}
f2(1,2,3,a=1,b=2,c=3)           # 1 2 (3,) {'a': 1, 'c': 3, 'b': 2}

f2(*l,**d)                   # 1 2 (3,) {'a': 7, 'c': 9, 'b': 8}
f2(*t,**d)                   # 4 5 (6,) {'a': 7, 'c': 9, 'b': 8}
f2(1,2,*t)                   # 1 2 (4, 5, 6) {}
f2(1,1,q="winning",**d)      # 1 1 () {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}
f2(1,2,*t,q="winning",**d)   # 1 2 (4, 5, 6) {'a': 7, 'q': 'winning', 'c': 9, 'b': 8}

介绍@classmethod, @staticmethod, @property

回答背景知识

这些都是装饰器(decorator)。装饰器是一种特殊的函数,要么接受函数作为输入参数,并返回一个函数,要么接受一个类作为输入参数,并返回一个类。@标记是语法糖(syntactic sugar),可以让你以简单易读得方式装饰目标对象。

@my_decorator
def my_func(stuff):
    do_things
Is equivalent to

def my_func(stuff):
    do_things

my_func = my_decorator(my_func)

真正的答案

@classmethod, @staticmethod和@property这三个装饰器的使用对象是在类中定义的函数。下面的例子展示了它们的用法和行为:

class MyClass(object):
    def __init__(self):
        self._some_property = "properties are nice"
        self._some_other_property = "VERY nice"
    def normal_method(*args,**kwargs):
        print "calling normal_method({0},{1})".format(args,kwargs)
    @classmethod
    def class_method(*args,**kwargs):
        print "calling class_method({0},{1})".format(args,kwargs)
    @staticmethod
    def static_method(*args,**kwargs):
        print "calling static_method({0},{1})".format(args,kwargs)
    @property
    def some_property(self,*args,**kwargs):
        print "calling some_property getter({0},{1},{2})".format(self,args,kwargs)
        return self._some_property
    @some_property.setter
    def some_property(self,*args,**kwargs):
        print "calling some_property setter({0},{1},{2})".format(self,args,kwargs)
        self._some_property = args[0]
    @property
    def some_other_property(self,*args,**kwargs):
        print "calling some_other_property getter({0},{1},{2})".format(self,args,kwargs)
        return self._some_other_property

o = MyClass()
# 未装饰的方法还是正常的行为方式,需要当前的类实例(self)作为第一个参数。

o.normal_method
# <bound method MyClass.normal_method of <__main__.MyClass instance at 0x7fdd2537ea28>>

o.normal_method()
# normal_method((<__main__.MyClass instance at 0x7fdd2537ea28>,),{})

o.normal_method(1,2,x=3,y=4)
# normal_method((<__main__.MyClass instance at 0x7fdd2537ea28>, 1, 2),{'y': 4, 'x': 3})

# 类方法的第一个参数永远是该类

o.class_method
# <bound method classobj.class_method of <class __main__.MyClass at 0x7fdd2536a390>>

o.class_method()
# class_method((<class __main__.MyClass at 0x7fdd2536a390>,),{})

o.class_method(1,2,x=3,y=4)
# class_method((<class __main__.MyClass at 0x7fdd2536a390>, 1, 2),{'y': 4, 'x': 3})

# 静态方法(static method)中除了你调用时传入的参数以外,没有其他的参数。

o.static_method
# <function static_method at 0x7fdd25375848>

o.static_method()
# static_method((),{})

o.static_method(1,2,x=3,y=4)
# static_method((1, 2),{'y': 4, 'x': 3})

# @property是实现getter和setter方法的一种方式。直接调用它们是错误的。
# “只读”属性可以通过只定义getter方法,不定义setter方法实现。

o.some_property
# 调用some_property的getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# 'properties are nice'
# “属性”是很好的功能

o.some_property()
# calling some_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: 'str' object is not callable

o.some_other_property
# calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# 'VERY nice'

# o.some_other_property()
# calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: 'str' object is not callable

o.some_property = "groovy"
# calling some_property setter(<__main__.MyClass object at 0x7fb2b7077890>,('groovy',),{})

o.some_property
# calling some_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
# 'groovy'

o.some_other_property = "very groovy"
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# AttributeError: can't set attribute

o.some_other_property
# calling some_other_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})

说明下列代码的输出结果

class D(B,C):
    def go(self):
        super(D, self).go()
        print "go D go!"
    def stop(self):
        super(D, self).stop()
        print "stop D stop!"
    def pause(self):
        print "wait D wait!"

class E(B,C): pass

a = A()
b = B()
c = C()
d = D()
e = E()

# 说明下列代码的输出结果

a.go()
b.go()
c.go()
d.go()
e.go()

a.stop()

为什么提这个问题?

因为面向对象的编程真的真的很重要。不骗你。答对这道问题说明你理解了继承和Python中super函数的用法。

答案

a.go()
# go A go!

b.go()
# go A go!
# go B go!

c.go()
# go A go!
# go C go!

d.go()
# go A go!
# go C go!
# go B go!
# go D go!

e.go()
# go A go!
# go C go!
# go B go!

a.stop()
# stop A stop!

b.stop()
# stop A stop!

c.stop()
# stop A stop!
# stop C stop!

d.stop()
# stop A stop!
# stop C stop!
# stop D stop!

e.stop()
# stop A stop!

a.pause()
# ... Exception: Not Implemented

b.pause()
# ... Exception: Not Implemented

c.pause()
# ... Exception: Not Implemented

d.pause()
# wait D wait!

e.pause()
# ...Exception: Not Implemented

说明下面代码的输出结果

class Node(object):
    def __init__(self,sName):
        self._lChildren = []
        self.sName = sName
    def __repr__(self):
        return "<Node '{}'>".format(self.sName)
    def append(self,*args,**kwargs):
        self._lChildren.append(*args,**kwargs)
    def print_all_1(self):
        print self
        for oChild in self._lChildren:
            oChild.print_all_1()
    def print_all_2(self):
        def gen(o):
            lAll = [o,]
            while lAll:
                oNext = lAll.pop(0)
                lAll.extend(oNext._lChildren)
                yield oNext
        for oNode in gen(self):
            print oNode

oRoot = Node("root")
oChild1 = Node("child1")
oChild2 = Node("child2")
oChild3 = Node("child3")
oChild4 = Node("child4")
oChild5 = Node("child5")
oChild6 = Node("child6")
oChild7 = Node("child7")
oChild8 = Node("child8")
oChild9 = Node("child9")
oChild10 = Node("child10")

oRoot.append(oChild1)
oRoot.append(oChild2)
oRoot.append(oChild3)
oChild1.append(oChild4)
oChild1.append(oChild5)
oChild2.append(oChild6)
oChild4.append(oChild7)
oChild3.append(oChild8)
oChild3.append(oChild9)
oChild6.append(oChild10)

# 说明下面代码的输出结果

oRoot.print_all_1()
oRoot.print_all_2()

为什么提这个问题?

因为对象的精髓就在于组合(composition)与对象构造(object construction)。对象需要有组合成分构成,而且得以某种方式初始化。这里也涉及到递归和生成器(generator)的使用。

生成器是很棒的数据类型。你可以只通过构造一个很长的列表,然后打印列表的内容,就可以取得与print_all_2类似的功能。生成器还有一个好处,就是不用占据很多内存。

有一点还值得指出,就是print_all_1会以深度优先(depth-first)的方式遍历树(tree),而print_all_2则是宽度优先(width-first)。有时候,一种遍历方式比另一种更合适。但这要看你的应用的具体情况。

答案

oRoot.print_all_1()会打印下面的结果:

<Node 'root'>
<Node 'child1'>
<Node 'child4'>
<Node 'child7'>
<Node 'child5'>
<Node 'child2'>
<Node 'child6'>
<Node 'child10'>
<Node 'child3'>
<Node 'child8'>
<Node 'child9'>

oRoot.print_all_1()会打印下面的结果:

<Node 'root'>
<Node 'child1'>
<Node 'child2'>
<Node 'child3'>
<Node 'child4'>
<Node 'child5'>
<Node 'child6'>
<Node 'child8'>
<Node 'child9'>
<Node 'child7'>
<Node 'child10'>

简要描述Python的垃圾回收机制(garbage collection)

答案

这里能说的很多。你应该提到下面几个主要的点:

  • Python在内存中存储了每个对象的引用计数(reference
    count)。如果计数值变成0,那么相应的对象就会消失,分配给该对象的内存就会释放出来用作他用。
  • 偶尔也会出现引用循环(reference
    cycle)。垃圾回收器会定时寻找这个循环,并将其回收。举个例子,假设有两个对象o1和o2,而且符合o1.x == o2和o2.x == o1这两个条件。如果o1和o2没有其他代码引用,那么它们就不应该继续存在。但它们的引用计数都是1。
  • Python中使用了某些启发式算法(heuristics)来加速垃圾回收。例如,越晚创建的对象更有可能被回收。对象被创建之后,垃圾回收器会分配它们所属的代(generation)。每个对象都会被分配一个代,而被分配更年轻代的对象是优先被处理的。

将下面的函数按照执行效率高低排序

它们都接受由0至1之间的数字构成的列表作为输入。这个列表可以很长。一个输入列表的示例如下:[random.random() for i in range(100000)]。你如何证明自己的答案是正确的。

def f1(lIn):
    l1 = sorted(lIn)
    l2 = [i for i in l1 if i<0.5]
    return [i*i for i in l2]

def f2(lIn):
    l1 = [i for i in lIn if i<0.5]
    l2 = sorted(l1)
    return [i*i for i in l2]

def f3(lIn):
    l1 = [i*i for i in lIn]
    l2 = sorted(l1)
    return [i for i in l1 if i<(0.5*0.5)]

为什么提这个问题?

定位并避免代码瓶颈是非常有价值的技能。想要编写许多高效的代码,最终都要回答常识上来——在上面的例子中,如果列表较小的话,很明显是先进行排序更快,因此如果你可以在排序前先进行筛选,那通常都是比较好的做法。其他不显而易见的问题仍然可以通过恰当的工具来定位。因此了解这些工具是有好处的。

答案:

按执行效率从高到低排列:f2、f1和f3。要证明这个答案是对的,你应该知道如何分析自己代码的性能。Python中有一个很好的程序分析包,可以满足这个需求。

import cProfile
lIn = [random.random() for i in range(100000)]
cProfile.run('f1(lIn)')
cProfile.run('f2(lIn)')
cProfile.run('f3(lIn)')

为了向大家进行完整地说明,下面给出上述分析代码的输出结果:

>>> cProfile.run('f1(lIn)')
         4 function calls in 0.045 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.009    0.009    0.044    0.044 <stdin>:1(f1)
        1    0.001    0.001    0.045    0.045 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.035    0.035    0.035    0.035 {sorted}

>>> cProfile.run('f2(lIn)')
         4 function calls in 0.024 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.008    0.008    0.023    0.023 <stdin>:1(f2)
        1    0.001    0.001    0.024    0.024 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.016    0.016    0.016    0.016 {sorted}

>>> cProfile.run('f3(lIn)')
         4 function calls in 0.055 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.016    0.016    0.054    0.054 <stdin>:1(f3)
        1    0.001    0.001    0.055    0.055 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.038    0.038    0.038    0.038 {sorted}

你有过失败的经历吗?

为什么提这个问题?

恰当地回答这个问题说明你用于承认错误,为自己的错误负责,并且能够从错误中学习。如果你想变得对别人有帮助的话,所有这些都是特别重要的。如果你真的是个完人,那就太糟了,回答这个问题的时候你可能都有点创意了。

错误的答案

我从来没有失败过!

你有实施过个人项目吗?

如果做过个人项目,这说明从更新自己的技能水平方面来看,你愿意比最低要求付出更多的努力。如果你有维护的个人项目,工作之外也坚持编码,那么你的雇主就更可能把你视作为会增值的资产。即使他们不问这个问题,我也认为谈谈这个话题很有帮助。

  • 文章目录
  • 站点概览
loveNight

loveNight

自古求真皆寂寞,唯挑心灯伴夜霭

46 日志
24 分类
68 标签
RSS
Github Weibo Email SegmentFault Zhihu
友情链接
  • 我的CSDN博客
  • 我的新浪博客
  • 腾讯分析
  1. 1. 基础知识
  2. 2. Python Docs
  3. 3. 实用代码
    1. 3.1. 简易Web服务
    2. 3.2. 获取脚本所在的目录
    3. 3.3. 拖曳文件到Python脚本图标上,获取文件名
    4. 3.4. 解析csv
    5. 3.5. 如果文件已存在,则删除
    6. 3.6. 打开文件
    7. 3.7. 性能分析使用cProfile模块
    8. 3.8. 一维数组变二维
    9. 3.9. 二维矩阵转置
    10. 3.10. 使用zip合并相邻的列表项
    11. 3.11. 使用zip反转字典
    12. 3.12. random.sample(list, n)通常用来产生不重复的n位数字
    13. 3.13. enumerate会将数组或列表组成一个索引序列
    14. 3.14. 判断一个数是不是素数
    15. 3.15. 多序列同时迭代
    16. 3.16. 嵌套序列变平
    17. 3.17. 迭代多个有序排列数组(多路归并排序)
    18. 3.18. 一行筛质数
    19. 3.19. 对 array 按照第二列降序排序并取前 10 个
    20. 3.20. 对两个字符串(这里假设等长)做异或操作
    21. 3.21. 转置矩阵
    22. 3.22. 链式比较:
    23. 3.23. 真值测试
    24. 3.24. 字典默认值
  4. 4. 技术博客
  5. 5. 练习资源
  6. 6. 学习资料
  7. 7. 常用库
  8. 8. pip 常用命令
  9. 9. IDE与编辑器
  10. 10. 论坛与网站
  11. 11. 经验教训
    1. 11.1. os 库
  12. 12. 面试宝典
    1. 12.1. 到底什么是Python?
    2. 12.2. 补充缺失的代码
    3. 12.3. 阅读下面的代码,写出A0,A1至An的最终值
    4. 12.4. Python的多线程是个好主意吗?
    5. 12.5. 你如何管理不同版本的代码?
    6. 12.6. 下面代码会输出什么?
    7. 12.7. 猴子补丁(monkey patching)是什么?这种做法好吗?
    8. 12.8. 解释*args,**kwargs的含义与用途
    9. 12.9. 介绍@classmethod, @staticmethod, @property
    10. 12.10. 说明下列代码的输出结果
    11. 12.11. 说明下面代码的输出结果
    12. 12.12. 简要描述Python的垃圾回收机制(garbage collection)
    13. 12.13. 将下面的函数按照执行效率高低排序
    14. 12.14. 你有过失败的经历吗?
    15. 12.15. 你有实施过个人项目吗?
© 2015 - 2017 loveNight   |  Google网站地图   |  百度网站地图
powered by Hexo
主题 - NexT.Pisces
  |  本站总点击 次   |  您是第 位访客