文章目录
Python 技巧
文件相关
读取文件
打开文件的话可以先写路径,再写open,open里面可以指定操作,编码等
path='./data.txt'
fb=open(path,encoding='UTF-8')
但是上面这种做法不常用,因为不能保证文件正常关闭,如果发生异常,缓冲区的内容可能不会写入,推荐下面这种方式:
with open(...) as fb:
然后读取文件操作,有四种方式,分别是read,readline,readlines
,最后是我常用的for line in fb:
需要注意的是,文件中如果某一行带有换行符,那么肯定会读入换行符,需要我们使用 strip()
方法丢弃字符串
read:
调用read()会一次性读取文件全部内容, 速度最快,但当数据过大时不适用。
readline:
使用readline()方法,逐行读取内容,返回结果为list。
with open('/path/to/file', 'r') as f:
line = f.readline()
while line:
line = f.readine() #这里只能读取一行数据
...
像上面这种就是readline的标准写法
readlines():
选择使用readlines()方法,一次性读取文本所有内容,返回结果为list,其中每个元素结尾有"\n"。该方法适合读取配置文件,速度较快,但是文本越大占用内存越大。
这种方法读取的文本内容,每行文本末尾都会带一个’\n’换行符 (可以使用L.rstrip(’\n’)去掉换行符)。注意,python中方法的调用返回的是一个副本,并不会对原有的元素进行修改,如果要修改末尾符号,需要处理赋值给新的字符串。
with open('/path/to/file', 'r') as f:
line = f.readlines()
for i in line:
lines.append(i.rstrip('\n'))
最后一种方法是我常用的,感觉是最简洁的写法
with open(...) as fb:
for line in fb: #读取文件中的内容
...
需要注意的是,如果文本文件中一行有回车符,读取进来的字符串始终带有回车符号,我们可以用str的strip操作去除回车符
line = fb.readline()
print(type(line))
print(line)
print(len(line))
line=line.strip('\n')
print(len(line))
输出:
<class 'str'>
戴相龙说中国经济发展为亚洲作出积极贡献 # 这里带有一个换行符
# 这是print自己的换行符
20 # 带有换行符的长度
19
strip之后回车符就去掉了
strip还有去除文本中指定字符的操作,不过只能左右两边,中间不能去除
文档关于strip的描述:
如果只想处理一边的话,有lstrip和rstrip方法。
另外如果读入进来的文本按照指定符号分割,可以用 split()
来按照指定符号来分割字符串,得到的是一个list
line = fb.readline()
print(line)
line=line.split()
print(line)
输出结果:
戴相 龙说中国经济发展为 亚洲作出 积极 贡献
['戴相', '龙说中国经济发展为', '亚洲作出', '积极', '贡献']
文件定位操作
介绍三个函数,一个seek,一个tell
使用seek方法可以很方便的定位当前的文件指针
一共有两个参数,第一个是是表示偏移量offset,可正可负,第二个参数可选,表示移动的起点,默认值为0,就是文件的初始处
fb.seek(0)可以把文件指针指向第一行,进行重复读取
使用tell方法会返回文件指针当前的位置
举一个例子:
如果当前有一个特别大的文本文件,不能一次性的读入内存,要求从键盘输入一个行号,然后立刻输出对应行的文本。 由于文件很大,不允许将文件内容全部放到内存中; 同时也不允许从头扫描 文件,得到对应行的文本,因为这样速度太慢
def func():
pos = 0
indexes = []
with open("bigfile.txt") as file:
while pos < path.getsize("bigfile.txt") - 1: # getsize返回文件总大小
indexes.append(pos) # 增加行号起点
content = file.readline() # 读入一行(只是不能一次性读入)
pos = file.tell() # 获取当前的文件指针,就是下一行的起始位置
print(indexes)
index = eval(input("请输入需要读取的行号(1~%d):" % len(indexes)))
if type(index) == int and 0 < index <= len(indexes): #判断一下是否越界
file.seek(indexes[index - 1])
content = file.readline()
print(content.rstrip("\n"))
else:
raise ValueError()
写入文件
写入文件我只用write,write接受一个字符串参数,写入到文件中,如fb.write(...)
需要注意的是write不会写入回车符,要自己手动加上
字符串相关
首先要知道str在python中是不可变数据对象,所以不能通过下标去修改值
3.6开始的新特性,字符串前面加一个f
之前很常用format,现在可以用f表达式,更简洁了
看样例
num=10
print(f'num is :{num}')
===result===
num is :10
还可以像原来的format一样加上格式控制
num=1234
print(f'num is : {num:>10.2f}')
===result===
num is : 1234.00
逆置str
利用切片可以快速逆置一个str s[::-1]
普通的reversed方法对str并不适用,转不回来 s=str(reversed(s))
如果你非要用的话可以这样''.join(reversed(s))
⬆
来自https://stackoverflow.com/questions/931092/reverse-a-string-in-python SO的回答
str转list,int
把字符串的每个元素存放到list中,直接转list即可
s='1234'
L=list(s)
print(L)
['1','2','3','4']
我们常常需要这种操作,将数字的每一位存放到一个list里面,例如: num:1234 => list:[1,2,3,4]
上面这种操作一行代码就能完成,也就是先转换成str , 1234=> ‘1234’ ,再对每一位求值(执行eval),然后得到[1,2,3,4]的map对象,最后手动转成list
list(map(eval,str(num))
字符串数字转int,直接转换即可,这么做的时候要确保str符合int数据规则,比如带有小数点就不行
n=int(s)
int还可指定转换的进制
s='0b1001'
print((int(s,base=2)) #结果是9
另外,python还内置了多个进制转换的函数:
# 获取用户输入十进制数
dec = int(input("输入数字:"))
print("十进制数为:", dec)
print("转换为二进制为:", bin(dec))
print("转换为八进制为:", oct(dec))
print("转换为十六进制为:", hex(dec))
搭配int和上面的bin,oct,hex可以实现常见的进制转换
按照规则分隔字符
利用join方法在字符串中每个元素之间插入空格
当然可以自己指定特定的字符
' '.join(s)
将list中的元素转成str
需要用到map函数和repr函数
map不太好解释,repr就是eval的逆操作,即把一串数字变为字符串
python是不折不扣的强类型程序语言,所以我们插入str的时候要把其它类型的值转成字符串
另外,这种写法是不行的 s2=str(map(repr,L))
,s2会指向生成的map对象
L=[1,2,3,4]
s2=''.join(map(repr,L))
print(s2)
>>>1234
提取文本中的单词
假如我们有一段文本,里面含有多个空格符,逗号,句号等符号,我们需要提取出每一个单词
一种常用的操作是使用re库把其余字符全部转换成’’(假设每个符号后面跟着空格),然后再调用split
import re
re.sub('[,.!-]','',s)
s.split()
一种更好的方法是:
来源: https://www.geeksforgeeks.org/python-extract-words-from-given-string/
# Python3 code to demonstrate
# to extract words from string
# using regex( findall() )
import re
# initializing string
test_string = "Geeksforgeeks, is best @# Computer Science Portal.!!!"
# printing original string
print ("The original string is : " + test_string)
# using regex( findall() )
# to extract words from string
res = re.findall(r'\w+', test_string)
# printing result
print ("The list of words is : " + str(res))
======result======
The original string is : Geeksforgeeks, is best @# Computer Science Portal.!!!
The list of words is : [‘Geeksforgeeks’, ‘is’, ‘best’, ‘Computer’, ‘Science’, ‘Portal’]
\w在正则中是匹配任意数字和字母,相当于 [a-zA-Z0-9_],+是匹配1到多次
int相关
取到int的某一位
L=list(str(123))
>>>['1','2','3']
使用map又可以把list中的str转成int,这样就能取到每一位了
int 求和
我们需要求和int的每一位,例如1234 => 10,常用的做法是for循环取得每一位再累加
reduce函数很好的帮我们完成了这种操作
from functools import reduce
print(reduce(lambda x, y: x + y, list(map(eval,str(1234)))))
===result===
10
reduce接受两个参数,第一个是lambda对象,指定执行的操作,第二个是可迭代对象,所以我们需要把1234 转成 [1,2,3,4]来传入
字典
一般用d[i]=d.get(i,0)+1
来访问字典
也可以使用
d.setdefault(i,0)
d[i]+=1
我比较喜欢第二种方法
Counter类
文档解释
A Counter is a dict subclass for counting hashable objects. It is an unordered collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. The Counter class is similar to bags or multisets in other languages.
Elements are counted from an iterable or initialized from another mapping (or counter):
注意most_common,非常强大,很多情况下我们直接使用Counter能节省很多代码量
排序
复杂排序
sorted在python里面是默认升序的,使用reverse=True来调整成降序,另外也可以设置key成 key = lambda x:-x
来调整成降序
如果排序对象只有一个参数,那么sorted调用结果很明显,如果像[('a',13),('ds',3,),('vdf',4)]
这种涉及到多个参数,那么就会复杂一些
指定参数作为排序依据
如果有多个参数,指定key可以按照某个元素作为排序,例如
按照第二个参数升序排列
L=[('a',4),('b',3),('a',2)]
print(sorted(L,key= lambda x:x[1]))
=====================================
[('a', 2), ('b', 3), ('a', 4)]
不想写lambda也可以用 itemgetter,效果是一样的
from operator import itemgetter
if __name__ == '__main__':
L=[('a',4),('b',3),('a',2)]
print(sorted(L,key= itemgetter(1)))
itemgetter(i)的意思就是获取对象的第i个元素
get=itemgetter(1)
print(get([1,2,3]))
结果是2
如果排序对象是一个object,还可以用attrgetter
attrgetter(*attrs)
返回一个可从操作数中获取 attr 的可调用对象。 如果请求了一个以上的属性,则返回一个属性元组。 属性名称还可包含点号。 例如:
在 f = attrgetter(‘name’) 之后,调用 f(b) 将返回 b.name。
在 f = attrgetter(‘name’, ‘date’) 之后,调用 f(b) 将返回 (b.name, b.date)。
在 f = attrgetter(‘name.first’, ‘name.last’) 之后,调用 f(b) 将返回 (b.name.first, b.name.last)。
来源:https://docs.python.org/zh-cn/3/library/operator.html#operator.attrgetter
文档中的实例
指定多个排序条件
如果我们有这样的结构L=[('a',4,2),('b',3,1),('a',2,7)]
需要对第二个参数升序,如果相等,则对第三个参数升序,那么我们可以这样做
# 1.
L = [('a', 4, 2), ('b', 3, 1), ('a', 4, 7)]
print(sorted(L,key= itemgetter(1,2)))
# 2.
L = [('a', 4, 2), ('b', 3, 1), ('a', 4, 7)]
print(sorted(L, key=lambda x: (x[1], x[2])))
====
[('b', 3, 1), ('a', 4, 2), ('a', 4, 7)]
如果是要求相等时第三个元素降序呢?
L = [('a', 4, 2), ('b', 3, 1), ('a', 4, 7)]
print(sorted(L, key=lambda x: (x[1], -x[2])))
===
[('b', 3, 1), ('a', 4, 7), ('a', 4, 2)]
在第二个参数前面加上一个符号即可
需要注意的是,如果我们指定reverse,那么reverse是对每个排序条件都起作用的,例如
L = [('a', 4, 2), ('b', 3, 1), ('a', 4, 7)]
print(sorted(L, key=lambda x: (x[1], x[2]),reverse=True))
===
[('a', 4, 7), ('a', 4, 2), ('b', 3, 1)]
可以看到排列结果中,第二,第三个参数都是降序的形式。如果想要第三个参数升序,那么在x[2]前面加符号即可。
问题来了,如果我们需要比较字符串类型怎么办?
例如这个:我们对第二个参数降序,第三个参数升序,第三个参数是字符串,没办法加负号处理
L = [('a', 4, 'aa'), ('b', 3, 'ba'), ('a', 4, 'ac')]
print(sorted(L, key=lambda x: (x[1], -x[2]))
这里有很多种方法,第一种方法就是排序两次,python的排序是保证稳定的,所以我们可以放心的排序
L = [('a', 4, 'aa'), ('b', 3, 'ba'), ('a', 4, 'ac')]
t=sorted(L, key=lambda x: x[1])
print(t)
t=sorted(t,key=lambda x:x[2],reverse=True)
print(t)
===
[('b', 3, 'ba'), ('a', 4, 'aa'), ('a', 4, 'ac')]
[('b', 3, 'ba'), ('a', 4, 'ac'), ('a', 4, 'aa')]
可以看到第一遍排序是对x[1]升序,第二次排序是对x[2]降序