python 全栈开发,Day26(hashlib文件一致性,configparser,logging,collections模块,deque,OrderedDict)
一、hashlib文件一致性校验
为何要进行文件一致性校验?
为了确保你得到的文件是正确的版本,而没有被注入病毒和木马程序。例如我们经常在网上下载软件,而这些软件已经被注入了一些广告和病毒等,如果不进行文件与原始发布商的一致性校验的话,可能会给我们带来一定的损失。
文件一致性校验原理
要进行文件的一致性校验,我们不可能像文本文件比较那样,将两个文件放到一起对比,因为很多的时候文件很大。目前最理想的办法就是,是通过加密算法,对文件生成对应的值,通过生成的值与发布商提供的值比较来确认两个文件是否一致。
MD5和SHA1就是目前使用最为广泛的良种加密算法。
举例:
先手动创建2个文件,file1和file2,内容为123
使用md5计算file1的加密值
import hashlib
md5obj = hashlib.md5() # 创建md5对象
with open('file1','rb') as f:
content = f.read() # 读取文件所有内容
md5obj.update(content)
print(md5obj.hexdigest())
执行输出:
202cb962ac59075b964b07152d234b70
再计算fiel2的加密值,再把上面的代码复制一遍?太low了,如果有多个文件怎么办?
定义一个方法
import hashlib
def check(filename):
md5obj = hashlib.md5() # 创建md5对象
with open(filename,'rb') as f:
content = f.read() # 读取文件所有内容
md5obj.update(content)
return md5obj.hexdigest() ret1 = check('file1')
ret2 = check('file2')
print(ret1)
print(ret2)
执行输出:
202cb962ac59075b964b07152d234b70
202cb962ac59075b964b07152d234b70
从结果上,可以看出是一致的。
修改file2的内容,改成123456
再次校验,执行输出
202cb962ac59075b964b07152d234b70
e10adc3949ba59abbe56e057f20f883e
就可以知道,文件内容不一致了。
但是上面的方法,有一个缺陷,当文件达到GB级别的时候,内存会爆炸
那怎么办呢?先来讲一个小例子
import hashlib
md5obj = hashlib.md5() # 创建md5对象
md5obj.update(b'alex sb') # b'string' 表示bytes类型,不能有中文符号
print(md5obj.hexdigest())
执行输出:
3eae6f4760a98a52891a109face75648
拆分字符串
import hashlib
md5obj = hashlib.md5() # 创建md5对象
md5obj.update(b'alex ') # 拆分字符串
md5obj.update(b'sb') #
print(md5obj.hexdigest())
执行输出:
3eae6f4760a98a52891a109face75648
可以看出2个结果是一样的
结论
一段字符串直接进行摘要和分成几段摘要的结果是相同的
那么就可以把大文件,分段进行md5加密,就可以了
下载一部电影《海上钢琴师》,文件有1.58GB
本片讲述了一个钢琴天才传奇的一生。 豆瓣评分9.2
计算电影的md5值
import hashlib
def check(filename):
md5obj = hashlib.md5()
with open(filename,'rb') as f:
while True:
content = f.read(1048576) # 每次读取1048576字节,也就是1MB
if content:
md5obj.update(content)
else:
break # 当内容为空时,终止循环
return md5obj.hexdigest() ret1 = check('E:\迅雷下载\[迅雷下载www.2tu.cc]海上钢琴师.BD1280高清中英双字.rmvb')
print(ret1)
花费了9秒,执行输出:
30c7f078203d761d3f13bec6f8fd3088
一次性校验,对算法要求没有那么高,用md5就足够了。
总结:
序列化 把数据类型变成字符串
为什么要有序列化 因为在网络上和文件中能存在的只有字节
json 在所有语言中通用 只对有限的数据类型进行序列化 字典 列表 字符串 数字 元组
在多次写入dump数据进入文件的时候,不能通过load来取。
pickle 只能在python中使用 对绝大多数数据类型都可以进行序列化
在load的时候,必须拥有被load数据类型对应的类在内存里
dumps 序列化
loads 反序列化
dump 直接向文件中序列化
load 直接对文件反序列化
shelve
f = open() 打开文件
json和pickle 必须熟练掌握
二、configparser
该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。
创建文件
来看一个好多软件的常见文档格式如下:
section称之为节点,节点里面的赋值对,称之为项
如果想用python生成一个这样的文档怎么做呢?
import configparser config = configparser.ConfigParser() #创建一个ConfigParser对象 config["DEFAULT"] = {'ServerAliveInterval': '45', #默认参数
'Compression': 'yes',
'CompressionLevel': '9',
'ForwardX11':'yes'
}
config['bitbucket.org'] = {'User':'hg'} #添加一个节点bitbucket.org
config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'} with open('example.ini', 'w') as configfile: #写入配置文件example.ini
config.write(configfile)
执行程序,查看example.ini的内容
[DEFAULT]
serveraliveinterval = 45
forwardx11 = yes
compression = yes
compressionlevel = 9 [bitbucket.org]
user = hg [topsecret.server.com]
forwardx11 = no
host port = 50022
可以看出节点的项,都变成小写了。
这是因为它在写入的时候,将所有字符串使用了lower()方法,转换为小写了。
查找文件
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
###上面内容为固定部分###
print(config.sections()) # 查看所有的节点,但默认不显示DEFAULT,返回列表
执行输出:
['bitbucket.org', 'topsecret.server.com']
下面的代码,固定部分我就不贴了
print('bitbucket.org' in config) # 验证某个节点是否在文件中
执行输出: True
print(config['bitbucket.org']['user']) # 查看某节点下面的某个项的值
执行输出: hg
print(config['bitbucket.org']) # 输出一个可迭代对象
执行输出: <Section: bitbucket.org>
#使用for循环一个可迭代对象
for key in config['bitbucket.org']: # 注意,有default时,会默认输出它的键
print(key)
执行输出:
user
serveraliveinterval
forwardx11
compression
compressionlevel
print(config.items('bitbucket.org')) # 找到'bitbucket.org'下所有的键值对
执行输出:
[('serveraliveinterval', '45'), ('forwardx11', 'yes'), ('compression', 'yes'), ('compressionlevel', '9'), ('user', 'hg')]
print(config.get('bitbucket.org','compression')) # get方法section下的key对应的value
执行输出: yes
增删改操作
增加一个节点
print(config.add_section('yuan')) # 增加一个节点
注意,它不会立即写入!必须执行下面的代码
config.write(open('example.ini', "w")) # 写入文件
open('example.ini',w) 表示清空文件
config.write 表示写入内容
再次查看文件内容:
[DEFAULT]
serveraliveinterval = 45
forwardx11 = yes
compression = yes
compressionlevel = 9 [bitbucket.org]
user = hg [topsecret.server.com]
forwardx11 = no
host port = 50022 [yuan]
删除一个节点
config.remove_section('bitbucket.org')
config.write(open('example.ini', "w")) # 写入文件
修改节点
config.set('yuan','k2','222') # yuan节点增加项k2 = 222
config.write(open('example.ini', "w")) # 写入文件
总结:
section 可以直接操作它的对象来获取所有的节信息
option 可以通过找到的节来查看多有的项
三、logging
为了保护数据安全
所有的增加,修改,删除操作,都要记录日志
比如log日志,管理员操作日志,消费记录...
日志给我们在内部操作的时候提供很多遍历
日志给用户提供更多的信息
在程序使用的过程中自己调试需要看的信息
帮助程序员排查程序的问题
logging模块 不会自动帮你添加日志的内容
你自己想打印什么 你就写什么
import logging
logging.debug('debug message') # debug 调试模式 级别最低
logging.info('info message') # info 显示正常信息
logging.warning('warning message') # warning 显示警告信息
logging.error('error message') # error 显示错误信息
logging.critical('critical message') # critical 显示验证错误信息
执行输出:
显示红色字体
root表示当前文件的权限
为啥少了2个?这个问题先放一边
logging 有2种配置形式
简单配置
配置logger对象
这2种形式是完全独立的
使用简单配置,局限性比较大
简单模式:默认情况下 只显示 警告 及警告级别以上信息
如果想显示debug,需要调整告警级别
import logging
logging.basicConfig(level=logging.DEBUG) # 设置警告级别为debug
logging.debug('debug message') # debug 调试模式 级别最低
logging.info('info message') # info 显示正常信息
logging.warning('warning message') # warning 显示警告信息
logging.error('error message') # error 显示错误信息
logging.critical('critical message') # critical 显示验证错误信息
执行输出:
设置info,只显示info以上的错误
能不能只显示一种级别信息呢?不行!
只能打印某个级别以上的信息
增加时间显示
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
logging.debug('debug message') # debug 调试模式 级别最低
logging.info('info message') # info 显示正常信息
logging.warning('warning message') # warning 显示警告信息
logging.error('error message') # error 显示错误信息
logging.critical('critical message') # critical 显示验证错误信息
执行输出:
2018-04-23 19:43:56,982 testt.py[line:58] DEBUG debug message
2018-04-23 19:43:56,982 testt.py[line:59] INFO info message
2018-04-23 19:43:56,982 testt.py[line:60] WARNING warning message
2018-04-23 19:43:56,982 testt.py[line:61] ERROR error message
2018-04-23 19:43:56,982 testt.py[line:62] CRITICAL critical message
设置时间格式
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s'),
datefmt = '%a, %d %b %y %H:%M:%S',
logging.debug('debug message') # debug 调试模式 级别最低
logging.info('info message') # info 显示正常信息
logging.warning('warning message') # warning 显示警告信息
logging.error('error message') # error 显示错误信息
logging.critical('critical message') # critical 显示验证错误信息
执行输出:
2018-04-23 19:46:01,727 testt.py[line:59] DEBUG debug message
2018-04-23 19:46:01,727 testt.py[line:60] INFO info message
2018-04-23 19:46:01,727 testt.py[line:61] WARNING warning message
2018-04-23 19:46:01,727 testt.py[line:62] ERROR error message
2018-04-23 19:46:01,727 testt.py[line:63] CRITICAL critical message
配置参数
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有: filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息
写入文件
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %y %H:%M:%S',
filename = 'userinfo.log'
)
logging.debug('debug message') # debug 调试模式 级别最低
logging.info('info message') # info 显示正常信息
logging.warning('warning message') # warning 显示警告信息
logging.error('error message') # error 显示错误信息
logging.critical('critical message') # critical 显示验证错误信息
执行程序,查看文件内容
某些情况下,查看文件是乱码的。
它的局限性有2个
编码格式不能设置
不能同时输出到文件和屏幕
loggin对象方式
由于简单配置有局限性,logging对象方式更为灵活
import logging
logger = logging.getLogger() # 实例化了一个logger对象
#在国外叫handler,在中国翻译过来,叫句柄
#设置文件名和编码
fh = logging.FileHandler('test.log',encoding='utf-8') # 实例化了一个文件句柄
sh = logging.StreamHandler() # 用于输出到控制台
#吸星大法
logger.addHandler(fh) # 吸收写文件功能
logger.addHandler(sh) # 吸收输出屏幕功能
logger.warning('warning message')
执行输出:
warning message
查看文件内容,也是
warning message
这样就具备了同时写入文件以及输出屏幕的技能
增加输出格式功能
import logging
logger = logging.getLogger() # 实例化了一个logger对象
#在国外叫handler,在中国翻译过来,叫句柄
#设置文件名和编码
fh = logging.FileHandler('test.log',encoding='utf-8') # 实例化了一个文件句柄 # 格式和文件句柄或者屏幕句柄关联
sh = logging.StreamHandler() # 用于输出到控制台 fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 格式化
fh.setFormatter(fmt) # 格式和文件句柄或者屏幕句柄关联
sh.setFormatter(fmt) #吸星大法
logger.addHandler(fh) # 吸收写文件功能 和logger关联的只有句柄
logger.addHandler(sh) # 吸收输出屏幕功能
logger.setLevel(logging.DEBUG) # 设置警告级别为debug,此处DEBUG源码为DEBUG = 10 logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
执行输出:
2018-04-23 20:16:58,850 - root - DEBUG - debug message
2018-04-23 20:16:58,850 - root - INFO - info message
2018-04-23 20:16:58,850 - root - WARNING - warning message
查看文件内容,也是一样的。
那么为什么不能Logger来吸?
因为要解耦
写入和屏幕输出,可以不同
比如:
有一个需求,文件记录所有级别信息,屏幕只显示错误信息
那么解耦就很有必要了。
总结:
logging
logging 是记录日志的模块
它不能自己打印内容 只能根据程序员写的代码来完成功能
logging模块提供5中日志级别,从低到高一次:debug info warning error critical
默认从warning模式开始显示
只显示一些基础信息,我们还可以对显示的格式做一些配置
简单配置 配置格式 basicCondfig
问题:编码问题,不能同时输出到文件和屏幕
logger对象配置
高可定制化
首先创造logger对象
创造文件句柄 屏幕句柄
创造格式
使用文件句柄和屏幕句柄 绑定格式
logger对象和句柄关联
logger.setLevel
使用的时候 logger.debug
四、collections模块
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
namedtuple
我们知道tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成:
p = (1, 2)
但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。
这时,namedtuple就派上了用场:
from collections import namedtuple
coordinate = namedtuple('Point',['x','y']) # 定义一个namedtuple类型Point,并包含x,y属性。
p = coordinate(1,2) #创建一个p对象
print(p)
print(p.x) # 获取x属性
print(p.y) # 获取y属性
执行输出:
Point(x=1, y=2)
1
2
Point的名字,可以随便定义,它不是关键字
使用名字来取值,代码更清晰
这段代码,类似于面向对象,但是里面的属性不能修改,毕竟它是一个特殊的元组
修改属性值
from collections import namedtuple
coordinate = namedtuple('Point',['x','y']) # 定义一个namedtuple类型Point,并包含x,y属性。
p = coordinate(1,2) #创建一个p对象
print(p)
print(p.x) # 获取x属性
print(p.y) # 获取y属性
p.x = 4 # 修改值
print(p.x)
执行报错:
p.x = 4
AttributeError: can't set attribute
看下面的代码,可读性比较差
p1 = (0,1) # 表示x和y
p2 = (0,2)
如果使用p.x和p.y分别表示x和y坐标,就比较清晰明了
应用场景
time模块
面向对象进阶,纸牌游戏
五、deque
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque
#双端队列 import queue
#队列 先进先出 fifo
#计算机数据结构模型
#先进先出 # 栈 先进后出
队列,内部维护了严格的顺序
不能跳着取,必须一个一个取。
栈,先从后面取,写入也是从后面写
双端
可以从左边取,也可以从右边取
但是不能从中间取
from collections import deque
#双端队列
dq = deque()
dq.append(1) # 往右边添加一个元素
dq.append(2)
dq.appendleft(3) # 往左边添加一个元素
print(dq)
print(dq.pop()) # 获取最右边一个元素,并在队列中删除
print(dq.popleft()) # 获取最左边一个元素,并在队列中删除
执行输出:
deque([3, 1, 2])
2
3
队列是为了维护秩序的,
如果需要用到增删改查,不适合用队列
比如抢票,秒杀,会用到队列
比如500个,同时请求服务器,那么将这些人,放到队列中
队列它是有顺序的,即是是同一秒,也可以区分谁第一
那么前10个,就可以抢到票了,
不能打乱它的顺序
六、OrderedDict
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict:
自动维护key的顺序,顺序
那么这个列表的顺序就固定了
dic = {'k1':'v1','k2':'v1','k3':'v1','k4':'v1'}
keys = list(dic.keys()) # 转换为列表,那么顺序就固定了
print(keys)
for k in keys:
print(k,dic[k])
执行输出:
['k2', 'k3', 'k4', 'k1']
k2 v1
k3 v1
k4 v1
k1 v1
上面的代码有缺点,它不能维护k1,k2,k3,k4的顺序
下面介绍有序的字典
dic = dict([('k1','v1'),('k2','v2')]) # 使用列表固定了顺序
print(dic)
执行输出
{'k1': 'v1', 'k2': 'v2'}
使用OrderedDict固定顺序
它内部,维护了一个列表
注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:
from collections import OrderedDict
dic = OrderedDict([('k1','v1'),('k2','v2')])
print(dic)
执行输出:
{'k1': 'v1', 'k2': 'v2'}
再增加key,是从后面加
今日作业
写一个函数
参数是两个文件的路径
返回的结果是True/False
答案:
import hashlib def compare(f1,f2): # 校验2个文件是否一致
def check(filename): # 计算文件的md5值
md5obj = hashlib.md5()
with open(filename, 'rb') as f:
while True:
content = f.read(1048576) # 每次读取1048576字节,也就是1MB
if content:
md5obj.update(content)
else:
break # 当内容为空时,终止循环
return md5obj.hexdigest() f_1 = check(f1) # 计算f1的md5
f_2 = check(f2)
if f_1 == f_2: # 判断md5值
return True
else:
return False ret = compare('file1','file2') # 校验2个已经存在的文件是否一致
print(ret)
老师的代码:
import hashlib
def compare(filename1,filename2):
md5sum = []
for file in [filename1,filename2]:
md5 = hashlib.md5()
with open(file,'rb') as f:
while True:
content = f.read(1024)
if content:
md5.update(content)
else:break
md5sum.append(md5.hexdigest())
if md5sum[0] == md5sum[1]:return True
else :return False
print(compare('f1','f2'))
明日默写:
import logging logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8') # 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG) fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch) logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
python 全栈开发,Day26(hashlib文件一致性,configparser,logging,collections模块,deque,OrderedDict)的更多相关文章
- python 全栈开发,Day8(文件操作)
一.文件操作流程 文件以什么编码存储的,就以什么编码打开 参数: 1.文件路径 2.编码方式,encode 3.执行动作(打开方式):只读,只写,追加,读写,写读... 打开一个已经存在的文件 f = ...
- python全栈开发_day9_脚本文件和函数的基本运用
一:脚本文件 1)脚本文件的操作 import sys p=sys.argv print(p) #将python代码放到cmd中运行,在后面添加参数,会自动保存在输出的列表中,默认输出的列表中只有一个 ...
- python全栈开发:hashlib加密
哈希加密代码 #!/usr/bin/env python # -*- coding;utf-8 -*- """ 哈希加密模块中有很多算法,调用不同的算法执行不同的加密, ...
- python 全栈开发,Day43(引子,协程介绍,Greenlet模块,Gevent模块,Gevent之同步与异步)
昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...
- 巨蟒python全栈开发-第11阶段 ansible3_2入门八个模块
大纲: 1.file模块 2.fetch模块 3.yum&&pip模块 4.service模块 5.cron模块 6.user模块 7.group模块
- 巨蟒python全栈开发-第11阶段 ansible3_1入门四个模块command&shell&script©
大纲 1.系统安装与机器克隆 2.ansible介绍和host-pattern格式 3.command模块 4.shell模块 5.script模块 6.copy模块
- python全栈开发学习_内容目录及链接
python全栈开发学习_day1_计算机五大组成部分及操作系统 python全栈开发学习_day2_语言种类及变量 python全栈开发_day3_数据类型,输入输出及运算符 python全栈开发_ ...
- Python全栈开发【模块】
Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...
- Python全栈开发【基础三】
Python全栈开发[基础三] 本节内容: 函数(全局与局部变量) 递归 内置函数 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 def 函数名(参数): ... 函数体 . ...
随机推荐
- 8、JPA-映射-双向一对一
一个管理对应一个部门,一个部门对应一个管理,例中由部门维护关联关系 实体类 Department package com.jpa.yingshe; import javax.persistence.* ...
- python---memcache使用操作
import memcache mc = memcache.Client(['127.0.0.1:8081'],debug=True) mc.set("key","val ...
- javascript 函数的4种调用模式
1. 函数模式 // this 指向 window 全局对象 2. 方法模式 // this 指向调用这个方法的对象 3. 构造函数模式 // this 指向 new 新创建出来的实例 4. 上下文模 ...
- synchronized实现原理
线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据.因此为了解决这个问题,我们可能需要这样一个方案, ...
- HDU - 5117 Fluorescent(状压dp+思维)
原题链接 题意 有N个灯和M个开关,每个开关控制着一些灯,如果按下某个开关,就会让对应的灯切换状态:问在每个开关按下与否的一共2^m情况下,每种状态下亮灯的个数的立方的和. 思路1.首先注意到N< ...
- FZU - 1989 AntiAC
Problem 1989 AntiAC Accept: 93 Submit: 444Time Limit: 4000 mSec Memory Limit : 32768 KB Prob ...
- Java编程思想 学习笔记12
十二.通过异常处理错误 Java的基本理念是“结构不佳的代码不能运行”. Java中的异常处理的目的在于通过使用少于目前数量的代码来简化大型.可靠的程序的生成,并且通过这种方式可以使你更加自信:你的 ...
- VUE2.0 饿了吗视频学习笔记(七-终):compute,循环,flex,display:table
一.star组件使用到了computed属性 computed相当于属性的一个实时计算,当对象的某个值改变的时候,会进行实时计算. computed: { starType() { return 's ...
- 腾讯云Unbuntu服务器安装桌面环境
进入命令行 1.sudo apt-get install xinit 2.sudo apt-get install gdm 3.sudo apt-get install ubuntu-desktop ...
- 15. Spring boot CRUD
一.列表页 templates/emp/list.html 0.侧边栏链接: <li class="nav-item"> <a class="nav-l ...