Python3入门3--函数、面向对象、文件操作、深浅拷贝、模块、异常及捕获

第一章 变量、常用循环体、代码结构、代码练习

第二章 列表、元组等数据结构、字符串驻留机制及字符串格式化操作

第三章 函数、面向对象、文件操作、深浅拷贝、模块、异常及捕获

第四章 项目打包、类和对象高级、序列、迭代器、生成器、装饰器

第五章 正则表达式、json、logging日志配置、数据库操作、枚举、闭包、匿名函数和高阶函数、time、datetime

第六章 Socket编程、多线程(创建方式、线程通信、线程锁、线程池)

函数

函数的创建和调用

什么是函数?

函数就是执行特定任务和完成特定功能的一段代码

函数的作用:

  • 复用代码
  • 隐藏实现细节
  • 提高可维护性
  • 提高可读性便于调试

创建
在这里插入图片描述

简单的两数之和:

# 定义函数
def calc(a, b):
    c = a + b
    return c

# 调用函数
res = calc(10, 20)
print(res)

函数的参数传递

传参方式

在这里插入图片描述

# 定义函数
def calc(a, b):		# 形参
    c = a + b
    return c

# 位置实参调用函数
res = calc(10, 20)	# 位置实参
print(res)	# 30

# 关键字实参 调用函数
res = calc(b = 10, a = 20)
print(res)	# 30

传参分析

def fun(arg1, arg2):
    print('arg1', arg1) # arg1 11
    print('arg2', arg2) # arg2 [22, 33, 44]
    arg1 = 100
    arg2.append(10)
    print('arg1', arg1) # arg1 100
    print('arg2', arg2) # arg2 [22, 33, 44, 10]

n1 = 11
n2 = [22, 33, 44]
fun(arg1=n1, arg2=n2)
print('n1', n1)     # n1 11		n1的值没有改版
print('n2', n2)     # n2 [22, 33, 44, 10]	n2的值变了

结论:如果是可变对象,在函数体中的修改会影响到实参的值

而如果是不可变对象,在函数体的修改不会影响实参的值

函数 返回值

  • 返回值为多个值时,返回的是一个元组

    def fun(num):
        odd = []    # 奇数
        even = []   # 偶数
        for i in num:
            if i % 2:
                odd.append(i)
            else:
                even.append(i)
    
        return (odd, even)
    
    
    lst = [10, 29, 34, 23, 44, 53, 55]
    print(fun(lst))		# ([29, 23, 53, 55], [10, 34, 44])
    

函数的参数定义

  • 函数的形参,定义默认值
def fun(a, b = 100):
    print(a, b)

fun(11)			# 11 100
fun(11,200)		# 11 200 ,声明实参后,替换默认值
  • 个数可变的位置参数(得到元组) 只能定义一个
# * 可变参数  接收到后,是一个元组类型
def fun(*args):
    print(args)

fun()		# ()
fun(10)		# (10,)
fun(10, 20)	# (10, 20)
  • 个数可变的关键字形参(得到字典) 只能定义一个
def fun(**args):
    print(args)

fun(a = 1, b = 2, c = 3)	# {'a': 1, 'b': 2, 'c': 3}

注意:

# 正确写法
def fun(*args1, **args2):	# 当函数参数中,既有个数可变的关键形参,也有个数可变的位置形参时
    print(args1)			# 个数可变的位置形参一定要放到 个数可变的关键字形参之前
    print(args2)
    
# 错误写法
# 直接错误
def fun(**args1, *args2):	# 当函数参数中,既有个数可变的关键形参,也有个数可变的位置形参时
    print(args1)			# 个数可变的位置形参一定要放到 个数可变的关键字形参之前
    print(args2)

总结

在这里插入图片描述

def fun(a, b, c):
    print('a=', a)
    print('b=', b)
    print('c=', c)

lst = [11, 22 ,33]
fun(*lst)   # 在函数调用时,将列表中每个元素都转换为位置实参传入

dct = {
    
    'a':111, 'b':222, 'c':333}
fun(**dct)  # 将字典中的键值对 都转换为关键字实参 传入

在这里插入图片描述

关键字形参

def fun(a, b, *, c, d):		# 使用了*,表示后面两个参数只能用 关键字实参传值,否则报错
    print(a)
    print(b)
    print(c)
    print(d)

fun(10, 20, c=30, d=50)

函数定义时,形参的顺序

def fun1(a,b,*,c,d,**args):
    pass

def fun2(*args, **args2):
    pass

def fun3(a, b = 10, *args, **args2):
    pass

变量的作用域

  • 局部变量 (函数代码块中的变量)

  • 全局变量 (函数外定义的变量)

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问

if True:
    total = 20
print(total)

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中
当内部作用域想修改外部作用域的变量时,就要用到 global

total = 0
def fun():
    global total
    total += 2
fun()
print(total)	# 2

递归函数

在一个函数体内,调用了该函数本身,称之为递归函数

  • 组成:递归调用与递归终止条件
  • 过程:
    • 每递归调用一次函数,都会在栈内存分配一个栈帧
    • 每次执行完一次函数,都会释放响应的空间
  • 优缺点:
    • 缺点:占用内存多,效率低下
    • 优点:思路和代码简单

练习:阶乘

def fac(n):
    if n == 1:
        return 1
    else:
        return n * fac(n - 1)

print(fac(6))	# 720

斐波那契数列

# 1 1 2 3 5 8 ..	第三个数 = 前两个数的和
def fib(n):
    if n == 1:
        return 1
    elif n == 2:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)

print(fib(6))

Bug

常见的异常类型

在这里插入图片描述

  • ZeroDivisionError : 除零
  • IndexError : 找不到索引
  • KeyError : 没有这个键
  • NameError :未声明/初始化对象
  • SyntaxError : Python语法错误
  • ValueError : 传入无效参数

异常处理机制

在这里插入图片描述

  • try-except:
try:

    a = int(input('请输入第一个整数'))
    b = int(input('请输入第二个整数'))

    res = a / b
    print(res)
except Exception:
    print('除数不能为0')
print('程序结束')
  • 多个except结构:

如果有父级关系,捕获的顺序按照先子类后父类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException

try:
    a = int(input('请输入第一个整数'))
    b = int(input('请输入第二个整数'))

    res = a / b
    print(res)
except ZeroDivisionError:
    print('除数不能为0')
except ValueError:
    print('只能输入数字')
print('程序结束')
  • try...except...else结构

如果try中没有抛出异常,那么执行 else块,如果try中抛出异常,那么执行except块

try:

    a = int(input('请输入第一个整数'))
    b = int(input('请输入第二个整数'))
    res = a / b
except BaseException as e:		# 可以获取到错误信息
    print('出错了', e)
else:
    print(res)
  • try...except...else...finally

finally,最后一定会执行,一般用来关闭申请的资源。。

try:

    a = int(input('请输入第一个整数'))
    b = int(input('请输入第二个整数'))
    res = a / b
except BaseException as e:
    print('出错了', e)
else:
    print(res)
finally:
    print('资源关闭了')

使用traceback 打印异常信息

import traceback
try:
    print(1/0)
except:
    traceback.print_exc()

❤PyCharm的调试模式

设置断点 + Debug模式运行Python程序

总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P356lXti-1648351201120)(imgs2/7.png)]

类和对象

两大编程思想

  • 面向过程:事物比较简单,可以用线性的思维去解决
  • 面向对象:事物比较复杂,简单的线性思维无法解决

二者相辅相成,并不是对立的

通过面向对象方式,使我们从宏观上把握事物之间的复杂关系,方便我们分析整个系统。

当具体到某个微观细节操作,仍然需要使用面向对象方式来处理。

在这里插入图片描述

像数字100,99…都是int类下的不同实例,这些实例被称之为 实例对象

类和对象的创建

Python中一切皆对象

在这里插入图片描述

简单创建一个对象:

class Student:  # 类名由一个或多个单词组成,每个单词首字母大写,其余小写
    pass

# Student是对象? 内存中有存储吗?	
# Student是对象,并且在内存中开辟了空间(有id标识),是`type`类型
print(id(Student))      # 1243795827504
print(type(Student))    # <class 'type'>
print(Student)          # <class '__main__.Student'>

类的创建(模板)

类的组成:

  • 类属性
  • 实例方法
  • 静态方法
  • 类方法
class Student:  # 类名由一个或多个单词组成,每个单词首字母大写,其余小写
    native_pace = '河北'  # 直接写在类里的属性,称为 `类属性`

    # 实例方法  self必须要写
    def eat(self):
        print('学生吃饭')

    # 静态方法  self不能写
    @staticmethod
    def method():
        print('静态方法')

    # 类方法  要写cls
    @classmethod
    def cm(cls):
        print('类方法')

    # 类的构造函数 (赋值操作)
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 在类中定义的是 方法,而在类之外定义的叫做 函数
def drink():
    print('喝水')

对象的创建

对象的创建又称为是类的实例化

  • 语法

    实例名 = 类名()
    
  • 示例:

    stu = Student('张三', 25)
    print(id(stu))      # 2863853260560
    print(type(stu))    # <class '__main__.Student'>
    print(stu)          # <__main__.Student object at 0x0000029ACAF4CF10>
    
    # 其中 stu的id值(十进制) == 0x0000029ACAF4CF10(十六进制)
    # 把id值转换为 十六进制 可以发现,其实是相等的,也就是输出的内存地址
    
  • 大致图示

    在这里插入图片描述

实例对象中类指针指向类对象中

注意:类对象(类)和实例对象(根据类创建的对象),在内存中都是有存储的,因为Python中一切皆对象,所以定义一个类之后,这个类(类对象)就已经被存储到内存中了。

调用属性和方法

  • 调用属性:直接实例对象.属性即可
  • 调用方法:
    • 实例对象.方法()
    • 类对象.方法(实例对象)
stu = Student('张三', 25)
# 直接用实例对象. 调用即可
print(stu.name)		# 张三
print(stu.age)		# 25

# 调用方式一
stu.eat()			# 学生吃饭

# 调用方式二	(实际上就是方法定义处的 self)
Student.eat(stu)	# 学生吃饭

类属性类方法与静态方法

  • 类属性:类中 方法外的变量称为类属性,被该类所有对象共享
  • 类方法:@classmethod修饰的方法,使用类名直接访问的方法
  • 静态方法:@staticmethod修饰的方法,使用类名直接访问的方法

在这里插入图片描述

类属性的使用示例:

# 类属性使用方式
# print(Student.native_pace)
stu1 = Student('张三', 25)
stu2 = Student('李四', 30)
print(stu1.native_pace)
print(stu2.native_pace)
Student.native_pace = '廊坊'
print(stu1.native_pace)
print(stu2.native_pace)

在这里插入图片描述

类方法、静态方法的使用示例:

# 类方法使用
Student.cm()

# 静态方法使用
Student.method()

动态绑定属性和方法

也就是:给已经创建的实例对象,创建独享的属性或者方法

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + '在吃饭')


stu1 = Student('张三', 20)
stu2 = Student('李四', 30)
print('--------------给stu2动态绑定性别属性---------------')
stu2.gender = '男'	# 单独为一个实例对象,新增属性。
print(stu2.gender)

print('--------------给stu2动态绑定方法---------------')
def show():
    print('我是函数')
stu2.show = show
stu2.show()

一个Student类可以创建N个Student类的实例对象,并且每个实例对象的属性值不同

总结调用方式

在这里插入图片描述

面向对象的三大特征

  • 封装:提高程序的安全性
    • 将属性和方法,包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法
    • Python中没有专门的修饰符表示属性私有,若希望属性不被类对象外部访问,那么变量前面使用两个’_’
  • 继承:提高代码复用性
  • 多态:提高程序的可扩展性和可维护性

封装

class Student:
    def __init__(self, name, age):
        self.name = name
        self.__age = age    # 年龄属性,不希望被外部访问,加了两个 _
    def show(self):
        print(self.name, self.__age)

stu = Student('张三', 20)
stu.show()
print(stu.name)
#print(stu.__age)	# 外部无法访问,会报错

# 查看类的所有 方法及属性
print(dir(stu)) # 可以找到一个 _Student__age
# 强制访问 私有属性
print(stu._Student__age)

正常情况下,私有属性就不要强制去访问了。

继承

  • 语法

    class 子类名(父类1, 父类2...):
        pass
    
  • 如果一个类没有继承任何类,那么默认为继承 object

  • 支持多继承

  • 定义子类时,子类的构造函数中,必须调用父类构造函数

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.__age =age

    def info(self):
        print(self.name, self.__age)


class Student(Person):
    def __init__(self, name, age, stu_no):
        super().__init__(name, age)
        self.stu_no = stu_no


class Teacher(Person):
    def __init__(self, name, age, teacherYear):
        super().__init__(name, age)
        self.teacherYear = teacherYear


stu = Student('张三', 23, '1001')
stu.info()  # 调用的是 Person类的info()实例方法

方法重写

父类中的方法不满足需求,可在子类中重写此方法完成实现

class Student(Person):
    def __init__(self, name, age, stu_no):
        super().__init__(name, age)
        self.stu_no = stu_no

    def info(self):     # 重写父类的info()方法
        super().info()      # 调用父类的info()方法
        print(self.stu_no)  # 子类给予具体实现

object类

  • 是所有类的父类,因此所有类都有object类的方法和属性
  • 内置函数dir()可查看指定 对象所有属性
  • objct有一个__str__()方法,用于返回一个对于"对象的描述",对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对__str__()方法进行重写(其实也就是java中的toString())
class Student:
    def __init__(self, name, age):
        self.name = name
        self.__age = age

    def __str__(self):
        return f'我的名字是{
      
      self.name},我的年龄{
      
      self.__age}岁'

stu = Student('张三', 20)
print(stu)		# 这里因为重写了__str__(),就不会再去输出 实例对象的引用地址了

多态

多态,有多种形态。即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法。

运行中,根据变量所引用的类型,动态决定调用哪个对象中的方法。

class Animal(object):
    def eat(self):
        print('动物吃东西')

class Dog(Animal):
    def eat(self):
        print('狗吃肉')

class Cat(Animal):
    def eat(self):
        print('猫吃鱼')

class Person(object):
    def eat(self):
        print('人吃五谷杂粮')

def fun(ob):
    ob.eat()

fun(Cat())		# 猫吃鱼
fun(Dog())		# 狗吃肉
fun(Animal())	# 动物吃东西

静态语言(Java)满足实现多态的3个必要条件:

  • 继承
  • 方法重写
  • 父类引用指向子类对象

动态语言(Python),只关心对象的行为。。

特殊方法和特殊属性

在这里插入图片描述

  • dir() : 查看对象的所有属性和方法
  • __dict__ : 获得类对象或实例对象所绑定的所有属性和方法的字典(其实就是以字典数据结构,展示已经赋值的属性和方法)
  • __len__() : 通过重写__len__()方法,让内置函数len()参数是自定义类型
  • __add__():通过重写__add__(),让自定义对象有 "+"的功能
  • __new__(): 创建对象
  • __init__() : 创建对象并且初始化

特殊属性

class A:
    pass
class B:
    pass
class C(A, B):
    def __init__(self, name):
        self.__name = name

x = C('zs')
print(x.__dict__)   # 查对象绑定的属性和方法的字典    {'_C__name': 'zs'}

print(x.__class__) # 输出对象所属的类   <class '__main__.C'>

print(C.__bases__) # 查询C类的父类    (<class '__main__.A'>, <class '__main__.B'>)

print(C.__mro__)  # 查询类的层次结构    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

print(A.__subclasses__())   # 查类的所有子类   [<class '__main__.C'>]

特殊方法

  • __add__()
a = 20
b = 100
c = a + b           # a + b 实际上就是调用了 __add__()方法
d = a.__add__(b)
print(c)			# 120
print(d)			# 120

class Student(object):
    def __init__(self, name):
        self.name = name
    def __add__(self, other):
        return self.name + other.name

stu1 = Student('zs')
stu2 = Student('ls')
print(stu1 + stu2)			# zsls
print(stu1.__add__(stu2))	# zsls
  • __len__()
lst = [1, 2, 3, 4]
print(len(lst))         # 4
print(lst.__len__())    # 4


class Student(object):
    def __init__(self, name):
        self.name = name

    def __len__(self):
        return len(self.name)


stu1 = Student('zs')
print(stu1.__len__())   # 2
print(len(stu1))        # 2
  • __new__() :创建对象
  • __init__() :对已经创建的对象进行初始化赋值
class Person(object):
    def __new__(cls, *args, **kwargs):
        print(f'__new___()被调用了,cls的id值是{
      
      id(cls)}')      # __new___()被调用了,cls的id值是2149260989648
        obj = super().__new__(cls)
        print('创建的对象的id为{0}'.format(id(obj)))           # 创建的对象的id为2149262024464
        return obj


    def __init__(self, name, age):
        print('__init__()调用,self 的id值{0}'.format(id(self)))     # __init__()调用,self 的id值2149262024464
        self.name = name
        self.__age = age


print('object类对象id:{0}'.format(id(object)))     # object类对象id:140715333991936
print('Person类对象id:{0}'.format(id(Person)))     # Person类对象id:2149260989648

p1 = Person('zs', 20)
print('p1实例对象的id:{0}'.format(id(p1)))       # p1实例对象的id:2149262024464

图示流程

在这里插入图片描述

类的浅拷贝和深拷贝

常见:两个变量共同指向一个内存地址

示例:

class CPU:
    pass

class Disk:
    pass

c1 = CPU()		
c2 = c1
print(id(c1))
print(id(c2))

在这里插入图片描述

浅拷贝

Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝

因此,源对象与拷贝对象都会引用同一个子对象。

使用copy模块的 copy()函数

class CPU:
    pass


class Disk:
    pass


class Computer:
    def __init__(self, cpu, disk):
        self.cpu = cpu
        self.disk = disk


# 类的浅拷贝
cpu = CPU()
disk = Disk()
computer = Computer(cpu, disk)

import copy
computer2 = copy.copy(computer)
print(computer, computer.cpu, computer.disk)
print(computer2, computer2.cpu, computer2.disk)

图示内存:

在这里插入图片描述

深拷贝

使用copy模块的deepcopy()函数,递归拷贝对象中包含的子对象,源对象和拷贝对象中所有的子对象也不相同

代码示例:类还是前面的CPU、Disk、Computer

# 深拷贝
computer3 = copy.deepcopy(computer)
print('computer', computer, computer.cpu, computer.disk)
print('computer3', computer3, computer3.cpu, computer3.disk)

内存图

在这里插入图片描述

可以看出,深拷贝,会去把源对象的所有对象信息进行拷贝,包括源对象里的子对象。

模块

什么是模块

模块:modules

  • 一个模块可以包含N个函数
  • Python中,一个扩展名为.py的文件就是一个模块

好处:

  • 方便其他程序和脚本的导入和使用
  • 编码函数名和变量名冲突
  • 提高代码的可维护性
  • 提高代码的可重用性

自定义模块

创建:创建一个.py文件,名称尽量不要和Python自带的标准模块名称相同

导入模块

语法:

  • import 模块名称 [as 别名]
  • from 模块名称 import 函数/变量/类
# 导入整个math模块所有内容
import math

# 导入需要的
from math import pi,pow
print(pi)		# 3.141592653589793
print(pow(2,3))	# 8.0

导入自定模块

自定义一个模块(Python文件)calc.py

定义一个add()函数

def add(a, b):
    return a + b

这里一定要看清楚,calc.py文件所在目录,是否是一个资源目录

如果只是一个普通目录,那么是无法使用到 calc模块

如下,普通目录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KxtNXUpp-1648351201125)(imgs2/19.png)]

如下,资源目录,直接导入 calc即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sMT6hhHH-1648351201125)(imgs2/20.png)]

以主程序形式执行

calc.py文件

def add(a, b):
    return a + b

print(add(10, 20))

demo.py文件

import calc
print(calc.add(100, 200))

以上,会导致calc.py文件中add()执行,然后demo.py文件中add()也执行

calc.py改为:

def add(a, b):
    return a + b

if __name__ == '__main__':	# 只有当执行calc.py文件时,才执行
    print(add(10, 20))

Python中的包

  • 包是一个分层次的目录结构,将一组功能相近的模块们组织在一个目录下

作用

  • 代码规范
  • 避免模块名重复

包和目录的区别

  • 包含__init_.py文件的是包
  • 目录:不包含__init__.py文件

包的导入

import 报名.模块名

起个别名,不然写起来太长

import chap6.calc as calc
calc.add(100, 200)

导入方式

# import导入  只能导入包名或者模块
import chap6.calc as calc
calc.add(100, 200)

# from...import导入	导入包,模块,函数....
from chap6 import calc
calc.add(100, 200)

第三方模块的安装及使用

常用的内置模块

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AIM6rurw-1648351201126)(imgs2/21.png)]

# sys模块
import sys

print(sys.getsizeof(24))  # 获取对象占用的字节数

# time模块
import time

print(time.time())
print(time.localtime(time.time()))

# urllib
import urllib.request as re
print(re.urlopen("http://www.baidu.com").read())

第三方模块安装

在这里插入图片描述

  • 在线安装 pip install 模块名

在这里插入图片描述

安装后,发现可以在PyCharm中导入了

定时任务练习:

import time

import schedule


def job():
    print('O(∩_∩)O哈哈~')


schedule.every(3).seconds.do(job)	# 每三秒执行一次

while True:
    schedule.run_pending()
    time.sleep(1)			# 线程休眠1秒

文件IO

编码格式

常见的编码格式

  • Python解释器使用的是 Unicode(内存)
  • .py文件在磁盘上使用 UTF-8存储(外存)

在这里插入图片描述

修改.py文件的编码格式(默认是UTF-8格式)

# encoding=gbk
print('你好,中国')

文件读写原理

文件的读写,俗称’IO操作’

在这里插入图片描述

io流,实际就是队列的数据结构先进先出

文件读写操作

在这里插入图片描述

# 注意:读取时默认是 gbk格式读取,如果你的文件是UTF-8格式的,请写好参数
file = open('a.txt','r',encoding='UTF-8')
print(file.readlines())
file.close()

文件分为两大类:

  • 文本文件

    存储的是普通"字符"文本,默认unicode字符集,可以使用记事本程序打开

  • 二进制文件

    把数据内容用"字节"进行存储,无法用记事本打开,必须用专用软件打开,如:.mp3, .mp4, .jpg图片

文件模式:

在这里插入图片描述

写入文件,注意w是覆盖

a是追加

file = open('b.txt','w',encoding='UTF-8')
file.write('你好哇,咔咔咔')
file.close()

file = open('b.txt','a+',encoding='UTF-8')
file.write('你好哇范德萨发生的,咔咔咔')
file.close()

文件的拷贝:

file = open('work.xls','rb')
tar_file = open('copywork.xls','wb')

tar_file.write(file.read())

tar_file.close()
file.close()

文件对象常用方法

在这里插入图片描述

读取

# read()    可以读取 字节和字符
file = open('work.xls','rb')
print(file.read())
file.close()

# readline() 读取一行字符
# readlines() 读取所有,且返回一个列表
file2 = open('a.txt','r+',encoding="UTF-8")
print(file2.readline())
print(file2.readlines())
file2.close()

写入,文件不存在时,自动创建文件

file = open('c.txt','a',encoding='UTF-8')
file.write('hello world')
lst = ['java', 'python']
file.writelines(lst)
file.close()

移动文件指针:

seek(offset[,whence])

位置从0开始

需要注意:移动的是字节数,而不是字符数,一个中文代表3个字节

file = open('c.txt','r',encoding='UTF-8')
file.seek(3)		# 表示当前指针在第4个位置 
print(file.read())
print(file.tell())	# 获取当前指针的位置
file.close()

文件缓冲区

file = open('d.txt','a',encoding='UTF-8')
file.write('hello')
file.flush()
file.write('world')
file.flush()
file.close()

flush之后,文件流未关闭,还可以继续写入内容

close之后,文件流已经关闭了,不能继续写入内容

with语句(上下文管理器)

可以自动管理上下文资源,不论什么原因跳出with块,都能确保文件能够正确的关闭,来达到释放资源的目的

在这里插入图片描述

自动释放资源…

# open('c.txt','r', encoding='UTF-8') 是上下文管理器
with open('c.txt','r', encoding='UTF-8') as file:
    print(file.read())

什么是上下文管理器??

无论是否产生异常,资源都会关闭

'''
MyContentMgr实现了特殊方法 __enter__() , __exit__(),称为该类对象遵守了上下文管理器协议
那么该类的 实例对象,称为 上下文管理器
MyContentMgr()
'''

class MyContentMgr:
    def __enter__(self):		# 管理器启动时执行
        print('enter方法被调用')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit方法被调用')	# 管理器关闭时执行
        return self

    def show(self):
        print('show方法被调用')
        
with MyContentMgr() as file:
    file.show()				# enter方法被调用   show方法被调用	exit方法被调用

改良文件复制

with open('work.xls','br') as src_file:
    with open('copywork.xls','bw') as target_file:
        target_file.write(src_file.read())

OS模块

os模块:

  • 是Python内置的与操作系统功能和文件系统相关的模块,该模块中的语句执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样
  • os模块与os.path模块用于对目录或者文件进行操作
import os
os.system('notepad.exe')    # 打开notepad == cmd下执行的 notepad
os.system('calc.exe')       # 打开计算机

# 直接调用可执行文件
os.startfile('D:\\tools\\Typora\\Typora.exe')   # 打开系统文件

对目录操作

在这里插入图片描述

import os
print(os.getcwd())  # 获取当前工作目录
print(os.listdir('../chap6'))   # 返回路径下的文件和目录信息
os.mkdir('newdir')  # 创建目录
os.makedirs('a/b/c')    # 创建多级目录
os.rmdir('newdir')      # 删除目录
os.removedirs('a/b/c')  # 移除多级目录

os.path模块

在这里插入图片描述

import os.path as p

print(p.abspath('demo9.py'))  # 获取绝对路径  D:\environment\python-workspace\demo\chap7\demo9.py
print(p.exists('demo9.py'), p.exists('../chap6'))  # 文件或目录是否存在  True True

print(p.join('E:\\Python', 'demo9.py'))  # 路径拼接 E:\Python\demo9.py
print(p.split('E:\\Python\\demo9.py'))  # 将目录和文件拆分  ('E:\\Python', 'demo9.py')
print(p.splitext('demo9.py'))   # 文件名和后缀拆分          ('demo9', '.py')
print(p.basename('E:\\Python\\demo9.py'))   # 从目录中提取文件名 demo9.py
print(p.dirname('E:\\Python\\demo9.py'))    # 提取目录  E:\Python
print(p.isdir('E:\\Python\\demo9.py'))  # 是否是目录 False

查询目录练习

1.列出当前目录下,所有.py文件

import os

path = os.getcwd()
files = os.listdir(path)
for i in files:
    if i.endswith('.py'):
        print(i)

2.遍历目录下所有文件

import os
path = os.getcwd()
lst_files = os.walk(path)       # 获取目录下,所有的目录和文件
for dirpath,dirname,filename in lst_files:
    print(dirpath)
    print(dirname)
    print(filename)

第一章 变量、常用循环体、代码结构、代码练习

第二章 列表、元组等数据结构、字符串驻留机制及字符串格式化操作

第三章 函数、面向对象、文件操作、深浅拷贝、模块、异常及捕获

第四章 项目打包、类和对象高级、序列、迭代器、生成器、装饰器

第五章 正则表达式、json、logging日志配置、数据库操作、枚举、闭包、匿名函数和高阶函数、time、datetime

第六章 Socket编程、多线程(创建方式、线程通信、线程锁、线程池)

猜你喜欢

转载自blog.csdn.net/weixin_45248492/article/details/123770151