一、预备知识
1.python简介
Hello World
答案
if __name__ == '__main__':
str1 = "Hello,"
str2 = "World!"
print('str1'+'str2')
解析
直接把str1和str2当成字符串而不是变量当然不可能输出hello world
注:
- eval的用法是把括号里面的代码用python执行一下
str1="Helo,"
str2="World!"
print(eval("str1+str2"))
#### Helo,World!
- join的用法
str_list = ["Hello,","World!"]
res = ''.join(str_list)
2.程序设计思想
2.1 编程语言简史
答案
if __name__ == '__main__':
languages = ...
years = ...
for language in languages:
for year in years:
print(language, ':', year)
解析
错误选项:一个语言都和每个年份一起打印了出来,正确的应该是一个语言按顺序对应一个年份。
2.2 编程语言发明家
答案
def parse_creators(creators):
profiles = []
i = 0
while i<len(creators):
creator = creators[i]
name, achievement = parse_parts(creator)
profiles.append({ 'name_cn': name, 'name_en': name, 'achievement': achievement })
i+=1
return profiles
解析
缺少继续拆分中英文姓名的功能
2.3 Alice、Bob 和他们的朋友们
答案
class CryptographyCity:
def __init__(self):
self.peoples = []
def add(self, text):
parser = SimpleCryptographyPeopleParser(text)
people = parser.parse(text)
self.peoples.append(people)
def introduce():
for people in peoples:
say(people)
def say(people):
info = f'{people.name_cn}({people.name_en}): 密码学家说我是一位{people.role},{people.desc}。'
print(info)
解析
class中定义函数的正确写法,即类中定义函数必须要有一个self参数
3.安装python
Python 安装交互式查询程序
答案
while True:
ret = input("请选择安装平台[w/c/u/m, 按q退出]:")
platform = shortcut_keys.get(ret)
if ret == 'q':
break
if platform is None:
print("不支持的平台")
break
doc = install.get(platform)
print(f"{platform}: {doc}")
解析
break退出循环,continue结束本次循环,进入下一轮循环。
4.运行方式
操作系统如何运行程序
答案
while True:
ret = input("请选择你想了解的 Python 运行方式(输入:r/s选择,输入 q 退出):")
if ret == 'r' or ret == 's':
has_learn_repl = ret=='r'
has_learn_source = ret=='s'
desc = run.get(shoutcut_keys.get(ret))['desc']
for i in range(0, len(desc)):
print("{}. {}".format(i, desc[i]))
elif ret != 'q':
print("[错误] 不支持的运行方式")
break
else:
pass
解析
- 因为ret只有在用户输入r或s时才有值,如果用户输入其他字符,那么ret就没有值,会导致程序出错。应该在判断用户输入是否合法后再进行has_learn_repl和has_learn_source的赋值操作.
- ret == ‘r’ or ret == 's’也符合elif的判断
5.常用开发工具
现代集成开发环境(IDE)
答案
find_records = {}
for top_ide in top_ides:
for py_ide in py_ides:
py_ide_name = py_ide['name']
if not find_records.get(py_ide_name):
if py_ide['name'].lower() == top_ide['IDE'].lower():
find_records[py_ide['name']] = True
dump_join_result(py_ide, top_ide)
解析
错误的打印是在满足两个都有同样IDE名称的时候打印共有的三个IDE信息,而其他的都是打印下面四个IDE信息。
可更改为
find_records = {}
find_records_names = []
for top_ide in top_ides:
for py_ide in py_ides:
py_ide_name = py_ide['name']
if not find_records.get(py_ide_name):
if py_ide['name'].lower() == top_ide['IDE'].lower():
find_records[py_ide['name']] = True
find_records_names.append(py_ide['name'].lower())
dump_join_result(py_ide, top_ide)
for py_ide in py_ides:
if py_ide['name'].lower() not in find_records_names:
dump_join_result(py_ide, None)
6.编码规范
代码规范(风格)
答案
if not word in word_dict:
word_info = {'word': word, 'count': 0}
word_dict[word] = word_info
word_info['count'] += 1
解析
其他正确选项的第一句都是:word_info = word_dict.get(word)。作用是将word_info指向word_dict中对应的值上。缺少这一句的话,word_info会指向上一个while循环的位置。
举例说明:
guides = “a b c d a b ” # 因为在分割符位置进行计数,所以最后要有一个空格,才能将最后一个数计入
''' 输出结果 '''
单词排行榜
--------
1. 单词:d, 词频:3
2. 单词:a, 词频:1
3. 单词:b, 词频:1
4. 单词:c, 词频:1
7.模块管理
7.1 Python标准库模块导入
答案
import time.time
if __name__ == '__main__':
print(time())
解析
没有time.time模块,所以无法导入。可以frome time import time 。time.time()返回的是时间戳。
7.2 从前有座山,山上有座庙,庙里有个老和尚说:使用Python 包(package)组织代码
答案
import sys
if __name__ == '__main__':
while True:
import parent
import parent.one.one
import parent.two
del sys.modules['parent']
del sys.modules['parent.one.one']
del sys.modules['parent.two']
解析
注:导入子目录会自动导入父目录的module
import parent
缓存已有---无
输出---从前有座山,
缓存新增---parent
import parent.one.one
缓存已有---parent
输出---山上有座庙,庙里有个老和尚,
缓存新增---parent.one, parent.one.one
import parent.two
缓存已有---parent,parent.one, parent.one.one
输出---老和尚说
缓存新增---parent.two
del sys.modules['parent']
缓存还有---parent.one, parent.one.one, parent.two
del sys.modules['parent.one.one']
缓存还有---parent.one, parent.two
del sys.modules['parent.two']
缓存还有---parent.one (这里没删干净!!!!!)
(下一次循环)
import parent
缓存已有---parent.one
输出---从前有座山,
缓存新增--- parent
import parent.one.one
缓存已有---parent.one, parent
输出--庙里有个老和尚,(这里因为parent.one缓存还在,不会执行“山上有座庙”)
...
7.3 使用相对路径导入包
答案
import ..subpackage2.moduleZ
解析
import module_name。即import后直接接模块名
from package_name import module_name。一般把模块组成的集合称为包(package)。与第一种写法类似,Python会在sys.path和运行文件目录这两个地方寻找包,然后导入包中名为module_name的模块。
二、基础语法
1.缩进规则
看不见的开始和结束
答案
if __name__ == '__main__':
i = 0
c = 5
max = 10
while i < max:
d = max-i-i
if abs(d) < 3:
print(i, max-i)
else:
pass
i += 1
解析
缩进问题
2.函数
2.1 使用函数组织代码
答案
circulate_print(str, count)
解析
没有count+1,会导致死循环
2.2 循环计算阶乘函数
答案
import math
z = n + 1
p = [1.000000000190015, 76.18009172947146, -86.50532032941677,
24.01409824083091, -1.231739572450155, 1.208650973866179E-3, -5.395239384953E-6]
d1 = math.sqrt(2 * math.pi) / z
i = 1
d2 = p[0]
while i <= 6:
d2 += p[i] / (z + i)
i += 1
d3d4 = math.pow((z + 5.5), (z + 0.5))*math.exp(-(z + 5.5))
d = d1 * d2 * d3d4
r = int(d)
解析
计算的不是阶乘
2.3 Python 函数递归(1)
答案
def inner_fact(n, m, r):
if m == n:
return r
return inner_fact(n, m+1, r*m)
def fact4(n):
return inner_fact(n, 1, 1)
解析
m 等于 n 时, 阶乘 r 还只是乘到了 m - 1, 没有乘到 m, 计算 10 的阶乘, 实际只计算了 9 的阶乘
代码可以改为
def inner_fact(n, m, r):
if m == n:
return r
return inner_fact(n, m+1, r*m)
def fact4(n):
return inner_fact(n+1, 1, 1)
2.4 Python 斐波那契(fibonacci)(I)
答案
def fibonacci_inner(n, r):
if n == 1 or n == 2:
return r
return fibonacci_inner(n-1, fibonacci_inner(n-2, r))
def fibonacci4(n):
return fibonacci_inner(n, 0)
解析
r没有参与到迭代中
改为
def fibonacci_inner(n, r):
if n == 1 or n == 2:
return r
return fibonacci_inner(n-1, fibonacci_inner(n-2, r+1))
def fibonacci4(n):
return fibonacci_inner(n, 1)
2.5 Python 斐波那契(fibonacci)(II)
答案
if cache.get(n) is None:
fibonacci_inner1(n-2, cache)
fibonacci_inner1(n-1, cache)
cache[n] = cache[n-1]+cache[n-2]
return cache[n]
解析
没有给cache[n-1]和cache[n-2]赋值
2.6 基于函数的API设计,理解接口与实现分离
答案
def init():
return {"pre": None, "key": None, "value": None, "next": None}
def set(dict, key, value):
node = dict
while node is not None:
if node['key'] == key:
return
node = node['next']
node['next'] = {"pre": node, "key": key, "value": value, "next": None}
def get(dict, key):
node = dict
while node is not None:
if node['key'] == key:
return node['value']
node = node['next']
def exist(dict, key):
node = dict
while node is not None:
if node['key'] == key:
return True
node = node['next']
return False
解析
在初始化时把所有的值都赋值成了None.在node = node[‘next’]之后,这个node就变成了None,所以后面再去使用node[‘next’]就提示不存在了。
def init():
return {"pre": None, "key": None, "value": None, "next": None}
def set(dict, key, value):
node = dict
while node["next"] is not None:
if node['key'] == key:
return
node = node['next']
node["next"] = {"pre":node, "key": key, "value": value, "next": None}
def get(dict, key):
node = dict
while node is not None:
if node['key'] == key:
return node['value']
node = node['next']
def exist(dict, key):
node = dict
while node is not None:
if node['key'] == key:
return True
node = node['next']
return False
3 类
3.1 Python 类的基本使用(1)
答案
class GuessSentenceGame:
...
def setup(sentences):
for sentence in sentences:
cut_pos = sentence.find(' ')
self.kv.set(sentence[0:cut_pos], sentence[cut_pos+1:].strip())
def guess(first_word):
self.kv.get(first_word)
return 0, value if value else 1, None
解析
这道题的错误有点像找茬问题,问题选项的guess方法中没有赋值给value,所以出错
但是从题目逻辑性出发,可以进一步增强代码的健壮性,比如guess方法中加入self.ret和self.value的比较
class KeyValueSet:
def __init__(self) -> None:
self.dict = {}
def set(self, key, value):
self.dict[key] = value
def get(self, key):
return self.dict.get(key)
def keys(self):
return self.dict.keys()
class GuessSentenceGame:
def __init__(self):
self.kv = KeyValueSet()
self.score = 0
def setup(self, sentences):
for i in sentences:
key = i.split(' ', 1)[0]
value = i.split(' ', 1)[1]
self.kv.set(key, value)
def guess(self, first_word):
err = 0
if self.kv.get(first_word) == self.ret:
err = 0
value = self.kv.get(first_word)
return err, value
else:
err = 1
value = self.kv.get(first_word)
return err, value
def run(self):
self.score = 0
for first_word in self.kv.keys():
self.ret = input("猜一猜下半句是什么? {} -> :".format(first_word))
err, value = self.guess(first_word)
if err == 0:
print('你太厉害了,这都能猜得到!+10分!')
self.score += 10
else:
self.score -= 2
print('哈哈,肯定猜不到得啦:{}->{},扣除2分!'.format(first_word, value))
print('游戏结束,你本次游戏得分:', self.score)
if __name__ == '__main__':
sentences = [
"hello world",
'monkey king',
'tomorrow is another day',
"good bye"
]
game = GuessSentenceGame()
game.setup(sentences)
game.run()
3.2 Python 类的基本使用(2)
通过类的集成,可以扩展原有的类。例如继承KeyValueSet容器类,扩展功能,支持类似redis的 hset/hget/hkeys 扩展接口
答案
hash_set = self.get(hash_key,{key:value})
self.set(hash_key, hash_set)
解析
hashset的主key只有一个,后面的dict是值
注:
- 本题使用的是KeyValueSet作为基类,其中每个key对应的是一个value列表。因此,对于相同的hash_key,我们可以在value列表中添加多个key-value对。对于hget方法,可以通过value列表来获取指定的key值。对于hset方法,我们需要在value列表中添加新的key-value对,而不是直接覆盖原有的key-value对。
- hash_set = {key:value} 和 hash_set[key]=value的区别是,前者hash_set是空,是赋值操作;后者是添加值操作
3.3 Python 类的基本使用(3)
答案
self.set(hash_key, {key: value})
解析
类HashKeyValueSet没有定义set函数,无法调用,所以是错误的。self.kvset是一个KeyValueSet类,定义了set函数,可以调用。
此外,这两个选项没有对{key:value}进行扩展,而是直接覆盖了,所以都是错的。运行结果只有一个{“good”:“bye”}。
4.顺序语句结构
python顺序语句
答案
x = 10
y = 20
s = x * y
解析
python的运行顺序是,哪怕是你调用方法,只要方法内部,不存在其他方法,他就是自上向下运行代码,必须先有数据,才能对数据做运算,如果还没有数据,或者只有一部分数据,都会报错
注:
if __name__ == '__main__':
含义是:表示如果程序直接被python 启动,例如 python test.py
的时候。一个python文件也可能被其他python文件通过 import 导入,加了这句则被导入的时候不会执行这行代码下缩进的代码。如果不加这句,直接放全局,无论是被 python命令启动还是被其他文件import,全局代码都会执行。
5.条件和分支
5.1 Python 条件和分支(1)
答案
if ret == "{}".format(test):
print("哎,这么简单都答不对,回去重修吧!")
else:
print("恭喜你答对了!")
解析
逻辑问题
5.2 Python 条件和分支(2)
答案
if database.get(key) is None:
print("* 无法检索到该信息!")
else:
print("* 返回:{}".format(database[key]))
解析
考察if not value/ if value/ if value is None的用法
6.循环
6.1 Python 循环1
答案
for i, item in list:
print('')
print("## 第{}条信息".format(i))
print("* id: {}".format(item['id']))
print("* number: {}".format(item['number']))
print("* title: {}".format(item['title']))
print("* body: {}".format(item['body']))
解析
enumerate的用法,输出是list的index 和value
6.2 Python 循环2
答案
while i in list:
item = list[i]
print('')
print("## 第{}条信息".format(i))
print("* id: {}".format(item['id']))
print("* number: {}".format(item['number']))
print("* title: {}".format(item['title']))
print("* body: {}".format(item['body']))
循环
i是index not inlist
注:
- python iter()函数用于生成迭代器;
- python next()函数和iter()函数组合使用,返回迭代器的下一个项目。如果是next(a,b),那么获取a的最后一个元素之后, 下一次next返回设置的默认值b, 而不会抛出 StopIteration。
7. 数据类型
python六大数据类型包括:数字型(整型、浮点型、布尔型和复数类型)、字符串、列表、元组、集合和字典
7.1 字符串
答案
print("双引号字符串里的双引号: "hello world!"")
print('单引号字符串里的单引号: 'hello world!'')
triple2 = '''
三引号字符串里的三引号:
* "双引号"
* '单引号'
* '''三引号'''
'''
解析
引号嵌套问题:同种引号嵌套要注意转义,修改后的正确实现如下
print("双引号字符串里的双引号: \"hello world!\"")
print('单引号字符串里的单引号: \'hello world!\'')
triple2 = '''
三引号字符串里的三引号:
* "双引号"
* '单引号'
* \'''三引号\'''
'''
7.2 列表
答案
[30, 40]
解析
1.首先array = []是一个空列表
2. append了一个10和20,这个时候列表里面就多了两个数,不再是空列表 而是变成了array=[10,20]
3.pop默认是删除最后一个的,但是它给了一个索引位置0,那么就把array中索引为 0 的元素删除了,这个时候array=[20]
4.然后又append添加了 30和40两个数 ,这个时候array=[20,30,40]
5.pop把索引为0的删除,这个时候array=[30,40]
7.3元组
答案
tuple1 = ('红色')
for element in tuple1:
print(element)
解析
只有一个元素的元组,需要在最后面添加一个逗号,不然系统会误判
不带括号的一系列逗号组成的序列也是元组
7.4字典
答案
['程序员', '户外达人']
None
解析
- python 对于dict 字典 key value 类型, key 值必须唯一, 当对一个字段进行add key 时, 如果key 存在 则更新key 的value内容。不存在则新增
- 字典get方法不会报错,没有的话返回None
8.内置类
答案
def filter_element(items, bound):
res = [item for item in items if item < bound]
return res
解析
要求是要过滤掉小于3的数字,逻辑错误
9.内置函数
9.1 Python 常用内置方法(1)
答案
解析
round()函数表示用于四舍五入
9.2 Python 常用内置方法(2)
列表相关
答案
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
assert len(seasons) == 4
shortcut = list(map(lambda s: s[0], seasons))
assert shortcut == ['S', 'S', 'F', 'W']
9.3 python基本输入
答案
while True:
n = input("请输入0-100之间的一个数字:")
try:
n = int(n)
except:
print("无效的数字")
continue
if n == v:
print("你猜对了!")
break
elif n < v:
print("你猜错了,我想到的数字比{}大".format(n))
elif n > v:
print("你猜错了,我想到的数字比{}小".format(n))
解析
input 返回str,需要int
注:
- try和except的使用
运行一段代码,能运行继续运行,不能运行的话,输出except后的语句,也可以设置错误类型,最后加个finally的话try最后总会运行finally - read函数是读取文件输入,input接收用户从键盘上输入,返回的结果是字符串,如果判断需要进行强制转换一下。
三、进阶语法
1. Python 列表推导式
1.1 Python 列表推导式(1)
答案
even = [n for n in list if n % 2 == 0]
解析
列表推导式
https://www.runoob.com/python3/python-comprehensions.html
https://zhuanlan.zhihu.com/p/90558097
1.3 Python 生成器推导式
答案
reading = (book for book in books if len(book) <= 4)
解析
元组的推导式,同list
元组可以理解为特殊的list,即不能更改元素的list
1.4 Python 元组推导式
答案
def test():
books = ('程序员修炼之道', '构建之法', '代码大全', 'TCP/IP协议详解')
reading = (book for book in books if len(book) <= 4)
print("太长的书就不看了,只读短的:")
for book in reading:
print(" ->《{}》".format(book))
print("可是发现书的名字短,内容也可能很长啊!")
if __name__ == '__main__':
test()
1.5 Python 字典推导式
答案
non_windows = {key: install[key] for key in install if key != 'w'}
解析
字典的推导式
2.三元表达式
2.1 Python 三元表达式(1)
答案
even_count += 1 if i % 2 == 0 else 0
解析
三元推导式
2.2 Python 三元表达式(2)
答案
even_count += 2 if i % 4 == 0 else 1 if i % 2 == 0 else 0
解析
先判断是否是4的倍数,再判断是否是2的倍数
如果先判断2,轮不到判断4,明显让2就一锅端了。反之,先判断4,2的也不会被一锅端进4里边
3. 断言
Python 断言
答案
def check_param(key_value_map, key):
assert key_value_map
assert type(key_value_map) == dict
assert key
assert type(key) == str
解析
所谓断言,就是证明,使用 assert 对输入函数输入参数和函数返回结果分别做前校验和后校验
正确的是
def check_param(key_value_map, key):
assert key_value_map is not None
assert type(key_value_map) == dict
assert key is not None
assert type(key) == str
4. with as
4.1 Python with-as 语句(1)
答案
def load_json(file):
with open(file, 'r') as f:
return json.loads(f.read())
def dump_json(file, obj):
with open(file, 'w') as f:
f.write(json.dumps(obj, indent=2, ensure_ascii=False))
解析
- r表示read w表示write
- json.loads 转为json json.dumps json转为其他
4.2 Python with-as 语句(1)
答案
class TimeSpan:
def __enter__(self):
return time.time()
def __exit__(self, exc_type, exc_val, exc_tb):
end = time.time()
print('耗时:{}毫秒'.format((end-exc_val)))
注:
- 参数传给slef这种写法值得学习
class TimeSpan:
def __enter__(self):
self.end = None
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.end = time.time()
print('耗时:{}毫秒'.format((self.end-self.start)))
5. 异常捕获预处理
Python 异常处理
# -*- coding: UTF-8 -*-
import json
import traceback
import logging
logger = logging.getLogger(__name__)
def load_json(file):
with open(file, 'r') as f:
return json.loads(f.read())
def test():
try:
ret = load_json('a.json')
return {'err': 'success', 'result': ret}
except Exception as e:
logger.error(f"load json exception:{str(e)}")
logger.error(traceback.format_exc())
return {'err': 'exception'}
ret = load_json('a.json')
if __name__ == '__main__':
test()
解析
- except Exception as e:固定写法
- logging的用法
6. 字符串方法
Python 字符串方法
答案
def naive_calc(code):
code_lines = [l for l in code.split('\n') if l.strip() != '']
for line in code_lines:
ret = re.match("\s*(\d+)([\+\-\*\/])(\d+)\s*", line)
left = ret.group(1)
op = ret.group(2)
right = ret.group(3)
if op == '+':
print('{}+{}={}'.format(left, right, int(left)+int(right)))
elif op == '-':
print('{}-{}={}'.format(left, right, int(left)-int(right)))
elif op == '*':
print('{}*{}={}'.format(left, right, int(left)*int(right)))
elif op == '/' and right != '0':
print('{}/{}={}'.format(left, right, int(left)/int(right)))
解析
- re.match(rule,target)
- str转换为int 直接int()
7. lambda函数
Python 匿名表达式
答案
解析