python学习 day3

一、python文件操作

文件操作基本流程:

计算机系统分为:计算机硬件,操作系统,应用程序三部分。

我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所周知,应用程序是无法直接操作硬件的,这就用到了操作系统。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。

有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:

方法一:
#打开文件,得到文件句柄并赋值给一个变量
f = open('D:\code\\1.txt',encoding='utf-8',mode='r')  #指定打开文件的自己,默认是以读模式打开
file = f.read()  #通过句柄对文件进行操作

f.close()   #关闭文件,使用该方法打开的文件,操作完成一定要进行关闭,不然会有内存溢出的风险

方法二:
#次方法的优点不需要担心关闭文件,只要在with语句下的代码执行完毕后,该方法会自动帮你将文件关闭
with open('D:\code\st.txt','w') as f:
     f.write("hello")    #绝对路径

文件打开方式:

#1. 打开文件的模式有(默认为文本模式):
r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】
w,只写模式【不可读;不存在则创建;存在则清空内容】
a, 只追加写模式【不可读;不存在则创建;存在则只追加内容】
注:正常工作中使用r、w、a这三种模式就完全够用了,不建议使用r+、w+等模式

#2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb 
wb
ab
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码

#3,‘+’模式(就是增加了一个功能)
r+, 读写【可读,可写】
w+,写读【可写,可读】
a+, 写读【可写,可读】

#4,以bytes类型操作的读写,写读,写读模式
r+b, 读写【可读,可写】
w+b,写读【可写,可读】
a+b, 写读【可写,可读】

常用的文件操作方法:

f1 = open('空姐护士老师主妇.txt', encoding='utf-8', mode='r')
content = f1.read()
print(content)
f1.close()

# read 全部读出,强烈不建议使用该方法,因为该方法会将全部文件都加载到内存中,如果文件过大的话会撑爆内存
f1 = open('log1', encoding='utf-8')
content = f1.read()  #
print(content)
f1.close()

#read(n)
f1 = open('log1', encoding='utf-8')
content = f1.read(5)  # r 模式 按照字符读取。
print(content)
f1.close()

f1 = open('log1', mode='rb')
content = f1.read(3)  # rb模式 按照字节读取。
print(content.decode('utf-8'))
f1.close()

#readline()按行读取
f1 = open('log1', encoding='utf-8')
print(f1.readline())
print(f1.readline())
print(f1.readline())
print(f1.readline())
f1.close()

#readlines() 将每一行作为列表的一个元素并返回这个列表
f1 = open('log1', encoding='utf-8')
print(f1.readlines())
f1.close()

#for循环
f1 = open('log1', encoding='utf-8')
for i in f1:
    print(i)
f1.close()

#我们在工作建议使用for循环的方法

#编码的补充:
s1 = b'\xd6\xd0\xb9\xfa'
s2 = s1.decode('gbk')
s3 = s2.encode('utf-8')
#将gbk编码转换为utf-8
print(s3)  # b'\xe4\xb8\xad\xe5\x9b\xbd'
s1 = b'\xd6\xd0\xb9\xfa'.decode('gbk').encode('utf-8')
print(s1)

文件修改:

1,打开原文件,产生文件句柄。
2,创建新文件,产生文件句柄。
3,读取原文件,进行修改,写入新文件。
4,将原文件删除。
5,新文件重命名原文件。

#文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:

方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os  # 调用系统模块

with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
    data=read_f.read() #全部读入内存,如果文件很大,会很卡
    data=data.replace('Tom','jerry') #在内存中完成修改

    write_f.write(data) #一次性写入新文件

os.remove('a.txt')  #删除原文件
os.rename('.a.txt.swap','a.txt')   #将新建的文件重命名为原文件

方法二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os

with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
    for line in read_f:
        line=line.replace('Tom','jerry')
        write_f.write(line)

os.remove('a.txt')
os.rename('.a.txt.swap','a.txt') 

 

二、函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print(),len()等。但你也可以自己创建函数,这被叫做用户自定义函数。

#函数定义
def mylen():
    """计算s1的长度"""
    s1 = "hello world"
    length = 0
    for i in s1:
        length = length+1
    print(length)

#函数调用  
mylen() #函数名+() 执行函数

#函数的返回值 return
'''
1,遇到return,结束函数。
def func1():
print(11)
print(22)
return
print(333)
print(444)
func1()
2,给函数的调用者(执行者)返回值。
无 return 返回None
return 不写 或者 None 返回None
return 返回单个数.
return 返回多个数,将多个数放在元组中返回。
'''

函数参数:

#函数定义
def mylen(s1):
    """计算s1的长度"""
    length = 0
    for i in s1:
        length = length+1
    return length

#函数调用
str_len = mylen("hello world")
print('str_len : %s'%str_len)

我们告诉mylen函数要计算的字符串是谁,这个过程就叫做 传递参数,简称传参,我们调用函数时传递的这个“hello world”和定义函数时的s1就是参数

实参与形参

参数还有分别:

我们调用函数时传递的这个“hello world”被称为实际参数,因为这个是实际的要交给函数的内容,简称实参。

定义函数时的s1,只是一个变量的名字,被称为形式参数,因为在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。 

传递多个参数

参数可以传递多个,多个参数之间用逗号分割。

def mymax(x,y):
    the_max = x if x > y else y
    return the_max

ma = mymax(10,20)
print(ma)

动态参数 *args,**kwargs 万能参数

 

三、命名空间和作用域

我们回忆一下python代码运行的时候遇到函数是怎么做的。

从python解释器开始执行之后,就在内存中开辟了一个空间

每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。

但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。

等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

注:我们给这个“存放名字与值的关系”的空间起了一个名字——叫做命名空间

 代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间

命名空间与作用域:

命名空间一共分为三种:

  全局命名空间

  局部命名空间

  内置命名空间

*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。

三种命名空间之间的加载与取值顺序:

加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

取值:

  在局部调用:局部命名空间->全局命名空间->内置命名空间

作用域

作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。

全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

局部作用域:局部名称空间,只能在局部范围生效

globals和locals方法

def func():
    a = 12
    b = 20
    print(locals())
    print(globals())

func()

输出:

{'b': 20, 'a': 12}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0578A590>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python/day4/练习.py', '__cached__': None, 'func': <function func at 0x0582B8E8>}

 

闭包

def func():
    name = 'eva'
    def inner():
        print(name)

闭包函数:

内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数

判断闭包函数的方法__closure__

#输出的__closure__有cell元素 :是闭包函数
def func():
    name = 'eva'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f = func()
f()

#输出的__closure__为None :不是闭包函数
name = 'egon'
def func2():
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f2 = func2()
f2()

总结:

命名空间:

  一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间

作用域(包括函数的作用域链):

小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)

在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错

函数的嵌套:

  嵌套调用

  嵌套定义:定义在内部的函数无法直接在全局被调用

函数名的本质:

  就是一个变量,保存了函数所在的内存地址

闭包:

  内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数

 

posted @ 2018-04-24 23:09  飞奔的小水牛  阅读(157)  评论(0编辑  收藏  举报