函数与文件操作

本文详细介绍了Python中的函数声明、调用机制,包括实参、形参、默认参数、关键字参数、可变参数以及拆包和装包的概念。此外,还涵盖了字符串编码、解码、文件操作的流程,以及如何处理图片复制和网络爬虫中的图片下载。
摘要由CSDN通过智能技术生成

函数

1. 函数声明

使用 def 关键字进行函数声明:

# 函数声明 
def pokers():
    lst1 = ["🍬", "💕", "😀", "🍭"]
    lst2 = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]

    for i in lst1:
        for j in lst2:
            print(f"{i}{j}", end=" ")
        print()

注:只声明而不调用,函数里面的内容不会执行。

2. 函数调用

特点:一次声明多次调用

3. 函数参数

3.1 实参和形参

形式参数:函数声明时,使用的参数

实际参数:调用函数时,传入的参数

# 计算 1 到 n 的累加和
def get_sum(n):
    num = 0
    for i in range(1, n + 1):
        num = num + i
    print(num)


get_sum(100)
get_sum(1000)

# 输出:
5050
500500

其中,n 为形参,100 和 1000 为实参。

3.2 位置参数

  1. 实参和形参按照位置,一一对应的进行传递参数;
  2. 也叫做必传参数,如果不传则会报错;
def add(x, y):
    print(x + y)


add(1, 2)
add(10, 20)

# 输出:
3
30

3.3 默认参数

  1. 在函数声明时,给形参赋值一个默认参数。如果函数调用时,如果实际参数没有给这一项,就使用默认参数;
  2. 也叫做非必传参数,不传的时候取默认值,传了则取实际值;
def add1(x, y=100):
    print(x + y)


add1(1, 2)
add1(1)

# 输出:
3
101

3.4 关键字参数

以 **形参=实参 **的形式去传递参数,因此可以不受传递参数的位置、顺序的影响。

def get_sum(m, n):
    num = 0
    for i in range(m, n + 1):
        num = num + i
    print(num)


get_sum(1, 1000)
get_sum(n=1000, m=1)

# 输出:
500500
500500

3.5 可变参数

当我们传递参数的值不确定时,可以使用可变参数;

可变参数 args 把参数组装成元组*,可变参数 kwargs 把参数组装成字典*;

def fun1(*args):
    print(args)
    print(type(args))
    
def fun2(**args):
    print(args)
    print(type(args))


fun1(1, 2, 3, 4, 5, "six")
fun2(a=1, b=2, c=3)

# 输出:
(1, 2, 3, 4, 5, 'six')
<class 'tuple'>
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>

3.6 拆包和装包

拆包

  • 形参中的 *args 其实真正接收数据的是 args,它是一个元组,把传进来的数据放在了 args 这个元组中
  • 函数体里的 args 依然是那个元组,但是 *args 的含义就是把元组中的数据进行拆包,也就是把元组中的数据拆成单个数据
  • 对于 args 这个元组,如果不对其进行解包,就将其作为实参传给其它以 *args 作为形参的函数时。args 这个元组会看看作一个整体,作为一个类型为元组的数据传入

示例一:

def run(a, *args):
    print(a)  		# 第一个参数传给了a
    print(args)  	# args是一个元组,里面是2和3两个参数

    # *args是将这个元组中的元素依次取出来
    print("对 args 拆包: ", end="")
    print(*args)  # *args 相当于 a,b = args

    print("将未拆包的数据传给run1: ", end="")
    run1(args)

    print("将拆包后的数据传给run1: ", end="")
    run1(*args)


def run1(*args):
    print("输出元组: ", end="")
    print(args)
    print("对元组进行拆包: ", end="")
    print(*args)


run(1, 2, 3)  # 后面的2和3

# 输出:
1
(2, 3)
对 args 拆包: 2 3
将未拆包的数据传给run1: 输出元组: ((2, 3),)
对元组进行拆包: (2, 3)
将拆包后的数据传给run1: 输出元组: (2, 3)
对元组进行拆包: 2 3

示例二:

def run(**kwargs):
    # kwargs是一个字典
    print(kwargs)
    print("对 kwargs 拆包: ", end="")
    # 此处可以把 **kwargs 理解成对字典进行了拆包
    # {"a":1,"b":2} 的 kwargs 字典又被拆成了 a=1, b=2 传递给 run2
    # 但是 **kwargs 不能像之前 *args 那样被打印出来看的
    run2(**kwargs)
    # print(**kwargs)


def run2(a, b):  # 此处的参数名一定要和字典的键的名称一致 因为相当于是关键字传参 a=1, b=2
    print(a, b)


run(a=1, b=2)

# 输出:
{'a': 1, 'b': 2}
对 kwargs 拆包: 1 2

装包

  • 装包的含义就是把未命名参数和命名参数分别放在元组或者字典中

4. 函数返回值

4.1 默认返回值

如果没有写 return,默认返回空值 None

result1 = print("Hello Python")
print(result1)

# 输出:
None

4.2 多个返回值

如果以逗号分隔返回多个值,则实际返回的是一个元组

def send():
    name = "Jarvis"
    age = 21
    email = "123@qq.com"
    return name, age, email


print(send())

# 输出:
('Jarvis', 21, '123@qq.com')

4.3 自定义多个返回值

如果有多个返回值,也可以装在一个列表返回

def send1():
    name = "Jarvis"
    age = 21
    email = "123@qq.com"
    return [name, age, email]


print(send1())

# 输出:
['Jarvis', 21, '123@qq.com']

当然也可以返回一个字典

def send2():
    name = "Jarvis"
    age = 21
    email = "123@qq.com"
    return {
        "name": name,
        "age": age,
        "email": email
    }
    

print(send2())

# 输出:
{'name': 'Jarvis', 'age': 21, 'email': '123@qq.com'}

文件操作

1. 字符编码

计算机存储信息的基本单元为字节,即 Byte,一个字节等于八个比特位,即 1 Byte = 8 bit

  • ASCII
image-20240503191957442
  • GBK
image-20240503192026192
  • Unicode
image-20240503192108139
  • UTF-8
image-20240503192122032

2. 编码与解码

  • 当我们创建一个文件时,实际上相当于在磁盘中开辟一块空间,然后按照指定的编码方式存放一堆二进制数据;
  • 当我们打开某个文件时,实际上相当于从磁盘的空间中,以指定的解码方式,将二进制数据翻译为对应的信息;
  • 这些事情都是系统默默去完成的,我们看不见这个编码和解码的过程;
  • 但是如果编码和解码的方式不一致,就会导致翻译过后的数据不是我们真正想要的,可能会出现乱码;
  • 由于 ASCII 字符集被其他字符集所兼容,所以即使编码解码方法不一致,英文、数字等字符也不会变成乱码;

3. Python 的编码与解码

3.1 编码

在 Python 中对字符串进行编码,会得到一个新的数据类型:字节 Bytes

str1 = "Hello Python"
str2 = "你好"

result = str1.encode()      # 默认 utf-8
result1 = str2.encode()     # 默认 utf-8
result2 = str2.encode("gbk")
# utf-8 中一个汉字占 3 个字节
# gbk 中一个汉字占 2 个字节

print(result, type(result), sep='\t')
print(result1, type(result1), sep='\t')
print(result2, type(result2), sep='\t')

# 输出:
b'Hello Python'	<class 'bytes'>
b'\xe4\xbd\xa0\xe5\xa5\xbd'	<class 'bytes'>
b'\xc4\xe3\xba\xc3'	<class 'bytes'>

3.2 解码

用到字节类型的内置方法:decode()

data1 = b'Hello Python'
data2 = b'\xe4\xbd\xa0\xe5\xa5\xbd'
data3 = b'\xc4\xe3\xba\xc3'

print(type(data1), type(data2), type(data3), sep='\t')
print(data1.decode())
print(data2.decode())
print(data3.decode("gbk"))

# 输出:
<class 'bytes'>	<class 'bytes'>	<class 'bytes'>
Hello Python
你好
你好

4. 文件操作

image-20240504183724669

4.1 r 模式基本流程

首先创建一个 .txt 文件,内容如下:

Jarvis
好累啊呜呜呜呜呜
12345
Csgo Apex GTA5

再写一个 Python 程序如下:

# 该函数返回一个操作句柄
f = open("a.txt", "r", encoding="utf-8")

# 读所有字符
data = f.read()

print(data)

# 输出:
Jarvis
好累啊呜呜呜呜呜
12345
Csgo Apex GTA5

解释:

  1. 首先,这个 .txt 文件是以 utf-8 的形式编码为字节数据存储在电脑的磁盘中,而 Python 程序不能直接读取磁盘中的内容,他会先向操作系统发出一个请求,然后由操作系统读取磁盘内容,交给程序;
  2. 操作系统读取到的是字节数据,然后交给程序,但是 mode=“r” 表示程序需要的是字符;
  3. 于是操作系统会傻乎乎的按照自己默认的编解码方式,对字节数据进行解码,然后交给程序(Windows 操作系统默认为 gbk,Mac 系统默认为 utf-8);
  4. 但是我们的 .txt 文件是以 utf-8 的形式编码为字节数据,然后存储在磁盘中的,所以操作系统默认以 gbk 进行解码读取,中文就必然会出现乱码;
  5. 要解决这个问题有两个办法,第一,可以将 .txt 文件更改为 gbk 编码;第二,可以在 open 函数中指定一个编解码方式,例如 encoding=“utf-8” 表示 Python 程序告诉操作系统别用自己的默认,用我指定的规则来解码,这样就可以正确解码;

4.2 rb 模式基本流程

# 字节操作
with open("c.txt", "rb") as f:
    data = f.read().decode("utf-8")
    print(data)

解释

类似的,rb 模式表示 Python 程序向操作系统申请,读取磁盘空间的字节数据,不过这次不用麻烦操作系统来解码,这次是操作系统把拿到的数据交给 Python 程序,程序自己来解码。

4.3 wb 模式基本流程

with open("c.txt", "wb") as f:
    f.write("你看内容被覆盖了吧".encode("utf-8"))

解释:

类似的,wb 模式表示 Python 程序申请向磁盘中写入字节数据,但是这次不用麻烦操作系统编码,Python 程序自己使用 encode() 编码为字节数据,然后交给操作系统,存入内存即可。

4.4 文件读写操作

方法作用示例结果
open()返回一个操作句柄f = open(“a.txt”, “r”, encoding=“utf-8”)可以用 f 来完成各种文件操作
f.read()读取并返回所有字符,光标会随着读取而移动data = f.read()data 即文件中的所有字符,不建议用来读很大的文件,如视频文件
f.tell()返回光标位置print(f.tell())2998
f.seek()将光标移动到指定位置f.seek(0)光标位置回到文件内容最开始处
f.read(17)读取指定数量的字符,光标也会随着字符的读取而移动data1 = f.read(17)
f.readline()读取一行的内容并返回,光标会随着字符的读取而移动line = f.readline()注意每一行的末尾自带一个换行 ‘\n’
f.readlines()读取所有行,将每一行的内容作为一个元素放入列表中,返回一个列表lines = f.readlines()[‘汉皇重色思倾国,御宇多年求不得。\n’, ‘杨家有女初长成,养在深闺人未识。\n’]
遍历文件相当于每次 line 指向文件的某一行,读取之后释放资源,再指向下一行for line in f:建议使用这种方式遍历文件,对内存友好,不会一下子读取所有内容
f.write()写字符到文件,默认不换行,想要换行手动添加 ‘\n’,光标随着写入而移动f.write(“Hello Jarvis 哈哈”)
f.writelines()需要传入一个列表作为参数,将列表中的每一个元素写入文件,换行需要自己添加,光标随着写入移动f.writelines(lst)
f.close()关闭文件,释放资源f.close()
with open … as自动关闭文件,释放资源,更加安全with open(“c.txt”, “r”, encoding=“utf-8”) as f:

补充:

f.read() 时,光标会随着读取字符而移动,因此执行一次 f.read() 后,光标到达文件内容的末尾,第二次 f.read() 实际上什么也读不到,所以只会打印出一次文件的内容。

# 该函数返回一个操作句柄
f = open("长恨歌.txt", "r", encoding="utf-8")

# 读所有字符
data = f.read()
print(data)
data = f.read()
print(data)

如果想到将文件内容 f.read() 两次,需要将光标移动到文件最开始处,如下所示:

# 该函数返回一个操作句柄
f = open("长恨歌.txt", "r", encoding="utf-8")

# 读所有字符
data = f.read()
print(data)
f.seek(0)
data1 = f.read()
print(data1)

不一定每次打开一个文件对象时,都要创建一个文件句柄对象:

f = open("c.txt", "w", encoding="utf-8")

lines = open("a.txt", "r", encoding="utf-8").readlines()
f.writelines(lines)

# 追加模式
open("c.txt", "a", encoding="utf-8").write("Hello, apple\n")
open("c.txt", "a", encoding="utf-8").write("Hello, banana")

一种比 f.close() 更加安全的资源释放 with open

image-20240504203415547

5. 图片拷贝案例

拷贝图片的实质,就是先读取图片的二进制字节数据,然后写到指定的位置:

with open(r"F:\Code\Java\background.jpg", "rb") as fr:
    data = fr.read()
    with open("copy.jpg", "wb") as fw:
        fw.write(data)

6. 爬虫下载高清图片

首先要安装 requests 模块,在控制台输入:pip install requests 即可下载安装

image-20240504211052755

如何删除 requests 模块,在控制台输入:pip uninstall requests 即可卸载

使用 requests.get() 获取网页资源,然后 res.content 即可得到二进制字节数据,写入指定的位置即可

# 爬虫下载高清图片
import requests

# 得到章若楠图片的二进制数据
res = requests.get("https://img-baofun.zhhainiao.com/fs/af24bceea223a09c25194ae06f629daf.jpg")

with open("章若楠.jpg", "wb") as f:
    f.write(res.content)
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值