文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

初认python-4

2023-09-22 17:54

关注

文件

 变量是把数据保存到内存中,如果程序重启/主机重启,内存中的数据就会丢失,要想能让数据被持久化储存,就可以把数据储存到硬盘中,也就是在文件中保存。

在ws中的目录名之间使用  \   来分割   但是使用   /   来分给也是可以的,但是我们一般用  /  ,因为 \  在编译语言的在字符串中有特定的含义,用来表示转义字符。如果我们想用反斜杠,那么就要用    \\   , \\    在字符串里面才表示字符   \   的含义。

变量就是在内存中,文件就是在外存中,我们要用python实现对文件操作。

文件操作

 打开文件

 在Python中我们使用   open  函数打开一个文件:

open('d:/Python环境/test.txt','r')

open函数中的第一个参数是我们要打开文件的绝对路径,第二个参数是我们打开这个文件的方式,‘r’ 表示read,按照读的方式打开;而open函数的返回值是一个文件对象,用来表示文件:

f = open('d:/Python环境/test.txt','r')print(f)print(type(f))

 输出:

<_io.TextIOWrapper name='d:/Python环境/test.txt' mode='r' encoding='cp936'>

 这个 文件对象  --  class '_io.TextIOWrapper'   是python专门给这个类型取了个名字。

文件对象--  文件的内容是在硬盘上的,而我们的文件对象,则是内存上的一个变量,我们写的python程序是在内存上运行的,后序读写文件操作,要在内存中实现对硬盘中文件的修改,都是拿着这个文件对象来进行操作。此处的文件对象,就像一个遥控器一样,我们直接操作硬盘中的内存不好操作,我们就在内存中操作这个‘遥控器“,通过这个文件对象间接操作这个硬盘。

在计算机中,也把这样的远程操作的“遥控器:称为 ” 句柄 “ (handler)

当文件不存在的时候,我们再用open打开的话就会抛出异常:

 下面是关于  文件打开方式:

 关闭文件

 我们使用 close 方法来对文件进行删除:

f = open('d:/Python环境/test.txt','r')print(f)print(type(f))f.close()

我们的文件打开 (open函数) 和文件关闭 (close 方法)是一对离不开的孪生兄弟,文件打开之后,是用完之后,必须把文件关闭。这时因为,打开文件其实是在申请一定的系统资源,当我们不在使用这个文件的时候,这个资源就该及时释放,如果不释放,以后其他人在打开文件就用不了。而且资源是有限的,我们打开文件的个数也是有限的。

flist = []count = 0while True:     f = open('d:/Python环境/test.txt','r')     flist.append(f)     count += 1     print(f'打开文件的个数:{count}')

 我们发现在打开一定数量的文件后,文件打开操作就失败了。(文件资源泄漏)

我们发现我们最终打开了8189 个文件个数,但是这不是我们这个程序所能打开的最大的文件个数,对于一个程序可以打开多少文件,我们在系统里面可以配置,但是无论配置多少,都不是无穷无尽的,因此我们要记得及时关闭文件。

我们的这个 8189 + 3 = 8192 => 2的13次方,计算机是使用二进制来表示数据的,因此计算机里的很多数据都是按照2的多少次方这样的方式来表示的。那么我们上述的这个  “3”  是怎么来的 呢?

我们每一个程序来启动的时候,都会默认打开三个文件:

 这三个文件很特殊,这三个文件不是在我们的磁盘里,而是在我们的键盘,显示器当中的。

 文件资源泄漏,是很重要的问题,因为这个问题不会第一时间报错出来,我们在比较大的程序中,这问题很难发现,当程序报错的时候,不是在我们写的那一时间报错,可能会在后面的时候发生文件资源泄漏,这时候我们不好再去找这个问题了。

我们上述的代码中,还有一个地方,就是我打开文件之后,我是把这个open返回的文件对象用一个 flist 列表来存储,当我们不用这个列表来存储的时候,我们打开的文件就不止  8189 个了:

flist = []count = 0while True:     f = open('d:/Python环境/test.txt','r')     # flist.append(f)     count += 1     print(f'打开文件的个数:{count}')

 我们发现此时我们打开了1200000 + 以上都没有停止,这是为什么呢?

这是因为在Python中有一个重要的机制,叫做垃圾回收机制(GC):可以自动的把不使用的变量给进行释放~~

例如上面这个代码,我们在每一次循环 用 open打开函数创建了一个  f  的文件对象的时候,因为我们没有对他进行使用,所以Python认为他是一个垃圾,所以就把这个文件对象个释放掉了,也就是python自动的帮我们调用了close方法了。

当我们把这个文件对象保存到我们 flist 这个列表当中的时候,我们的垃圾回收就不知道我们后序会不会再次使用这个文件对象,就不会帮我们自动删除了。

但是这个垃圾回收机制还是不是很及时的反应释放,所以我们不能依赖这个机制,每一次使用完文件之后都要关闭文件。

写文件

 用  write  方法来写文件

 只写方式打开来用write 方法写:

f = open('d:/Python环境/test.txt','w')f.write('hello')f.close()

我们打开文件发现:

 ’hello‘字符串已经被我们写入了。

 需要注意的是,我们在open打开的时候是用  w  的方式打开的,如果我们在写文件的时候用 r 的方式打开的,则会抛出异常:

 报错:

 报错说:这是一个不支持的操作(UnsupportedOperation)不可写的(not table)

像 w 方法打开的话,会先把文件里面的内容给清空掉然后再执行其他的操作,如果我们用 w 方式open打开文件什么都不执行然后就 close 关闭文件的话,会出现下面的情况:

f = open('d:/Python环境/test.txt','w')f.close()

 我们发现之前我们在曾 test.txt 文件中写入的 ’hello’字符串被清空了。

所以我们写文件还有第二种方式:

用 a 方式在文件中追加内容:

#用 w 的方式写文件f = open('d:/Python环境/test.txt','w')f.write('1111')f.close()#用 a 的方式写文件f = open('d:/Python环境/test.txt','a')f.write('2222')f.close()

 我们发现此时在test.txt 中在 1111  的基础上追加了 2222 这个字符串。

我们发现我们之前在每一次打开open打开之后,都去 把这个文件关闭(close)了,如果文件对象已经被关闭,那么意味着系统中的和该文件相关的内存资源已经释放了,如果我们在文件关闭的情况下去强行去写的话就会出现异常:

#用 w 的方式写文件f = open('d:/Python环境/test.txt','w')f.write('1111')f.close()f.write('2222')

 编译器会提示你 这个 I/0 操作针对了一个被关闭的文件上,当然这操作是不能修改文件中的操作的:

 可以看到文件中只有第一次操作有效,2222没有被输入。

 读文件

 

 我们要读取这个文件中的内容。

f = open('d:/Python环境/test.txt','r')result = f.read(2)    #表示读前两个字符print(result)f.close()

 这个报错是关于字符编码的问题,我们文件中是中文的内容,中文和英文类似,在计算机中,都是使用“数字”来表示字符的,但是具体是哪个数字对应这个汉子,在计算机中国可以有多个版本,我们最主要的版本是  GBK  和  UTF-8  这两种版本。GBK  只能表示我们的一些简体中文,表示的范围有限,一些跟复杂的符号就无法翻译了;而UTF - 8是使用更广泛的编码方式,全世界任一一种语言都可以用这个编码方式来翻译。

在实际开发的时候,就需要保证我们文件内容的编码方式和代码中操作文件的编码方式,得匹配。如果不匹配就容易出现上面的问题。

在代码中是尝试按照gbk来进行解析,而我们查看我们的文件编码发现是:UTF - 8的编码方式。

解决方式就是,让我们的代码按照UTF-8的编码方式来进行度文件的操作,我们在使用open函数的时候在后面多调用一个  encoding 参数:

f = open('d:/Python环境/test.txt','r',encoding = 'utf8')

这个open函数里面的前两个参数叫做  位置参数   ;第三个参数叫做   关键字参数。对于encoding这样的参数,是有默认值的,不传这个参数,在windows系统中,我们不传encoding参数那么它默认值为  GBK  编码方式进行编码。

f = open('d:/Python环境/test.txt','r',encoding = 'utf8')result = f.read(2)    #表示读前两个字符print(result)f.close()#床前

现在我们可以读出并打印这个文件里面的前两个字符了,这时我们发现,打印了“床前"这两个汉字,说明在Python中,一个汉字对应这一个字符。

 利用for循环,按行读取文件内容

 之前我们用read方法,可以读取文件中任意字符的内容,现在我们用for循环来按行来读取文件内容,这个其实是我们更常见的读取文件内容的方法:

f = open('d:/Python环境/test.txt','r',encoding = 'utf8')for line in f:    print(f'line = {line}')f.close()#line = 床前明月光#line = 疑似地上霜#line = 举头望明月#line = 低头思故乡

我们在for 循环中创建了一个临时变量--line,而这个for循环的意思是,在f 这个文件对象中,每一次循环,我读取一行的内容给给line这个变量;

我们在打印的时候发现,我们每输出一行就要空出一行,然后在输出下一行。

这是因为,我们本来读取到的文件内容(这一行内容,末尾就有一个 '/n')  ;  而此处每一次使用print() 函数打印的时候,就会自动多加一个换行符。

如果不想有print()自动添加换行的行为,可以给print函数多加一个参数:

print(f'line = {line}',end = ' ')

此处的  end = ‘ ’ 中我们在 ' ' 中放的是一个 空格 ,这个参数的意思是,我们每一次调用print  函数的时候,在打印的最后以  空格   的形式来结束这一次打印。同样,按照之前的说法,这个参数也是有默认值的,默认值为 ‘\n’  。

改进之后输出:

 使用   readlines   方法直接把整个文件所有内容都读出来,按照行组织到一个列表里

f = open('d:/Python环境/test.txt','r',encoding = 'utf8')lines = f.readlines()print(lines)    #['床前明月光\n', '疑似地上霜\n', '举头望明月\n', '低头思故乡']f.close()

我们发现输出的是一个列表,这个列表里的每一个元素都是文件中每一行的内容,我们发现每一行的后面都有一个 ‘\n'  ,如此也就验证了我们之前的操作。

 这个方法相对于之前使用 for 循环来读取全部文件操作,有一个好处,就是我们这个  readlines  方法是一次性全部读取完的,而for 循环是每一次循环就读一行;当我们的文件小 的时候还好,当我们文件里内容很多的时候,使用for循环比较低效,因为他需要一行一行的一次一次循环读取。

当然,readlines 方法也有坏处,就是我们能一次使用这个方法来读完文件里全部内容,是因为这个文件本来就不大,如果这个文件里内容太多,我们的内存根本就装不下。

上下文管理器

 我们之前说过文件有打开就必须由关闭,但是我们不是每一次度可以考虑到文件 close  操作的,比如我定义一个函数:
 

def func()    f = open('d:/xxxxxxx/xxxxxx','r')    #中间来写其他的操作文件的代码    #万一中间的代码,有条件判定,函数返回,就会导致我们的文件泄漏    if 条件:        #进行条件处理        f.close()        return     #代码    # 代码    # 代码    # 代码    if 条件:        #进行条件处理        return   #这里我就忘记写  f.close() 关闭文件了

我们在条件判读,函数返回的时候,可能不是每一次都可以注意到文件关闭,这样就会导致文件泄漏,那么接下来,我们的上下文管理器就派上用场了。

          

def func():    with open('d:/Python环境/test.txt','r',encoding = 'utf8') as f:        #进行文件处理逻辑        lines = f.readlines()                #我们在处理文件操作的时候,可能就是使用if return出函数了        if 条件:          return

我们此处之前是吧 open函数的返回值直接赋值给 f,现在我们就不再用 = 来赋值,我们用 with as :语句来进行赋值。我们的 with as :  语句的下面是一个代码块,这个代码块里面就是需要我们对文件的操作代码,最后无论我们在if条件判断,跳出函数,有没有 close 文件,当这个with as :语句执行完,就会自动的帮我们进行 文件关闭操作。

python中库的使用

 所谓库也就是别人已经写好的代码,我们拿来直接使用,在python中的库,使用模块的方式去体现的。在python中有python的标准库和其他人写的第三方库,python中的第三方库的种类和数量都是远远大于标准库的。

标准库

 我们在Python的官方文档里面就可以看到这些库的内容:
The Python Standard Library — Python 3.10.8 documentationhttps://docs.python.org/3.10/library/index.html

 当我们安装了python之后,这个文档也会自动的下载在我们的python目录里:

 这个文档是直接下载好的不需要加载。

 下面我们举例来讲解库的使用操作:

日期计算器

 给定两个日期,计算这两个日期之前相差多少天。

在python中有一个datetime这个库可以帮助我们实现我们的操作:

import datetime#先构造 datetime 变量date1 = datetime.datetime(2012,2,14)date2 = datetime.datetime(year = 2016,month = 2,day = 3)print(date2 - date1)    #1450 days, 0:00:00

import语句用来导入其他python文件(称为模块module),使用该模块里定义的类、方法或者变量,函数。这个调用的模块可以是第三方库,标准库  或者是自己写的模块。上面的 import datetime  就是调用了  datetime  这个模块。

而datetime.datetime 意思是在datetime 模块中 创建了一个 datetime 这个类型(前面的为模块,后面的为模块中的类型)而后括号中的是这个类型的参数(按照左到右的顺序是  年 月 日 时 分 秒,这些参数的默认值都是 0 )

我们还可以这样写:

from datetime import datetime#先构造 datetime 变量date1 = datetime(2012,2,14)date2 = datetime(year = 2016,month = 2,day = 3)print(date2 - date1)    #1450 days, 0:00:00

最上面的 from datetime import datetime  意思是在  datetime  这个模块里  import 一下 datetime这个类型。这个时候我们发现 下面的 赋值操作就不需要在前面加一个  datetime.  (模块名. )  来说明这时datetime 模块里面的内容了。

还可以这样写:

import datetime as dt#先构造 datetime 变量date1 = dt.datetime(2012,2,14) #从前面的某一天到2012.2.14这天有多少天date2 = dt.datetime(year = 2016,month = 2,day = 3)  #从前面某一天带2016.2.3这天有多少天print(date2 - date1)    #1450 days, 0:00:00

import datetime as dt  的意思就是 我们先import出  datetime 这个模块,然后 as dt 就是把这个模块其一个别名叫做  dt。这个时候,我们在下面创建 datetime  类型的变量的时候,前面的模块申明就可以直接写成 dt  ,不用再写成 datetime了。

 字符串操作

 字符串是 Python 的内置类型,字符串的很多方法不需要导入额外的模块,即直接使用就行了。

翻转单词顺序

 输入一个英文句子,翻转句子中的英文单词的顺序,但是单词内字符串的顺序不变。为简单起见,标点符号和普通字母一样处理,例如:
输入字符串” I am a student,"  ,则输出 "student , a am I" 。我们使用空格来分割单词。

思路:

def reversWord(s):    tokens = s.split(' ')  #用 空格 来进行分割字符串    tokens.reverse()     #对这个列表进行逆序    return ' '.join(tokens) #把 分割逆序之后 tokens里面的每一个字符串 重新拼接print(reversWord('I am a student.'))   #student. a am I

 我们在pycharm中 在对某一变量后面输入 “  .  ” 之后他会把这个类型的方法给列出来方便我们的快捷输入:

 但是我们在输入上述代码的时候pycharm没有给这样的提示:

 

 我们对代码进行一下修改:

def reversWord(s: str):    tokens = s.split(' ')  #用 空格 来进行分割字符串    tokens.reverse()     #对这个列表进行逆序    return ' '.join(tokens) #把 分割逆序之后 tokens里面的每一个字符串 重新拼接print(reversWord('I am a student.'))   #student. a am I

其中我们对这个 s 变量进行类型声明,这是因为python是一个动态语言,在我们输入之前s的值之前,编译器是不知道这个 s 到底是什么类型,不知道什么类型也就不知道这个变量到底可以用什么方法,我们其中用的 split 方法是否可以用,编译器也是不知道的。所以我们在函数接收参数的时候,给这个变量声明一个 str 类型,告诉编译器这是一个字符串。

我们用以变量来接收 split 方法所传回来的 用空格分割好的字符串列表,这个列表的每个元素是 s 中字符串分割出的每一个单词。

然后用 reverse 方法来对字符串进行逆序。

然后再函数return 返回时候,我们用了  '  '.join(tokens)   ;其中   ‘  ’  是一个空格的字符串,而字符串里面有一个  join 方法,可以帮我们把  tokens 里面的内容填写进去。

最后我们打印这个函数的返回值就可以实现这个效果了。、

旋转字符串

 给定两个字符串,  s  和 goal  ,如果在若干次旋转操作之后,  s  能变成  goal  ,那么返回true

s  的 旋转操作就是将 s  最左边的字符移动到最右边。

例如:   s = 'abcde',在旋转一次之后,结果就是'bcdea'

思路:

我们想到字符串的拼接,假如:s = 'abcde'   我们让 s + s 得到一个新的字符串  =>  'abcdeabcde',然后我们在去下标为 [ 1 ]  到 [ 6 ]  的字符串出来,而这个取出来的字符串不就是我们将 s 旋转之后得到的字符串吗?

当然,以上情况是我们知道了 输入的 s 字符串里字符的个数,当我们不知道字符串里字符的个数的时候,那我们取出的下标应该是  [  1  ]  ~~  [  len - 1 ]   其中len的长度是 我们输入的 s  的字符串长度。

而我们发现,我们在 s + s  得到一个更大的字符串,这个字符串其实就包含了我们 s  是的所有旋转之后的结果。

def rotateSyring(s,goal):    if len(s) != len(goal):   #先判断这两个字符串里的字符个数是否相等,不相等那么说明不管s怎么选旋转都不可能=goal        return False    return goal in s + s  #判断在 s + s 这个大字符串里面有没有和goal相等的子集

统计字符串前缀

 给定一个字符串列表 words 和一个字符串  s  ,其中 words[i]  和 s 只包括小写英文字母;请你返回words中是字符串 s 前缀的字符串数目。

注:一个字符串前缀是出现在字符串开头的子字符串。子字符串是一个字符串中的连续字符序列;

例:

 思路:

遍历一遍word,取出每个字符串,判定当前这个字符串,是否是s 的前缀就行了(s 是否是以曾字符串开头的)

在python中的字符串类型 有一个 startswith 方法判定某一个字符串,他的前缀是不是另一个字符串。是就返回 True  不是就返回 False。        

def countPrefixes(words: list, s: str):    count = 0    for word in words:    #用 for 循环 遍历 words 这个列表        if s.startswith(word):   每一次遍历,只要这个元素是 s 的前缀就让 count + 1            #s  是以word 开头            count += 1    return countprint(countPrefixes(['a','b','c','ab','bc','abc'],'abc'))    #3

来源地址:https://blog.csdn.net/chihiro1122/article/details/127894953

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯