函数基础与文件处理

文件处理

一 主动控制文件内指针移动

#大前提:文件内指针的移动都是Bytes为单位的,唯一例外的是t模式下的read(n),n以字符为单位


with open('a.txt',mode='rt',encoding='utf-8') as f:
     data=f.read(3) # 读取3个字符
    

with open('a.txt',mode='rb') as f:
     data=f.read(3) # 读取3个Bytes


# 之前文件内指针的移动都是由读/写操作而被动触发的,若想读取文件某一特定位置的数据,则则需要用f.seek方法主动控制文件内指针的移动,详细用法如下:
# f.seek(指针移动的字节数,模式控制): 
# 模式控制:
# 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
# 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
# 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
# 强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用

1.1 案例一: 0模式详解 

# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好

# 0模式的使用
with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.seek(3,0)     # 参照文件开头移动了3个字节
    print(f.tell()) # 查看当前文件指针距离文件开头的位置,输出结果为3
    print(f.read()) # 从第3个字节的位置读到文件末尾,输出结果为:你好
    # 注意:由于在t模式下,会将读取的内容自动解码,所以必须保证读取的内容是一个完整中文数据,否则解码失败

with open('a.txt',mode='rb') as f:
    f.seek(6,0)
    print(f.read().decode('utf-8')) #输出结果为: 好

1.2 案例二: 1模式详解

# 1模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(3,1) # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
    print(f.tell()) # 输出结果为:3
    f.seek(4,1)     # 从当前位置往后移动4个字节,而此时的当前位置为3
    print(f.tell()) # 输出结果为:7

 

1.3 案例三: 2模式详解 

# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好

# 2模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(0,2)     # 参照文件末尾移动0个字节, 即直接跳到文件末尾
    print(f.tell()) # 输出结果为:9
    f.seek(-3,2)     # 参照文件末尾往前移动了3个字节
    print(f.read().decode('utf-8')) # 输出结果为:好

# 小练习:实现动态查看最新一条日志的效果
import time
with open('access.log',mode='rb') as f:
    f.seek(0,2)
    while True:
        line=f.readline()
        if len(line) == 0:
            # 没有内容
            time.sleep(0.5)
        else:
            print(line.decode('utf-8'),end='')

小练习:实现动态查看最新一条的效果

# 小练习:实现动态查看最新一条日志的效果
import time  # 导入的一个时间模块

# linux里面的一条命令:tail -f access.log
with open('access.log', mode='rb') as f:
    f.seek(0, 2)
    while True:
        line = f.readline()
        if len(line) == 0:
            # 没有内容
            time.sleep(0.5) # 睡眠0.5秒
        else:
            print(line.decode('utf-8'), end='')

二 文件的修改 

# 文件a.txt内容如下
张一蛋     山东    179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

# 执行操作
with open('a.txt',mode='r+t',encoding='utf-8') as f:
    f.seek(9)
    f.write('<妇女主任>')
    
# 文件修改后的内容如下
张一蛋<妇女主任> 179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的

文件对应的是硬盘空间,硬盘不能修改对应着文件本质也不能修改,
那我们看到文件的内容可以修改,是如何实现的呢?


大致的思路是将硬盘中文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘
具体的实现方式分为两种:

2.1 文件修改方式一

# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件


# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存 

with open('db.txt',mode='rt',encoding='utf-8') as f:
    data=f.read()

with open('db.txt',mode='wt',encoding='utf-8') as f:
    f.write(data.replace('kevin','SB'))

 

2.2 文件修改方式二

 # 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名


# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份

import os

with open('db.txt',mode='rt',encoding='utf-8') as read_f,\
        open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
    for line in read_f:
        wrife_f.write(line.replace('SB','kevin'))

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

函数

一 引入

目前的问题:
1. 我们现在所写的代码冗余度比较高,需要写重复代码
2. 目前写的代码兼容性太差了

函数:函数就类似于是一个工具箱,什么时候使用什么时候拿到就用内部封装了一些功能,哪里需要就在哪里使用

 

二 函数的定义与分类

def 函数名(参数1,参数2,...):
	"""函数注释"""
	函数体
	return 值

1. def 就是定义函数的关键字,它不能够省略,必须写


2. my_len():函数名,函数名的命名遵循变量的命名规范,他也是必填的,不能省略的,括号不能省略


3. a, b称为是函数的参数,是可选的,可有可无
    参数就是执行函数的一些前提条件


4. '''函数注释'''
    注释不参与函数的执行,只起到函数功能的提示作用,以及各个参数是什么意思
    # 可有可无的,但是,推荐每个函数都加上函数注释


5.  # 函数体
    才是函数的核心,它是函数所具备的核心功能,应该是必须有的,pass
    没有函数体的函数是没有意义的函数,一般情况都是要有函数体的


6. 返回值  return 函数的返回值
    # 返回值也是可选的,可以有返回值,也可以没有返回值,但是一般情况下都要有返回值
    # 一个函数只能有一个返回值...

 参数是函数的调用者向函数体传值的媒介,若函数体代码逻辑依赖外部传来的参数时则需要定义为参函数,

def my_min(x,y):
    res=x if x < y else y
    return res

否则定义为无参函数

def interactive():
    user=input('user>>: ').strip()
    pwd=input('password>>: ').strip()
    return (user,pwd)

函数体为pass代表什么都不做,称之为空函数。定义空函数通常是有用的,因为在程序设计的开始,往往是先想好程序都需要完成什么功能,然后把所有功能都列举出来用pass充当函数体“占位符”,这将使得程序的体系结构立见,清晰且可读性强。例如要编写一个ftp程序,我们可能想到的功能有用户认证,下载,上传,浏览,切换目录等功能,可以先做出如下定义:

def auth_user():
    """user authentication function"""
    pass

def download_file():
    """download file function"""
    pass

def upload_file():
    """upload file function"""
    pass

def ls():
    """list contents function"""
    pass

def cd():
    """change directory"""
    pass

之后我们便可以统筹安排编程任务,有选择性的去实现上述功能来替换掉pass,从而提高开发效率。

三 函数的调用与返回值 

函数的使用分为定义阶段与调用阶段,定义函数时只检测语法,不执行函数体代码,函数名加括号即函数调用,只有调用函数时才会执行函数体代码

# 定义阶段
def foo():
    print('in the foo')
    bar()

def bar():
    print('in the bar')

# 调用阶段
foo()

执行结果: 

in the foo
in the bar

 定义阶段函数foo与bar均无语法错误,而在调用阶段调用foo()时,函数foo与bar都早已经存在于内存中了,所以不会有任何问题。

 

按照在程序出现的形式和位置,可将函数的调用形式分为三种:

# 1、语句形式:
foo()

# 2、表达式形式:
m=my_min(1,2) #将调用函数的返回值赋值给x
n=10*my_min(1,2) #将调用函数的返回值乘以10的结果赋值给n

# 3、函数调用作为参数的形式:
# my_min(2,3)作为函数my_min的第二个参数,实现了取1,2,3中的较小者赋值给m
m=my_min(1,my_min(2,3))

若需要将函数体代码执行的结果返回给调用者,则需要用到return。return后无值或直接省略return,则默认返回None,return的返回值无类型限制,且可以将多个返回值放到一个元组内。 

def test(x,y,z):
    return x,y,z #等同于return (x,y,z)
res=test(1,2,3)
print(res)
(1, 2, 3)

 return是一个函数结束的标志,函数内可以有多个return,但只执行一次函数就结束了,并把return后定义的值作为本次调用的结果返回。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值