开发者笔记
2015 年 5 月 18 日
1.叠加装饰器的装饰顺序与执行顺序
装饰顺序:从下往上(被装饰函数)
执行顺序:从上往上(python代码的执行顺序)
1.1无参装饰器模板:
def outter(func): @wraps(func) def inner(*args, **kwargs): # 装饰前做的事 return func(*args, **kwargs) # 装饰后做的事 retur inner
给函数添加测试运行时间的功能:
import time from functools import wraps def outter(func): @wraps(func) def inner(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print(end_time-start_time) return res return inner @outter def time_func(): time.sleep(1) time_func()
1.2有参装饰器
from functools import wraps def wrappers(params1,params2,params3): def outter(func): @wraps(func) def inner(*args, **kwargs): # 装饰前做的事 return func(*args, **kwargs) # 装饰后做的事 return inner return outter
2.什么是无参装饰器与有参装饰器
无参装饰器:被装饰的函数不需要参数,两层
有参装饰器:被装饰的函数需要参数,三层
说白了,有参装饰器就是再无参装饰器的基础上又添加了一层包装,目的:添加一个参数。那么有没有可能四层、五层?答案是没必要。因为四层、五层就意味着传递了更多的参数,那么我们用三层就能达到效果。所有装饰器最多三层
3.简述可迭代对象,迭代器对象及迭代取值方式,及for循环内部原理
3.1迭代器
迭代器:迭代取值的工具 ——(用__iter__生成迭代器对象) 优点:1.不依赖与索引取值 2.内存中只占一份空间,不会内存溢出,节约空间,运行效率更高*(执行一次__next__取值一次,而不是一次全部取值)* 缺点:1.不能获取指定的元素 2.只能依次往后取值
3.2 迭代协议
class MyIter: """num传入 用来指定迭代次数 """ def __init__(self, num): self.num = num self.c = 0 # 迭代 def __iter__(self): return self # 取值 def __next__(self): self.c += 1 if self.c <= self.num: return "jeff" else: raise StopIteration # 循环取值 for i in MyIter(10): print(i)
3.2 for 循环内部原理
1、在遍历Foo的实例对象时,执行for...in...时,首先会先执行__iter__()方法,将此对象变为迭代器。 2、__iter__方法返回了一个迭代器对象,而后调用next()方法进行循环
4.迭代器对象的优缺点是什么?
优点:1.不依赖与索引取值 2.内存中只占一份空间,不会内存溢出,节约空间,运行效率更高*(执行一次__next__取值一次,而不是一次全部取值)* 缺点:1.不能获取指定的元素 2.只能依次往后取值
5.请实现一个装饰器,限制该函数被调用的频率,如10秒一次
import time def outter(func): def inner(*args, **kwargs): print('开始调用函数。。。') res = func(*args, **kwargs) time.sleep(10) print('函数调用结束。。。') return res return inner @outter def index(): print('函数正在执行中。。。') index()
6.什么是序列化?什么是反序列化?为什么要这么做?
序列化: 序列:字符串 序列化:其他数据类型转成字符串的过程 序列化:其他数据类型转成字符串的过程 反序列化:字符串转成其他数据类型 注意: 写入文件的数据必须是字符串(二进制) 基于网络传输的数据必须是二进制
7.什么是json与picjle的区别是什么?
json:可以和其他语言玩 pickle:只能和自己(python)玩
8.ATM的登录与注册功能,用户数据用json数据保存。
with open(user_path, 'w', encoding='utf-8') as f: json.dump(user_dic, f, ensure_ascii=False) f.flush()
9.写一个扑克牌随机发牌游戏
飘三叶:
有bug,可取到重复的牌
import random def fried_golden_flower(): for i in range(0, 3): color = random.choice(['♥', '♠', '♦', '♣']) number = random.choice(['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']) a = color b = number point = namedtuple('扑克牌', ['color', 'number']) p = point(color, number) print(p, a+b) fried_golden_flower()
斗地主:
from collections import namedtuple import random def fight_against_landlords(): list = ['大鬼', '小鬼'] color = ['♥', '♠', '♦', '♣'] number = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'] for i in color: for n in number: list.append(i+n) # 打乱顺序 random.shuffle(list) # 生成迭代器,避免取到重复的牌 a = list.__iter__() for i in range(0,3): list_s = [] # 将发的17张牌放在此列表中 for num in range(0, 17): list_s.append(a.__next__()) print("玩家%s:%s" % (i+1, list_s)) dizhupai = [] for i in range(0, 3): dizhupai.append(a.__next__()) print('地主牌:%s' % dizhupai) fight_against_landlords()
10.爬虫正则
# 注意: 先敲课堂上的代码,理解并记录博客,再写作业! ''' 1.subprocess模块的作用? subprocess 子进程模块 2.什么是包?包的作用是什么? 包是一个带有__init__.py的文件夹,包也可以被导入,并且可以一并导入包下的所有模块。 3.如何防止模块被导入时自动执行测试功能。 伪代码: if __name__ == '__main__': 调用执行的函数() 4.请写出logging模块的使用步骤: # logging配置字典 LOGGING_DICT = {...} 1.配置日志的路径,项目的路径 2.配置日志的文件(名字,创建日志文件) 3.配置日志字典数据 4.调用日志模块,并把字典数据当参数参数 5.请写出爬虫原理的4个过程? 整个流程: 1.发送请求:requests 2.获取响应数据:对方机器直接返回 3.解析并提取想要的数据:re 4.保存提取后的数据:with open()保存 我们需要做的: 1.发送请求 2.解析数据 3.保存数据 6.什么是正则表达式与re模块? 正则表达式:一种筛选匹配字符串的独立技术 re模块:pycharm利用re模块,匹配字符串 7.使用正则表达式匹配出str1中的地址。 source = '''www.baidu.com
www.taobao.com
www.jd.com
www.oldboyedu.com
''' 答案1:print(re.findall('www.(?:baidu|taobao|jd|oldboyedu).com', source)) 结果:['www.baidu.com', 'www.taobao.com', 'www.jd.com', 'www.oldboyedu.com'] 答案2:print(re.findall('www\..*com', source)) 8.用正则过滤掉str3中的英文和数字,最终输出"张全蛋 广州" str3 = "not 404 found 张全蛋 99 广州" 不标准答案:print(re.findall('(?:张全蛋|广州)', str3)) 结果:['张全蛋', '广州'] 答案:print(re.findall('[^a-z:0-9:A-Z ]{2}', str3)) 结果:['张全蛋', '广州'] 9.复习今日之前的所有知识点!!! '''
11.面向对象编程的优缺点是什么?
优点:可扩展性高 缺点:相对于面向过程复杂度高
12.对象的属性查找顺序是什么?
自己——类——报错
class Student: name = '张全蛋' def __init__(self, name): self.name = name def learn(self): print('learning...') stu1 = Student('赵铁柱') print(stu1.name) # 结果:赵铁柱 优先查找自己
13.什么是继承?继承的目的?
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类(super),新建的类称为派生类或子类
14.python与期他语言的继承区别是什么?
python可以多继承,其他语言只能单继承
15.如何寻找继承关系?
mro(): 会把当前类的继承关系列出来
16.继承背景下对象属性的查找顺序是什么?
自己–>类->报错
17.什么是派生?如何重用父类的属性并派生?两种方式
第一种:super().__init方法 class Animal(): def __init__(self, name, eat, run): self.name = name self.eat = eat self.run = run print(f'{self.name}会{self.eat}') print(f'{self.name}会{self.run}') class Sunwukong(Animal): def __init__(self, name, eat, run, aa): super().__init__(name, eat, run) self.aa = aa
第二种:父类.__init__方法 class Animal(): def __init__(self, name, eat, run): self.name = name self.eat = eat self.run = run print(f'{self.name}会{self.eat}') print(f'{self.name}会{self.run}') class Sunwukong(Animal): def __init__(self, name, eat, run, aa): Animal.__init__(self,name, eat, run) self.aa = aa
18.什么是新式类与经典类?
- 新式类: 1.凡是继承object的类或子孙类都是新式类。 2.在python3中所有的类都默认继承object,都是新式类。 - 经典类: 1.在python2中才会有经典类与新式类之分。 2.在python2中,凡是没有继承object的类,都是经典类。
19.钻石继承下,经典类与新式类属性的查找顺序是什么?
20.下面这段代码的输出结果将是什么?请解释。
class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x, Child1.x, Child2.x) # 1 1 1 Child1.x = 2 print(Parent.x, Child1.x, Child2.x) # 1 2 1 Parent.x = 3 print(Parent.x, Child1.x, Child2.x) # 3 2 3 # 结果: 1 1 1 1 2 1 3 2 3
21.下述代码新式类与新式类的查找顺序是什么?
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D, E): def test(self): print('from F') pass # python3中校验: FD->DB->FE->EC->CA # python2中校验: FD->DB->BA->FE->EC
22.什么是组合?为什么要使用组合?
组合指的是一个对象中,包含另一个或多个对象。
23.什么是封装?
隐藏对象的属性和实现细节,仅对外提供公共访问方式
24.什么是访问限制机制?
在内部在属性前加'__',使属性私有化。实际上是内部替换了变量名称 方法名 替换为:_类名__方法名
25.访问限制机制的优点?
1.让一些关键的数据,变成私有更加的安全 2.不是随意可以更改的 3.在属性,和方法前面加’__‘,变成私有,那么外界就不可以直接调用修改。 4.但是:在类的内部可以定义一个函数,方法调用修改。使用者直接调用这个函数就可以了。这个函数就是接口 5.可以在这个函数、方法加条件限制,而不是任意的改动
26.什么是property?为什么要使用property?
让使用者调用方式一致,是一个内置的装饰器。 使用了property内置装饰器之后,使用者调用方法时少了一个括号,导致看起来像获取某个方法,而不是加括号执行某个函数
27.输入半径,计算圆的面积、周长
第一种方式:类绑定
import math class Circular(): # 计算面积 @classmethod def area(self,randius): res = math.pi * math.pow(randius, 2) print(f'面积为:{res}') #计算周长 @classmethod def perimeter(self, randius): res = 2 * math.pi * randius print(f'周长为:{res}') Circular.area(10) Circular.perimeter(10) # 结果: 面积为:314.1592653589793 周长为:62.83185307179586
第二种方式:对象绑定
import math class Circular(): def __init__(self, randius): self.randius = randius # 计算面积 @property def area(self): res = math.pi * math.pow(self.randius, 2) print(f'面积为:{res}') # 计算周长 @property def perimeter(self): res = 2 * math.pi * self.randius print(f'周长为:{res}') # 生成对象 A = Circular(10) # 执行 A.area A.perimeter # 结果: 面积为:314.1592653589793 周长为:62.83185307179586
28、使用abc模块定义一个Phone手机抽象类,让所有子类都继承手机抽象类,让不同牌子的手机都必须遵循抽象类手机打电话的步骤。
# @abc.abstractmethod子类必须按照父类的方法编写 import abc class Phone(): @abc.abstractmethod def call(self): pass class Xiaomi(Phone): def call(self): print('小米手机正在打电话!') class Iphone(Phone): def call(self): print('我是闪亮苹果BB机,正在打电话!') # 产生对象 iphone = Iphone() xiaomi = Xiaomi() # 执行 iphone.call() xiaomi.call() # 结果: 我是闪亮苹果BB机,正在打电话! 小米手机正在打电话!
29 上传下载电影
服务端:
import socket import json import struct import os server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) conn, addr = server.accept() def unload(): while True: try: hand_dict = conn.recv(4) len_dict = struct.unpack('i', hand_dict)[0] dict_json = conn.recv(len_dict) dict = json.loads(dict_json.decode('utf-8')) move_size = dict['move_size'] accept_size = 0 with open(dict['move_name'], 'wb')as f: while accept_size < move_size: accept = conn.recv(1024) f.write(accept) accept_size += len(accept) print('上传成功!') except StopIteration as f: print(f) break def load(): while True: try: DATA_PATH = os.path.dirname(__file__) MOVE_PATH = os.path.join(DATA_PATH) # 把电影列表打包传给客户端 move_list = os.listdir(MOVE_PATH) move_list_json = json.dumps(move_list).encode('utf-8') hand_dict = struct.pack('i', len(move_list_json)) # 发送报头 conn.send(hand_dict) # 发送json格式真实电影列表 conn.send(move_list_json) # 接收客户选择要下载的电影编号 4个字节接受编号,足够 choice = conn.recv(4) choice = int(choice.decode('utf-8')) # 根根选择,拿到电影名 move_name = move_list[choice] # 拼接选择的电影路径 move_name_path = os.path.join(MOVE_PATH, move_name) # 电影大小 move_size = os.path.getsize(move_name_path) # 做成字典 move_dict = {'move_name': move_name, 'move_size': move_size} # 序列化 move_json = json.dumps(move_dict).encode('utf-8') hand_dict = struct.pack('i', len(move_json)) # 发送报头,和json格式字典 conn.send(hand_dict) conn.send(move_json) with open(move_name_path, 'rb')as f: for i in f: conn.send(i) print('下载成功!') except StopIteration as f: print(f) break def run(): res = conn.recv(4) res = res.decode('utf-8') if res == '1': unload() elif res == '2': load() run() server.close()
客户端:
import socket import json import os import struct client = socket.socket() client.connect(('127.0.0.1', 8080)) # 上传电影 def unload(): while True: print('---下载电影---') # 拼接路径 MOVE_PATH = os.path.join('D:\PS素材') move_list = os.listdir(MOVE_PATH) for index, move_name in enumerate(move_list): print(index, move_name) choice = input('请选择电影编号(q.退出):').strip() if choice == 'q': break if not choice.isdigit(): print('输入数字!') continue choice = int(choice) if choice not in range(len(move_list)): print('不在范围!') continue move_name = move_list[choice] move_name_path = os.path.join(MOVE_PATH, move_name) move_size = os.path.getsize(move_name_path) move_dict = {'move_name': move_name, 'move_size': move_size} move_json = json.dumps(move_dict).encode('utf-8') hand_dict = struct.pack('i', len(move_json)) client.send(hand_dict) client.send(move_json) with open(move_name_path, 'rb')as f: for i in f: client.send(i) print('上传成功!') # 下载电影 def load(): while True: print('---下载电影---') hand_dict = client.recv(4) len_dict = struct.unpack('i', hand_dict)[0] # 接收了json格式的列表 dict_json = client.recv(len_dict) # 解码电影列表 move_list = json.loads(dict_json.decode('utf-8')) # 打印列表,展示 for index, move_name in enumerate(move_list): print(index, move_name) while True: choice = input('选择你要下载的电影编号 (q.退出):').strip() if choice == 'q': run() if not choice.isdigit(): print('输入数字!') continue choice = int(choice) if choice not in range(len(move_list)): print('输入不规范!') continue # 如果输入规范,把用户选择的编号传给客户端 choice = str(choice).encode('utf-8') client.send(choice) hand_dict = client.recv(4) len_dict = struct.unpack('i', hand_dict)[0] dict_json = client.recv(len_dict) dict = json.loads(dict_json.decode('utf-8')) move_size = dict['move_size'] accept_size = 0 with open(dict['move_name'], 'wb')as f: while accept_size < move_size: accept = client.recv(1024) f.write(accept) accept_size += len(accept) print('下载成功!') continue def run(): while True: print(''' 1:【上传电影】 2:【下载电影】 q:退出 ''') choice = input('请选择功能:').strip() if choice == '1': client.send(choice.encode('utf-8')) unload() elif choice == '2': client.send(choice.encode('utf-8')) load() elif choice == 'q': break else: print('输入不规范!') continue if __name__ == '__main__': run()
30.二进制转其他字符类型:
int 其他进制转十进制 a = int('0b1010011010', 2) b = int('0o1232', 8) c = int('0x29a', 16) print(a,b,c) # 结果: 666 666 666 bin 十进制转二进制 aa = bin(666) print(aa) # 结果 :0b1010011010 oct 十进制转八进制 bb = oct(666) print(bb) # 结果 :0o1232 oct 十进制转八进制 bb = oct(666) print(bb) # 结果 :0o1232
31.decode、endoce
第一种: res = a.encode('utf-8') # 编码 print(res.decode('utf-8')) # 解码 第二种: res1 = bytes(a, encoding='utf-8') # 编码二进制 res2 = str(res1, encoding='utf-8') # 解码二进制