文章目录
这篇博客会经常性地持续更新,记录使用python过程中的一些琐碎技能
类成员变量和对象成员变量
class A():
name = "caixukun"
def __init__(self):
self.name = "changtiaorap"
if __name__ == "__main__":
a = A()
print(A.name)
print(a.name)
输出
caixukun
changtiaorap
这说明:
- 在方法外定义的变量属于类成员变量,不从属于任何一个对象实例
- 在构造方法内通过
self.
构造的变量属于对象成员变量 - 如果对象成员变量和类成员变量同名,则通过对象实例访问的变量是对象成员变量,否则是类成员变量。
在python中,基础类型没有枚举。模仿枚举的方式往往采用类成员变量模拟:
class CityPopulation():
shenzhen = 818.11
shanghai = 972.69
beijing = 794.3
chengdu = 437
wenzhou = 297
xiamen = 221.02
python的伪多线程
python的多线程一直是一个令人诟病的问题,原因就是因为python的多线程是一个伪多线程,意思是说,尽管是多线程在运行,实际上仍然是单核CPU上的时间片轮询。无论你使用了多少多线程,python始终只能利用一个CPU核。造成这种现象的原因在于CPython解释器中大名鼎鼎的全局锁(GIL)(当然,其他python解释器也可能会有)。
在上世纪,CPython解释器诞生的年代,并没有期待往后的计算机性能会有如此大的进步。GIL的出现主要是为了解决线程安全问题。然而。在如今,多线程的编写已经司空见惯,但是python的GIL阻止了python使用者去编写一个性能良好的程序。
其实在上世纪末,1999年,有人创建了一个python分支去专门试图移除GIL。下面是python创始人 Guido Van Rossum的一段话:
This has been tried before, with disappointing results, which is why I’m reluctant to put much effort into it myself. In 1999 Greg Stein (with Mark Hammond?) produced a fork of Python (1.5 I believe) that removed the GIL, replacing it with fine-grained locks on all mutable data structures. He also submitted patches that removed many of the reliances on global mutable data structures, which I accepted. However, after benchmarking, it was shown that even on the platform with the fastest locking primitive (Windows at the time) it slowed down single-threaded execution nearly two-fold, meaning that on two CPUs, you could get just a little more work done without the GIL than on a single CPU with the GIL. This wasn’t enough, and Greg’s patch disappeared into oblivion. (See Greg’s writeup on the performance.)
这次的尝试以惨败告终,移除GIL后的性能比单线程应用慢了近两倍。于是,他干脆直接说不必花太大的精力在GIL上。而面对不断被询问的多线程问题,python的专家们也精心准备了一个答案:
不要使用多线程,用多进程代替
然而,进程的创建和进程间通信使得在很多场合性能不如多线程。这意味着python从一开始就与高性能三字无缘。
在python 4.0的预计推出的新特性列表中,有这么一条:
The GIL has been removed
是不是非常地开心呢?
然而,这一条的下面一条,是这样的:
Just kidding! Instead we’ve been focusing all our effort on making it easier to juggle multiple interpreter data-structures within a single thread. No, no, you can thank us later!
这种无奈的玩笑,大概只有python的维护者们真正懂。python 4.0 预计推出的新特性链接点这里
在未来,Rust会因为安全而火起来,而golang会因为高性能变得更火。
python之读取Excel
读取Excel需要使用模块xlrd
,这个模块的安装,直接pip install xlrd
就好了。
读取一个Excel数据需要两个数据,一个是Excel表的路径 ,一个是sheet名称。下面书写一个接口,接受这两个数据,将对应的Excel中对应的Sheet表的所有数据读取到一张二维list中。
def read_excel(xls_path, sheet_name):
wb = xlrd.open_workbook(xls_path) # 打开Excel表格
sheet = wb.sheet_by_name(sheet_name) # 打开其中一张Sheet
cols = sheet.ncols # 列
rows = sheet.nrows # 行
sheet_list = []
for i in range(rows): # 逐行读取
row_list = []
for j in range(cols):
row_list.append(sheet.cell(i, j).value)
sheet_list.append(row_list)
return sheet_list
python之写入Excel
写入Excel需要导入xlsxwriter包,直接使用pip install xlsxwriter
进行安装。
关于这个包的使用,强烈建议阅读官方文档。这里我将简略展示我用到的关于xlsxwriter的部分功能,其中包括:
- 打开和关闭表格
- 写入数据
- 插入图表
- 简单的插入数据
import xlsxwriter
wb = xlsxwriter.Workbook('NewExcel.xlsx') # 打开表格
sheet = wb.add_worksheet('Sheet1') # 打开工作表
# 写入一行或一列数据
data = [1,2,3]
data2 = (4,5,6)
sheet.write_column('A11', data) # data 需要是可迭代对象
sheet.write_row('B11', data2)
sheet.set_column('A:J', 20) # 设置A到J所在列宽度为20
# 为单元格设置格式
wb_format = wb.add_format({
'bold': True, # 加粗
'border': 2, # 边框
'align': 'center', # 水平对齐
'valign': 'vcenter', # 垂直对齐
'fg_color': '#6D92f6' # 颜色
})
# 带格式的写入
sheet.write('A3', '服务器版本', wb_format)
# 合并单元格
sheet.merge_range('A1:J2', '总体情况', wb_format)
wb.close() # 必须有这一步,而且是直到这一步,上面的所有操作才会执行
- 插入图表
import xlsxwriter
# 打开表格
wb = xlsxwriter.Workbook('2807年 地球人口统计.xlsx') # 打开表格
sheet = wb.add_worksheet('第一次普查') # 打开工作表
# 定义数据
category = ['男人', '女人','中性人','外星人']
value = [23.45, 23.03, 12.71, 45.34] # 单位 亿
# 写入数据
sheet.write_column('A1', category)
sheet.write_column('B1', value)
# 定义图表
chart = wb.add_chart({'type': 'pie'}) # 这里pie表示绘制饼状图,还有更多的类型
chart.add_series({
'categories': '=第一次普查!$A$1:$A$4',
'values': '=第一次普查!$B$1:$B$4',
'data_labels': {'category': True, 'percentage': True, 'leader_lines': True} # 分别显示:类别名, 百分比, 引导线
})
chart.set_title({'name': '第一次普查结果'})
chart.set_size({'x_scale': 2, 'y_scale': 2}) # 这里表示以默认大小的两倍显示
chart.set_style(10)
# 插入图表
sheet.insert_chart('C1', chart)
wb.close() # 必须有这一步,而且是直到这一步,上面的所有操作才会执行
Mysql的安装和导入csv文件
当我再次操起Mysql的时候,Mysql已经被Oracle收购了。所以现在想要下载Mysql,首先得上Oracle官网。然而,自从不知道什么时候开始,下载Java sdk也需要登录Oracle之后,我对Oracle的官网总是有种莫名的恐惧。尽管全球为开源社区贡献榜单中Oracle公司名列前茅,但是大家似乎都在担心Mysql因此变得不开源。
另外这个问题放在这儿,是考虑以后可能会使用python操作数据库的需求。与其再建一个“数据库学习”博客,不如就写在这儿。
社区版的下载链接在 这
下载好msi之后,一路安装,不是点next,就是点Excute,或者finish。总而言之,对于新手来说,没有什么值得配置的地方。
那么这次的问题在于,MySql导入带有中文的CSV会有各种问题。
- 中文编码问题
- 权限问题
- 头部去除问题
这些问题对于老手而言很简单,然而对于我这样的新手,可是花了不小功夫去查资料解决。
首先假设我们已经有了一个名为DB
的数据库和名为my_data
的表。然后按照网上的教程,在Mysql workbench左侧右键表,点击table data import wizard
,打开数据导入向导页面。然后选择文件路径,开始导入。然后出错了。噢,编码问题。再按照网上套路,打开记事本,另存csv文件,选择编码utf-8。再按流程来一遍,还是出错。显然utf-8格式压根儿不对,因为中文编码基本上就是gb2312。可惜Mysql不提供这种编码方式的导入。然后网上又推荐使用navicat for mysql
导入csv。于是我就为了导入一个中文编码的文件,还要费尽周章下载一个额外的软件,还是付费的!
解决方法使用load data infile
语句。用sql语句导入,同时指定导入时的编码。
load data infile 'D:/files/data.csv'
into table my_data character set gb2312
fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\r\n';
这里要注意文件名的路径分隔符建议用/
,如果你在windows底下用\
,一定要记得用\\
。
到这里呢,还报错,说数据库运行在secure-file-priv
模式下,这个命令不允许执行。原因在于,MySql的配置里有一个secure-file-priv
。它的值如果不为空(默认是一个路径),则只能从这个路径下读取文件。
解决方法是把它改为空值。配置文件是C:\ProgramData\MySQL\MySQL Server 8.0\my.ini
。找到这一项,然后=""
就好了。
现在重启电脑(或者如果你会重启Mysql服务的话),运行脚本。还报错,不过显然文件可以读取了。错误显示读取的数据跟表定义的数据格式不符。原因在于,csv文件通常有开头一行不属于“数据”范畴,它是这些数据的“headers”,用来定义每一列数据的具体含义。或者有时候有更多行。但是Mysql读取的时候,是从第一行读取,不会帮你识别和忽略。解决办法是在sql语句后面加一句ignore 1 lines
,用来忽略第一行。
load data infile 'D:/files/data.csv'
into table my_data character set gb2312
fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\r\n' ignore 1 lines;
python 之 json 模块
import json
d = {"name":"qtc", "age":3, "tall":1.66, "girl_friend":{"name":"fanbingbing", "age":40, "tall":1.8}}
ret = json.dumps(d) # 将字典转化成字符串
将json字符串格式化打印:
j = json.dumps(json.loads(msg), indent=4)
python 之文件解压缩
import zipfile
# 解压文件
zfile = zipfile.ZipFile("origin_file.zip", "r")
zfile.extractall("./")
zfile.close()
# 压缩文件
files = os.listdir("./logs")
with zipfile.ZipFile("myzip.zip", mode="w", compression=zipfile.ZIP_LZMA, allowZip64=True) as f:
for file in files:
f.write(f"./logs/{file}", arcname=file)