一、文件处理相关
1、编码问题
(1)请说明python2 与python3中的默认编码是什么?
答:Python2默认的字符编码是ASCII,默认的文件编码也是ASCII ;python3默认的字符编码是unicode,默认的文件编码是utf-8。
(2)为什么会出现中文乱码?你能列举出现乱码的情况有哪几种?
答:无论以什么编码在内存里显示字符,在硬盘上存储都是二进制。存到硬盘是以何种编码,再从硬盘读取出来,就必须是何种编码,不然就会出现乱码。解释器默认编码、Terminal编码、文件编码、操作系统语言设置。
(3)如何进行编码转换?
答:对文件先decode为unicode,再encode为需要转换的编码。
(4)#-*-coding:utf-8-*- 的作用是什么?
答:告诉解释器这个文件的编码格式是utf-8
(5)解释py2 bytes vs py3 bytes的区别
答:python3把字符串的编码改成了unicode, 还把str和bytes做了明确区分, str就是unicode格式的字符,bytes是单纯二进制。
在python2里,将string处理为原生的bytes类型。
2、文件处理
(1)r和rb的区别是什么?
答:r是文本只读模式
rb:二进制只读模式,无法指定encoding,因为在该模式下数据读到内存里直接是bytes格式,如要查看内容还需手动decode
(2)解释一下以下三个参数的分别作用
open(f_name,\'r\',encoding="utf-8")
答:f_name将打开的当前目录文件名,r:文本只读模式,encoding="utf-8":指定打开文件为utf-8编码模式。
二、函数基础
1、写函数,计算传入数字参数的和。(动态传参)
def func(*args): list1 = [] sum_data = 0 for i in args: list1.append(i) sum_data += i print(list1) print(sum_data) func(313, 213, 12, 1234, 453, 56)
2、写函数,用户传入修改的文件名,与要修改的内容,执行函数,完成整个文件的批量修改操作
def file_modify(filename, old, new): import os f = open(filename, mode=\'r+\', encoding=\'utf-8\') new_f = open(filename+"_bak", mode=\'w\', encoding=\'utf-8\') for line in f: if old in line: line = line.replace(old,new) new_f.write(line) os.remove(filename) os.rename(filename+"_bak",filename) file_modify(\'aaaa.txt\', \'ddd\', \'goodman\')
3、写函数,检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容。
def func(args): n = 0 for i in args: if i == "": n += 1 print("有%s个空内容"%n) func((1, \'\', 2, 44, \'\', 12))
4、写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
PS:字典中的value只能是字符串或列表
def func(args_dic): for i in args_dic: if len(args_dic[i]) > 2: item = args_dic[i][0:2] # 前两项 args_dic[i] = item print(args_dic) dic = {"k1": "v1v1", "k2": [11,22,33,44]} func(dic) # {\'k1\': \'v1\', \'k2\': [11, 22]}
5、解释闭包的概念
答:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
三、函数进阶
1、写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组
例如:[(‘红心’,2),(‘草花’,2), …(‘黑桃A’)]
def poker(): a = [\'红心\', \'草花\', \'方片\', \'黑桃\'] b = [2, 3, 4, 5, 6, 7, 8, 9, 10] c = [\'J\', \'Q\', \'K\', \'A\'] li = [] for i in b: for j in a: item = (j,i) li.append(item) for m in c: for n in a: item2 = (n+m) li.append(item2) print(li) print(len(li)) poker()
2、写函数,传入n个数,返回字典{‘max’:最大值,’min’:最小值}
例如:min_max(2,5,7,8,4)
返回:{‘max’:8,’min’:2}
def min_max(*args): # dict形式 li = [] for i in args: li.append(i) li.sort() dic = {\'max\':li[-1], \'min\':li[0]} print(dic) min_max(2,5,7,8,4) # 输出:{\'max\': 8, \'min\': 2}
3、写函数,专门计算图形的面积
其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积
调用函数area(‘圆形’,圆半径) 返回圆的面积
调用函数area(‘正方形’,边长) 返回正方形的面积
调用函数area(‘长方形’,长,宽) 返回长方形的面积
def area(type, *args): def rectangle(length, wide): return "长方形面积", length*wide def square(length): return "正方形面积", length**2 def circlar(radius): import math return "圆形面积", math.pi*(radius**2) if type in locals(): return eval(type)(*args) print(area(\'rectangle\', 133, 4)) print(area(\'circlar\', 20)) print(area(\'square\', 10))
4、写函数,传入一个参数n,返回n的阶乘
例如:cal(7)
计算7*6*5*4*3*2*1
def cal(n): item = 1 if int(n) == n: li = range(n+1) for i in li: if i == 0: pass else: item = item*i print(item) else: return "%s不是整数"%n cal(3) # 法二: def cal(n): result=1 for i in range(n, 0, -1): # 倒序 result=result*i return result print(cal(7))
5、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
user_db = { \'hqs\':\'123\', \'susiff\':\'123\', \'guangfa\':\'123\' } with open(\'db.txt\', \'w\', encoding=\'utf-8\') as f: f.write(str(user_db)) login_db = {\'user\': None, \'status\': False} db_path = r\'db.txt\' def login(func): def inner(*args,**kwargs): if login_db[\'user\'] and login_db[\'status\']: res = func(*args, **kwargs) return res user = input(\'input user:\') passwd = input(\'input passwd:\') with open(db_path, \'r\', encoding=\'utf-8\') as f: user_db2 = eval(f.read()) if user in user_db2 and passwd == user_db2[user]: print(\'login ok\') login_db[\'user\'] = user login_db[\'status\'] = True res = func(*args, **kwargs) return res else: print(\'login error\') return inner # 加括号执行,不加括号返回内存地址 @login def home(): print("首页".center(40,\'-\')) @login def america(name): print("欧美专区".center(40,\'-\')) home() america(\'hqs\')
四、生成器和迭代器
1、生成器和迭代器的区别?
可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator).
在Python中,可以在循环过程中不断推算后续元素,这种一边循环一边计算的机制,称为生成器(generator)。
生成器是迭代器的一种:
1.生成器都是迭代器对象,但list\dict\str虽然是可迭代对象,但不是迭代器。
2.把list\dict\str等可迭代对象变成迭代器可以使用iter()函数
2、生成器有几种方式获取value?
1.next():唤醒生成器并继续执行
2.send():唤醒生成器并继续执行;发送一个信息到生成器内部。 3.for循环
3、通过生成器写一个日志调用方法, 支持以下功能
- 根据指令向屏幕输出日志
- 根据指令向文件输出日志
- 根据指令同时向文件&屏幕输出日志
- 以上日志格式如下
2017-10-19 22:07:38 [1] test log db backup 3 2017-10-19 22:07:40 [2] user alex login success #注意:其中[1],[2]是指自日志方法第几次调用,每调用一次输出一条日志
- 代码结构如下:
def logger(filename,channel=\'file\'): """ 日志方法 :param filename: log filename :param channel: 输出的目的地,屏幕(terminal),文件(file),屏幕+文件(both) :return: """ ...your code... #调用 log_obj = logger(filename="web.log",channel=\'both\') log_obj.__next__() log_obj.send(\'user alex login success\')
解答如下:
def logger(filename, channel): """ 日志方法 :param filename: log filename :param channel: 输出的目的地,屏幕(terminal),文件(file),屏幕+文件(both) :return: """ import time a = time.localtime() log_time = time.strftime(\'%Y-%m-%d %H:%M:%S\', a) count = 0 while count < 10: count += 1 sign = yield count log_info = log_time + \' [\' + str(count) + \'] \' + sign if channel == \'file\': f = open(filename, mode=\'a+\', encoding=\'utf-8\') f.write(\'\n\'+log_info) f.close() elif channel == \'terminal\': print(log_info) elif channel == \'both\': f = open(filename, mode=\'a+\', encoding=\'utf-8\') f.write(\'\n\' + log_info) f.close() print(log_info) else: print(\'请输入正确的模式!\') log_obj = logger(filename="web.log", channel=\'both\') log_obj.__next__() log_obj.send(\'user alex login success\') log_obj.send(\'user hqs login success\')
五、内置函数
1、用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb。
name = [\'alex\',\'wupeiqi\',\'yuanhao\',\'nezha\'] print(list(map(lambda x: x+\'_sb\', name))) """ [\'alex_sb\', \'wupeiqi_sb\', \'yuanhao_sb\', \'nezha_sb\'] """
2、用filter函数处理数字列表,将列表中所有的偶数筛选出来。
num = [1, 3, 5, 6, 7, 8] print(list(filter(lambda x: x % 2 == 0, num))) """ [6, 8] """
3、如下,每个小字典的name对应股票名字,shares对应多少股,price对应股票的价格。
portfolio = [ {\'name\': \'IBM\', \'shares\': 100, \'price\': 91.1}, {\'name\': \'AAPL\', \'shares\': 50, \'price\': 543.22}, {\'name\': \'FB\', \'shares\': 200, \'price\': 21.09}, {\'name\': \'HPQ\', \'shares\': 35, \'price\': 31.75}, {\'name\': \'YHOO\', \'shares\': 45, \'price\': 16.35}, {\'name\': \'ACME\', \'shares\': 75, \'price\': 115.65} ]
计算购买每支股票的总价;用filter过滤出,单价大于100的股票有哪些?
portfolio = [ {\'name\': \'IBM\', \'shares\': 100, \'price\': 91.1}, {\'name\': \'AAPL\', \'shares\': 50, \'price\': 543.22}, {\'name\': \'FB\', \'shares\': 200, \'price\': 21.09}, {\'name\': \'HPQ\', \'shares\': 35, \'price\': 31.75}, {\'name\': \'YHOO\', \'shares\': 45, \'price\': 16.35}, {\'name\': \'ACME\', \'shares\': 75, \'price\': 115.65} ] def sum_shares(dic): name = dic[\'name\'] shares = dic[\'shares\'] price = dic[\'price\'] sum_price = "%.2f" % (shares * price) new_dic = {\'name\':name, \'sum_price\':sum_price} return new_dic print(list(map(sum_shares, portfolio))) # 每支总价 """ [ {\'name\': \'IBM\', \'sum_price\': 9110.00}, {\'name\': \'AAPL\', \'sum_price\': 27161.00}, {\'name\': \'FB\', \'sum_price\': 4218.00}, {\'name\': \'HPQ\', \'sum_price\': 1111.25}, {\'name\': \'YHOO\', \'sum_price\': 735.75}, {\'name\': \'ACME\', \'sum_price\': 8673.75}] """ print(list(filter(lambda x: x[\'shares\'] > 100, portfolio))) """ [{\'name\': \'FB\', \'shares\': 200, \'price\': 21.09}] """
六、进阶练习
1、请分别介绍文件操作中不同的打开方式之间的区别:
r:文本只读模式,以什么模式存文件,就以什么编码打开文件
rb:二进制只读模式,该模式下数据读取到内存里直接就是bytes格式,无法指定encoding
r+:读写文件模式,可读可写可追加
rb+:二进制读写模式,在内存中读取写入的均为bytes格式
w:只写模式,不可读,不存在则创建,存在则清空内容
wb:二进制写模式
w+:写读模式,以创建的模式打开(将原文件覆盖),可以读取写入的内容
wb+:二进制写读模式
a:追加模式,可读,不存在则创建,存在则只追加内容
ab:二进制追加模式
a+:同a
ab+:同ab
2、有列表 li = [\'alex\', \'egon\', \'smith\', \'pizza\', \'alen\'], 请将以字母“a”开头的元素的首字母改为大写字母;
li = [\'alex\', \'egon\', \'smith\', \'pizza\', \'alen\'] def str_upper(x): if x[0] == \'a\': x = \'A\' + x[1:] else: pass return x print(list(map(str_upper, li))) """ [\'Alex\', \'egon\', \'smith\', \'pizza\', \'Alen\'] """
3、有如下程序, 请给出两次调用show_num函数的执行结果,并说明为什么:
num = 20 def show_num(x=num): print(x) show_num() num = 30 show_num() """ 20 30 """
答:函数参数x是取得num的值,num的值属于全局变量,第一次调用函数的时候,全局变量num=20,第二次调用时,全局变量num发生了修改num=30
4、有列表 li = [\'alex\', \'egon\', \'smith\', \'pizza\', \'alen\'], 请以列表中每个元素的第二个字母倒序排序;(后面调整解法)
li = [\'alex\', \'egon\', \'smith\', \'pizza\', \'alen\'] def str_sort(li): def cut_li(x): new_x = x[1:] return new_x new_li = list(map(cut_li, li)) new_li.sort() new_li.reverse() final_li = [] for i in new_li: for j in li: if i == j[1:]: final_li.append(j) print(final_li) str_sort(li)
运用内置函数sorted改写该题:
# 方法二:内置函数sorted() li = [\'alex\', \'egon\', \'smith\', \'pizza\', \'alen\'] new_li = sorted(li, key=lambda x: x[1], reverse=True) print(new_li) """ [\'smith\', \'alex\', \'alen\', \'pizza\', \'egon\'] """
5、有名为poetry.txt的文件,其内容如下,请删除第三行;
昔人已乘黄鹤去,此地空余黄鹤楼。
黄鹤一去不复返,白云千载空悠悠。
晴川历历汉阳树,芳草萋萋鹦鹉洲。
日暮乡关何处是?烟波江上使人愁。
import os filename = \'poetry.txt\' file = open(filename, \'r\', encoding=\'utf-8\') new_poetry = [] for line in file.readlines(): if line.strip() == \'\': pass else: new_poetry.append(line.strip()) del new_poetry[2] f = open(\'%s.new\' % filename, \'w\') for i in new_poetry: f.write(i+\'\n\n\') os.rename(\'%s.new\' % filename, filename)
6、有名为username.txt的文件,其内容格式如下,写一个程序,判断该文件中是否存在"alex", 如果没有,则将字符串"alex"添加到该文件末尾,否则提示用户该用户已存在;
pizza
alex
egon
filename = \'username.txt\' with open(filename, \'r+\', encoding=\'utf-8\') as f: name = \'alexx\' i = f.read() print(i) if name in i: print(\'%s already in this %s\' % (name, filename)) else: f.write(\'\n\'+name)
7、有名为user_info.txt的文件,其内容格式如下,写一个程序,删除id为100003的行;
pizza,100001 alex, 100002 egon, 100003
import os filename = \'user_info.txt\' with open(filename, \'r+\', encoding=\'utf-8\') as f: f_new = open(\'%s_new\' % filename, \'w+\', encoding=\'utf-8\') for i in f: if \'100003\' in i: pass else: f_new.write(i) # os.rename(\'%s_new\' % filename, filename) # 两种都有效果 os.replace(\'%s_new\' % filename, filename)
8、有名为user_info.txt的文件,其内容格式如下,写一个程序,将id为100002的用户修改为alex li
pizza,100001 alex, 100002 egon, 100003
import os filename = \'user_info.txt\' with open(filename,\'r+\', encoding=\'utf-8\') as f: f_new = open(\'%s_new\' % filename, \'w+\') for i in f: if \'100002\' in i: line = i.split(\',\') line[0] = \'alex li\' i = line[0] +\', \'+ line[1] f_new.write(i) else: f_new.write(i) os.rename(\'%s_new\' % filename, filename)
9、写一个计算每个程序执行时间的装饰器;
import time def timmer(func): def inner(): start_time = time.time() func() wait_time = time.time() - start_time print("%s 运行时间:" % func.__name__, \'%.2f\' % wait_time) return inner a = time.localtime() @timmer def log_1(): print(\'%s-%s-%s\'%(a.tm_year, a.tm_mon, a.tm_mday)) @timmer def log_2(): time.sleep(2) print(\'%s-%s-%s\' % (a.tm_year, a.tm_mon, a.tm_mday)) @timmer def log_3(): time.sleep(4) print(\'%s-%s-%s\' % (a.tm_year, a.tm_mon, a.tm_mday)) log_1() log_2() log_3()
10、lambda是什么?请说说你曾在什么场景下使用lambda?
答案:lambda函数就是可以接受任意多个参数(包括可选参数)并且返回单个表达式值得函数
优势:1.lambda函数比较轻便,即用即仍,适合完成只在一处使用的简单功能。
2.匿名函数,一般用来给filter,map这样的函数式编程服务
3.作为回调函数,传递给某些应用,比如消息处理。
11、题目:写一个摇骰子游戏,要求用户压大小,赔率一赔一。
要求:三个骰子,摇大小,每次打印摇骰子数。
import random def dice(status): a = random.randint(1, 6) # 返回1-6之间随机数,包括6 b = random.randint(1, 6) c = random.randint(1, 6) print(a, b, c) result = a + b + c if result > 10: print(\'结果是大!\') if status == \'大\': print(\'你赢了!!\') if status == \'小\': print(\'你输了!!\') else: print(\'结果是小!\') if status == \'小\': print(\'你赢了!!\') if status == \'大\': print(\'你输了!!\') dice(\'大\')