python学习笔记02(进阶)

01函数

1.1,函数的概述

  • 函数也是一个对象
  • 对象是内存中专门用来存储数据的一块区域
  • 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用
  • 创建函数:
def 函数名([形参1,形参2,...形参n]) :
            代码块
  • 函数名必须要符号标识符的规范:(可以包含字母、数字、下划线、但是不能以数字开头)
  • 函数中保存的代码不会立即执行,需要调用函数代码才会执行
  • 定义函数一般都是要实现某种功能的

1.2,函数的参数

  • 在定义函数时,可以在函数名后的()中定义数量不等的形参, 多个形参之间使用,隔开
  • 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值
  • 实参(实际参数)
  • 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参
  • 实参的传递方式:位置参数和关键字参数
  • 位置参数:就是将对应位置的的实参传递给对应位置的形参,也就是第一个实参传递给第一个形参,第二个实参传递给第二个形参,以此类推,不需要给形参预先指定默认值
def function1(a,b,c):
    print('a=',a);
    print('b=',b)
    print('c=',c)
function1(1,2,3)
  • 关键字参数:可以不按照形参定义的顺序传递直接根据参数名来传递参数,使用关键字参数的时候要给形参预先赋默认认值
def function2(a=0,b=0,c=0):
    print('a=',a);
    print('b=',b)
    print('c=',c)
function2(1,c=2)
  • 不定长参数:在定义函数时,可以在形参前面加上一个*号,这样这个形参将会获取到所有实参,将它保存到一个元组中,带*的形参只能接受位置型参数
    注意:如果有不定长参数,一定要放到最后
    特殊情况:如果不放在最后,带*的参数后面的所有参数,必须以关键字参数的形式传递
def function2(a, b, c):
def function2(*a):
def function2(*a, b=0, c=0):
def function2(a, *b, c=0):
def function2(a, b, *c):
  • **形参,可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中,注意:**形参必须写在所有参数的最后,并且只能有一个

1.3,参数的解包(序列参数)

  • 传递实参时,也可以在序列类型的参数前添加星号*,这样它会自动将序列中的元素依次作为参数传递,这里要求序列中元素的个数必须和形参的个数的一致。
  • 通过 **来对一个字典进行解包操作
# 参数的解包(拆包)
def function(a,b,c):
    print('a =',a)
    print('b =',b)
    print('c =',c)
    
# 创建一个元组
t = (10,20,30)
function(*t)

# 创建一个字典
d = {'a':100,'b':200,'c':300}
# 通过 **来对一个字典进行解包操作
function(**d)

1.4,函数的返回值

  • 返回值,返回值就是函数执行以后返回的结果
  • 通过 return 来指定函数的返回值
  • 当一个函数有返回值的时候,可以通过一个变量来接收函数的返回值
  • 如果仅仅写一个return 或者 不写return,则相当于return None
  • return后的代码都不会执行,return 一旦执行函数自动结束
# 函数的返回值
def function(a):
    print('a =',a)
    return a
b=function(521) # 使用变量接受函数的返回值
print(b)

1.5,文档字符串

  • 文档字符串:就是函数的说明
  • help()函数:Python中的内置函数
    通过help()函数可以查询python中的函数的用法
    语法:help(函数对象)
  • 文档字符串,在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明, 当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明
  • 文档字符串编写非常简单,其实直接在函数的第一行写一个字符串就是文档字符串
  • 注意:参数列表中冒号后面的变量类型仅是提示作用,并不起到限定作用,箭头后面是提示返回值类型,也不起到限定作用。
def function(a:int,b:bool,c:str='hello') -> int:
    '''
    这是一个文档字符串的示例

    函数的作用:。。。。。
    函数的参数:
        a,作用,类型,默认值。。。。
        b,作用,类型,默认值。。。。
        c,作用,类型,默认值。。。。
    '''
    return 10
help(function)

1.6,作用域(scope)

  • 作用域(scope):作用域指的是变量生效的区域
  • 在Python中一共有两种作用域
  • 全局作用域:
    全局作用域在程序执行时创建,在程序执行结束时销毁
    所有函数以外的区域都是全局作用域
    在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
  • 函数作用域
    函数作用域在函数调用时创建,在调用结束时销毁
    函数每调用一次就会产生一个新的函数作用域
    在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
  • 变量的查找
    当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,如果没有则继续去上一级作用域中寻找,如果有则使用,如果依然没有则继续去上一级作用域中寻找,以此类推,直到找到全局作用域,依然没有找到,则会抛出异常:NameError: name 'a' is not defined
  • 注意:如果局部变量和全局变量同名,当函数调用时,会首先找到局部变量而不是全局变量,如果想要在函数内部修改全局变量的值要使用关键字:global
a = 20
def function():
    a = 10 # 修改局部变量
    print('函数内部:','a =',a)

def function2():
    global a
    a = 10  # 修改全局变量
    print('函数内部:','a=',a)

function()
print('函数外部:','a =',a)
function2()
print('函数外部:','a =',a)

运行结果:
函数内部: a = 10
函数外部: a = 20
函数内部: a= 10
函数外部: a = 10

1.7,命名空间(了解)

  • 命名空间(namespace):指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
  • 每一个作用域都会有一个它对应的命名空间
  • 全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
  • 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
  • locals()函数:用来获取当前作用域的命名空间
    如果在全局作用域中调用locals()则获取全局命名空间
    如果在函数作用域中调用locals()则获取函数命名空间
  • globals()函数:可以用来在任意位置获取全局命名空间
# 获取命名空间
scope=locals()
print(type(scope))
print(scope)

# 向scope中添加一个key-value,相当于在全局中创建了一个变量(一般不建议这么做)
scope['c'] = 1000 
print(c)

def function():
    a = 10
    # 在函数内部调用locals()会获取到函数的命名空间
    scope = locals()
    # 可以通过scope来操作函数的命名空间(不建议这么做)
    scope['b'] = 20 
    #globals() #函数可以用来在任意位置获取全局命名空间
    global_scope = globals()
    # print(global_scope['a'])
    global_scope['a'] = 30
    # print(scope)
    
function()

1.8,高阶函数(了解)

1.8.1,高阶函数概述

  • 高阶函数:接收函数作为参数,或者将函数作为返回值的函数是高阶函数
  • 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数
# 创建一个列表
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def function(func, lst):
    '''
        fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回
        参数:
            lst:要进行筛选的列表
    '''
    # 创建一个新列表
    new_list = []
    # 对列表进行筛选
    for n in lst:
        # 判断n的奇偶
        if func(n):
            new_list.append(n)
    return new_list  # 返回新列表


# 定义一个函数,用来检查一个任意的数字是否是偶数
def function1(i):
    if i % 2 == 0:
        return True
    return False

# 定义一个函数,用来检查一个任意数是否是3的倍数
def function2(i):
    return i % 3 == 0

new_list1=function(function1,list)
print('筛选偶数:',new_list1)
new_list2=function(function2,list)
print('筛选3的倍数:',new_list2)


运行结果:
筛选偶数: [2, 4, 6, 8, 10]
筛选3的倍数: [3, 6, 9]

1.8.2,Python内置函数:filter

  • filter()函数:Python内置函数,可以从序列中过滤出符合条件的元素,保存到一个新的序列中
    参数:
    1.函数,根据该函数来过滤序列(可迭代的结构)
    2.需要过滤的序列(可迭代的结构)
    返回值:
    过滤后的新序列(可迭代的结构)

  • 注意:filter返回的是一个可迭代的结构,不能直接打印

# 创建一个列表
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 定义一个函数,用来检查一个任意的数字是否是偶数
def function1(i):
    if i % 2 == 0:
        return True
    return False

# function1是作为参数传递进filter()函数中
# 而function1实际上只有一个作用,就是作为filter()的参数
# filter()调用完毕以后,function1就已经没用
# 注意:filter返回的是一个可迭代的结构,不能直接打印
print(list(filter(function1,l)))

运行结果:
[2, 4, 6, 8, 10]

1.8.3,浅谈lambda表达式

  • 匿名函数 lambda表达式:(语法糖)
    lambda函数表达式专门用来创建一些简单的函数,它是函数创建的又一种方式
    语法:lambda 参数列表 : 返回值
  • 匿名函数一般都是作为参数使用,其他地方一般不会使用
# 创建一个列表
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 此lambda表达式为求取两个数的和
num=(lambda a,b : a + b)(10,20)
print(num)
# 也可以将匿名函数赋值给一个变量,一般不会这么做
function2 = lambda a, b: a + b
print(function2(10,30))

# 此lambda表达式:lambda i: i%2==0,获取偶数
r = filter(lambda i: i%2==0, l)
# 将r转换为列表并打印出来
print(list(r))

1.8.4,Python内置函数:map

  • map()函数:Python内置函数
    对可跌代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回。
    例如对列表中的所有元素都取平方,然后返回新的列表
# 创建一个列表
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

r = map(lambda i : i ** 2 , l)
print(list(r))

运行结果:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

1.8.5,Python内置函数:sort

  • sort()函数:Python内置函数
    该方法用来对列表中的元素进行排序
    sort()方法默认是直接比较列表中的元素的大小
    在sort()可以接收一个关键字参数key,需要一个函数作为参数,当设置了函数作为参数,每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小
l = ['bb','aaaa','c','ddddddddd','fff']
l.sort()
print('默认排序:',l)
# 使用长度进行排序
l.sort(key=len)
print('使用长度排序',l)

l = [2,5,'1',3,'6','4']
l.sort(key=int)
print('int排序:',l)

1.8.6,Python内置函数:sorted

  • sorted()函数:Python内置函数
    此函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序,并且使用sorted()排序不会影响原来的对象,而是返回一个新对象
l = [2,5,'1',3,'6','4']
print('排序前:',l)
print(sorted(l,key=int))
print('排序后:',l)

1.8.7,闭包

  • 将函数作为返回值返回,也是一种高阶函数,这种高阶函数我们叫做闭包
  • 通过闭包可以创建一些只有当前函数能访问的变量,以将一些私有的数据藏到的闭包中
def function():
    a = 10

    # 函数内部再定义一个函数
    def inner():
        print('我是inner' , a)

    # 将内部函数 inner作为返回值返回   
    return inner

# r是一个函数,是调用function()后返回的函数
# 这个函数是在function()内部定义,并不是全局函数
# 所以这个函数总是能访问到function()函数内的变量
r = function()
r()

运行结果:
我是inner 10
  • 形成闭包的要件
    ① 函数嵌套
    ② 将内部函数作为返回值返回
    ③ 内部函数必须要使用到外部函数的变量

1.8.8,装饰器

  • 当一个函数功能不能满足我们的需求,我们就要对其进行修改,我们可以直接通过修改函数中的代码,但是会产生以下一些问题
    ① 如果要修改的函数过多,修改起来会比较麻烦
    ② 并且不方便后期的维护
    ③ 并且这样做会违反开闭原则(OCP)
  • 程序的设计要求,对程序的扩展开放,对程序的修改关闭
  • 所以我们希望在不修改原函数的情况下,来对函数进行扩展
# 我们希望在不修改原函数的情况下,来对函数进行扩展
def function():
    print('我是fn函数....')

# 只需要根据现有的函数,来创建一个新的函数
def function2():
    print('函数开始执行~~~')
    function()
    print('函数执行结束~~~')

function2()
  • 上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了,为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数
def add(a,b):
    return a+b
#  用来对其他函数进行扩展,参数:要扩展的函数对象
def begin_end(old):
    # 创建一个新函数:参数为可变参数
    def new_function(*args , **kwargs):
        print('开始执行~~~~')
        # 调用被扩展的函数
        result = old(*args , **kwargs)
        print('执行结束~~~~')
        # 返回函数的执行结果
        return result

    # 返回新函数
    return new_function

f = begin_end(add) # f为我们想要的函数
r = f(123,456)
print(r)
  • begin_end()这种函数我们就称它为装饰器
  • 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
  • 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
  • 可以同时为一个函数指定多个装饰器,这样函数将会按照从内向外的顺序被装饰。
  • 实例:使用function1和function2为装饰器,对say_hello进行增强
def function1(old):
    # 创建一个新函数
    def new_function(*args , **kwargs):
        print('func1函数装饰~开始执行~~~~')
        # 调用被扩展的函数
        result = old(*args , **kwargs)
        print('func1函数装饰~执行结束~~~~')
        # 返回函数的执行结果
        return result

    # 返回新函数
    return new_function

def function2(old):
    # 创建一个新函数
    def new_function(*args , **kwargs):
        print('func2函数装饰~开始执行~~~~')
        # 调用被扩展的函数
        result = old(*args , **kwargs)
        print('func2函数装饰~执行结束~~~~')
        # 返回函数的执行结果
        return result

    # 返回新函数
    return new_function

# function1和function2为装饰器,对say_hello进行增强
@function1
@function2
def say_hello():
    print('大家好~~~')
say_hello()

运行结果:
func1函数装饰~开始执行~~~~
func2函数装饰~开始执行~~~~
大家好~~~
func2函数装饰~执行结束~~~~
func1函数装饰~执行结束~~~~

02,面向对象(类)

2.1,什么是对象?

  • 对象是内存中专门用来存储数据的一块区域。
  • 对象中可以存放各种数据(比如:数字、布尔值、代码)
  • 对象由三部分组成:
    1.对象的标识(id)
    2.对象的类型(type)
    3.对象的值(value)

2.2,什么是面向对象(oop)?

  • Python是一门面向对象的编程语言

  • 所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的

  • 面向过程的编程的语言,面向过程指将我们的程序的逻辑分解为一个一个的步骤,通过对每个步骤的抽象,来完成程序

  • 面向过程的编程思想将一个功能分解为一个一个小的步骤, 我们通过完成一个一个的小的步骤来完成一个程序, 这种编程方式,符合我们人类的思维,编写起来相对比较简单, 但是这种方式编写代码的往往只适用于一个功能, 如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,所以它可复用性比较低,并且难于维护

  • 面向对象的编程语言,面向对象的编程语言,关注的是对象,而不关注过程。

  • 对于面向对象的语言来说,一切都是对象

2.3,类

2.3.1,类的概述

  • 我们目前所学习的对象都是Python内置的对象
  • 但是内置对象并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象
  • 类,简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象
  • 类就是对象的图纸!
  • 我们也称对象是类的实例(instance)
  • 如果多个对象是通过一个类创建的,我们称这些对象是一类对象
  • int() float() bool() str() list() dict() ....这些都是类,a = int(10)创建一个int类的实例 等价于 a = 10
  • 我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名
  • 类也是一个对象, 类就是一个用来创建对象的对象!

2.3.2,如何定义一个类?

  • 类和对象都是对现实生活中的事物或程序中的内容的抽象
  • 实际上所有的事物都由两部分构成:
    1.数据(属性)
    2.行为(方法)
  • 在类的代码块中,我们可以定义变量和函数,
    变量:为该类实例的公共属性,所有的该类实例都可以通过 对象.属性名 的形式访问
    函数:为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法
  • 注意:
    方法调用时,第一个参数由解析器自动传递,所以定义方法时,至少要定义一个形参!
  • 属性和方法查找的流程:
    当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,如果有,则直接返回当前的对象的属性值,如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值,如果类对象中依然没有,则报错!
  • 类对象和实例对象中都可以保存属性(方法)
  • 如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中
  • 如果这个属性(方法)是某个实例独有,则应该保存到实例对象中
  • 一般情况下,属性保存到实例对象中,而方法需要保存到类对象中
  • 类的定义模板:
 class 类名([父类]) :

        公共的属性... 

        # 对象的初始化方法
        def __init__(self,...):
            ...

        # 其他的方法    
        def method_1(self,...):
            ...

        def method_2(self,...):
            ...
  • 实用类创建对象的流程
  p1 = Person()的运行流程
  1.创建一个变量
  2.在内存中创建一个新对象
  3.__init__(self)方法执行
  4.将对象的id(内存地址)赋值给变量
  • 方法调用时,第一个参数由解析器自动传递,所以定义方法时,至少要定义一个形参! ,这个形参的名字可以随便起,但是一般我们都将将其命名为self
    第一个参数,就是调用方法的对象本身
    如果是p1调的,则第一个参数就是p1对象
    如果是p2调的,则第一个参数就是p2对象
# 定义一个Person类
class Person():
    # 定义公共属性
    name='AISMALL'
    # 定义公共方法
    def say_hello(self):
        print('我是',self.name)

p1=Person()
p2=Person()
p1.name='aismall' # 修改属性值
p1.say_hello()
p2.say_hello()

运行结果:
我是 aismall
我是 AISMALL

2.3.3,对象的初始化

  • 在上面的例子中,对于Person类来说name属性是必须要有的,并且每一个对象中的name属性基本上都是不同的
    如果我们在定义类的时候给name属性赋一个默认值,我们在创建对象的时候如果忘记修改name属性就会有很多对象的name属性值相同(为默认值)
    如果我们在定义对象以后,手动添加name到对象中,这种方式很容易出现错误
    所以,我们希望,在创建对象时,必须设置name属性,如果不设置对象将无法创建,并且属性的创建应该是自动完成的,而不是在创建对象以后手动完成,这就是对象的初始化
  • 如何实现对象的初始化?
    使用Python的魔术方法(特殊方法),类比java或者C++中的有参构造方法
  • 何为特殊方法?
    特殊方法都是以__开头,__结尾的方法
    特殊方法不需要我们自己调用(能调用但是不需要调用)
    特殊方法将会在特殊的时刻自动调用
  • 学习特殊方法:
    1.特殊方法什么时候调用
    2.特殊方法有什么作用
创建对象的流程:
p1 = Person()的运行流程
1.创建一个变量
2.在内存中创建一个新对象
3.__init__(self)方法执行
4.将对象的id赋值给变量

init方法的作用:
init会在对象创建以后自动执行
init可以用来向新创建的对象中初始化属性
调用类创建对象时,类后边的所有参数都会依次传递到init()
  • 例子
# 定义一个Person类
class Person():
    # 定义魔术方法(构造器)
    def __init__(self,name):
        self.name=name

    def say_hello(self):
        print('我是',self.name)

# 创建对象的时候初始化对象
# p1=Person()  # 这种创建会报错
p1=Person('AISMALL')
print(p1.name)
p1.say_hello()

运行结果:
AISMALL
我是 AISMALL

2.3.4,封装—类的三大特性之一

  • 封装:指的是隐藏对象中一些不希望被外部所访问到的属性或方法,类比java和C++中的私有属性
  • 如何隐藏一个对象中的属性?
    将对象的属性名,修改为一个外部不知道的名字
  • 如何获取对象中的隐藏属性?
    需要提供一个getter和setter方法使外部可以访问到隐藏属性
    getter 获取对象中的指定属性(get_属性名)
    setter 用来设置对象的指定属性(set_属性名)
  • 使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
    1.隐藏了属性名,使调用者无法随意的修改对象中的属性
    2.增加了getter和setter方法,很好的控制的属性是否是只读的,只读的,则直接去掉setter方法,不能被外部访问,则直接去掉getter方法
    3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
    4.使用getter方法获取属性,使用setter方法设置属性
    5.可以使用getter方法可以表示一些计算的属性
# 定义一个Person类
class Person():
    # 定义魔术方法(构造器)
    def __init__(self,name):
        # 修改变量名,目的隐藏属性不能被外部访问
        self.hidden_name=name

    # 提供setter方法用来设置属性值
    def set_name(self,name):
        self.hidden_name=name

    # 提供getter方法用来获取属性值
    def get_name(self):
        return self.hidden_name

    def say_hello(self):
        print('我是',self.hidden_name)

# 创建对象的时候初始化对象
p1=Person('AISMALL')
print('修改前:',p1.get_name())
p1.set_name('aismall')
print('修改后:',p1.get_name())
p1.say_hello()

运行结果:
修改前: AISMALL
修改后: aismall
我是 aismall

  • 在上面的例子中虽然给属性改了名字,但是依然可以通过对象访问
  • 为了使外部无法通过对象直接访问,可以为对象的属性使用双下划线开头,__xxx,双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
  • 其实隐藏属性只不过是Python自动为属性改了一个名字,实际上是将名字修改为了,_类名__属性名 ,比如 _Person__name,修改过之后只不过无法直接通过对象访问,但是知道名字还可以访问(防不胜防)。
# 定义一个Person类
class Person():
    # 定义魔术方法(构造器)
    def __init__(self,name):
        # 修改变量名,目的隐藏属性不能被外部访问
        self.__name=name

    # 提供setter方法用来设置属性值
    def set_name(self,name):
        self.__name=name

    # 提供getter方法用来获取属性值
    def get_name(self):
        return self.__name

    def say_hello(self):
        print('我是',self.__name)

# 创建对象的时候初始化对象
p1=Person('AISMALL')
# print(p1.__name) # 调用报错
print(p1._Person__name) # 可以被访问被修改的名字
print('修改前:',p1.get_name())
p1.set_name('aismall')
print('修改后:',p1.get_name())
p1.say_hello()

运行结果:
AISMALL
修改前: AISMALL
修改后: aismall
我是 aismall

2.3.5,继承—类的三大特性之一

2.3.5.1,继承的概述
  • 如果有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
  • 如何能让这个类来实现全部的功能呢?
    ① 直接修改这个类,在这个类中添加我们需要的功能,修改起来会比较麻烦,并且会违反OCP原则
    ② 直接创建一个新的类,创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码
    ③ 直接来继承它的属性和方法
  • 通过继承我们可以使一个类获取到其他类中的属性和方法
  • 如何继承一个类?
    在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)
    被继承的类为父类,集成的类为子类,子类可以直接继承父类中的所有的属性和方法
# 继承
# 定义一个类 Animal(动物)
# 动物会跑,会睡觉:run() sleep()
class Animal:
    def run(self):
        print('动物会跑~~~')

    def sleep(self):
        print('动物睡觉~~~')


# 定义一个类 Dog(狗),
# 狗会跑,会睡觉,会叫:run() sleep() bark()
# 为了不重复写会跑和会睡觉的方法,我们使用狗类继承动物类
# 这样狗类就可以使用动物类中的属性和方法
class Dog(Animal):
     def bark(self):
         print('汪汪汪~~~')
         
d = Dog()
d.run()
d.sleep()
d.bark()

运行结果:
动物会跑~~~
动物睡觉~~~
汪汪汪~~~
  • 从上面的结果可以看出,虽然子类可以访问父类中的属性,但是感觉不太对,我们需要的结果应该是:狗会跑,狗会叫,狗会睡觉
2.3.5.2,重写
  • 如何实现上面的结果,就要引出一个新的概念:重写
    如果子类中有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而不是父类的方法,这个特点我们叫做方法的重写(覆盖,override)
  • 当我们调用一个对象的方法时,会优先去当前对象中寻找是否具有该方法,如果有则直接调用,如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法,如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错
# 继承
# 定义一个类 Animal(动物)
# 动物会跑,会睡觉:run() sleep()
class Animal:
    def run(self):
        print('动物会跑~~~')

    def sleep(self):
        print('动物睡觉~~~')


# 定义一个类 Dog(狗),
# 狗会跑,会睡觉,会叫:run() sleep() bark()
class Dog(Animal):
    def run(self):
        print('狗会跑~~~~')

    def sleep(self):
        print('狗会睡觉~~~~')

    def bark(self):
        print('汪汪汪~~~')

d = Dog()
d.run()
d.sleep()
d.bark()

运行结果:
狗会跑~~~~
狗会睡觉~~~~
汪汪汪~~~
  • isinstance:检查一个对象是否属于一某个类
    如果这个类是这个对象的父类,也会返回True
    在创建类时,如果省略了父类,则默认父类为object,object是所有类的父类,所有类都继承自object
  • issubclass:检查一个类是否是另一个类的子类
# 继承
class Animal:
    def run(self):
        print('动物会跑~~~')

    def sleep(self):
        print('动物睡觉~~~')

class Dog(Animal):
    def bark(self):
        print('汪汪汪~~~')

d=Dog()
# isinstance检查一个对象是否属于一某个类
print('d是否为Animal的实例:',isinstance(d , Animal))
print('d是否为Dog的实例:',isinstance(d,Dog))

# issubclass检查一个类是否是另一个类的子类
print('Animal是否为Dog的子类:',issubclass(Animal , Dog))
print('Dog是否为Animal的子类:',issubclass(Dog ,Animal))
print('Animal是否为object的子类:',issubclass(Animal , object))
print('Dog是否为object的子类',issubclass(Dog , object))

运行结果:
d是否为Animal的实例: True
d是否为Dog的实例: True
Animal是否为Dog的子类: False
Dog是否为Animal的子类: True
Animal是否为object的子类: True
Dog是否为object的子类 True
2.3.5.3,super关键字
  • 在继承的时候,父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
  • 如何调用父类中方法?
  • super() :可以用来获取当前类的父类,可以通过super()来调用父类中的方法,并且通过super()调用父类方法时,不需要传递self
class Animal:
    def __init__(self,name):
        self._name = name

    def run(self):
        print('动物会跑~~~')

    def sleep(self):
        print('动物睡觉~~~')

    # 装饰器:只用之后可以向调用类属性一样调用类方法
    @property
    def name(self):
        return self._name

    # 装饰器:使用此装饰器之前要先有前面的装饰器
    @name.setter    
    def name(self,name):
        self._name = name

# 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
class Dog(Animal):

    def __init__(self,name,age):
        # 希望可以直接调用父类的__init__来初始化父类中定义的属性
        # super() 可以用来获取当前类的父类,
        # 并且通过super()返回对象调用父类方法时,不需要传递self
        super().__init__(name)
        self._age = age

    def bark(self):
        print('汪汪汪~~~') 

    def run(self):
        print('狗跑~~~~')   

    @property
    def age(self):
        return self._age

    @age.setter    
    def age(self,age):
        self._age = age

d = Dog('旺财',18) 

print(d.name)       
print(d.age) 

运行结果:
旺财
18      
2.3.5.4,多重继承
  • 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
  • 如何多继承?
    可以在类名的()后边添加多个类,来实现多重继承
  • 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
  • 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
  • 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。 前边父类的方法会覆盖后边父类的方法

2.3.6,多态—类的三大特性之一

  • 多态:从字面上理解是多种形态
    例如:狗(狼狗、藏獒、哈士奇、古牧 。。。)
  • 一个对象可以以不同的形态去呈现

面向对象的三大特征:

  • 封装
    确保对象中的数据安全
  • 继承
    保证了对象的可扩展性
  • 多态
    保证了程序的灵活性

2.4,类属性,实例属性,类方法,实例方法,静态方法

  • 类属性:直接在类中定义的属性是类属性
    类属性可以通过类或类的实例访问到, 但是类属性只能通过类对象来修改,无法通过实例对象修改
  • 实例属性:通过实例对象添加的属性属于实例属性
    实例属性只能通过实例对象来访问和修改,类对象无法访问修改
  • 实例方法:在类中定义,以self为第一个参数的方法都是实例方法
    实例方法在调用时,Python会将调用对象作为self传入
    实例方法可以通过实例和类去调用
    当通过实例调用时,会自动将当前调用对象作为self传入
    当通过类调用时,不会自动传递self,此时我们必须手动传递self
  • 类方法:在类内部使用 @classmethod 来修饰的方法属于类方法
    类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
    类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
    类方法可以通过类和实例调用,没有区别
  • 静态方法:在类中使用 @staticmethod 来修饰的方法属于静态方法
    静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
    静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
    静态方法一般都是一些工具方法,和当前类无关
# 定义一个类
class A(object):
    # 类属性
    count = 0
    
    def __init__(self):
        # 实例属性
        self.name = 'AISMALL'

    # 实例方法
    def test(self):
        print('这是实例方法~~~ ', self)

    # 类方法
    @classmethod
    def test_2(cls):
        print('这一个类方法~~~ ',cls)
        print(cls.count)

    # 静态方法
    @staticmethod
    def test_3():
        print('这是一个静态方法~~~')

# 创建类的实例对象
a = A()
print('修改前',A.count)

# 对于类属性,实例和类都可以访问,但是只能通过类来修改
a.count = 10 # 使用实例修改
print('使用实例修改:',a.count)
A.count = 100  # 使用类修改
print('使用类修改:',A.count)

# 实例属性,只能通过实例来访问和修改,类对象无法访问和修改
# print('通过类访问实例属性:,',A.name)
print('通过实例访问实例属性:',a.name)

# 实例方法,类和对象都可以访问,只是类访问需要传递参数(类对象)
# a.test()等价于A.test(a)
a.test()
A.test(a)

# 类方法,类和对象都可以访问
# A.test_2() 等价于 a.test_2()
A.test_2()
a.test_2()

# 静态方法,类和对象都可以访问
A.test_3()
a.test_3()

2.5,垃圾回收

  • 就像我们生活中会产生垃圾一样,程序在运行过程当中也会产生垃圾
  • 程序运行过程中产生的垃圾会影响到程序的运行的运行性能,所以这些垃圾必须被及时清理
  • 在程序中没有被引用的对象就是垃圾,这种垃圾对象过多以后会影响到程序的运行的性能,所以我们必须进行及时的垃圾回收,所谓的垃圾回收就是将垃圾对象从内存中删除
  • 在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,所以我们不用手动处理垃圾回收
class A:
    def __init__(self):
        self.name = 'A类'

    # del是一个特殊方法,它会在对象被垃圾回收前调用
    def __del__(self):
        print('A()对象被删除了~~~',self)


a = A()
print(a.name)
# 将a设置为了None,此时没有任何的变量对A()对象进行引用,它就是变成了垃圾
a = None  
# del方法手动回收
# del a
input('回车键退出...')

2.6,特殊方法(了解)

  • 我们在前面也提到过特殊方法(魔术方法),特殊方法都是使用__开头和结尾的
  • 特殊方法的特征:不需要我们手动调用,需要在一些特殊情况下自动执行
object.__new__(cls[, ...]) 
object.__init__(self[, ...]) 
object.__del__(self) 

object.__repr__(self) 
object.__str__(self) 
object.__bytes__(self) 
object.__format__(self, format_spec) 
object.__bool__(self)
object.__hash__(self) 
object.__len__(self)

object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__matmul__(self, other)
object.__truediv__(self, other)
object.__floordiv__(self, other)
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)

object.__lt__(self, other) 小于 <
object.__le__(self, other) 小于等于 <=
object.__eq__(self, other) 等于 ==
object.__ne__(self, other) 不等于 !=
object.__gt__(self, other) 大于 >
object.__ge__(self, other) 大于等于 >=
# 定义一个Person类
class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 这个特殊方法会在尝试将对象转换为字符串的时候调用
    # 它的作用可以用来指定对象转换为字符串的结果 (print函数)
    def __str__(self):
        return 'Person [name=%s , age=%d]' % (self.name, self.age)

    # 这个特殊方法会在对当前对象使用repr()函数时调用
    # 它的作用是指定对象在 ‘交互模式’中直接输出的效果
    def __repr__(self):
        return 'Hello'

    # 这个特殊方法会在将对象装换为布尔值得时候调用
    # 它的作用是通过bool来指定对象转换为布尔值的情况
    def __bool__(self):
        return self.age > 17

    # 在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果
    # 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象
    def __gt__(self, other):
        return self.age > other.age

# 创建两个Person类的实例
p1 = Person('孙悟空', 18)
p2 = Person('猪八戒', 28)

# 打印象时,实际上打印的是对象的中特殊方法 __str__()的返回值
print(p1) # <__main__.Person object at 0x04E95090>
print(p2)

# repr__()
print(repr(p1))

# __gt__
print(p1 > p2)

# __bool__
print(bool(p1))
# __bool__
if p1 :
    print(p1.name,'已经成年了')
else :
    print(p1.name,'还未成年了')

2.6,模块(了解)

  • 模块可以类比C++里面的分文件编写
  • 模块化,模块化指将一个完整的程序分解为一个一个小的模块,通过将模块组合,来搭建出一个完整的程序
  • 为什么采用模块化?
    不采用模块化,统一将所有的代码编写到一个文件中,不利于修改和维护
  • 模块化的优点:
    ① 方便开发
    ② 方便维护
    ③ 模块可以复用
  • 在Python中一个py文件就是一个模块,要想创建模块,实际上就是创建一个python文件
  • 注意:模块名要符号标识符的规范
  • 如何在一个模块中引入外部模块
    ① import 模块名 (模块名,就是python文件的名字,注意不要py)
    ② import 模块名 as 模块别名
  • 引入模块时的注意事项:
    可以引入同一个模块多次,但是模块的实例只会创建一个
    import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
    在每一个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
    __name__属性值为 __main__的模块是主模块,一个程序中只会有一个主模块
    主模块就是我们直接通过 python 执行的模块
  • 访问模块中的变量:模块名.变量名
import test_module as test
# 获取模块的名字
print(test.__name__)
print(__name__)
  • 引入模块的其他方式
假如m 是一个模块

第一种方式:引入模块的全部内容
语法:import m
访问方式:
访问模块中的变量:模块名.变量名
访问模块中的方法:模块名.方法()
访问模块中的类属性:模块名.类名.变量名
访问模块中的类的方法:模块名.类名.方法()

第二种方式:引入模块中的部分内容
语法 from  m import 变量,方法,....
访问方式:
访问模块中的变量:变量
访问模块中的方法:方法()
访问模块中的类属性:类名.变量名
访问模块中的类的方法:类名.方法()

当引入的变量或者方法给当前类中的变量或者方法重名,当前类中的会被覆盖,
为了不被覆盖我们可以使用给引入的变量或者方法起别名的方式
语法:from 模块名 import 变量 as 别名

引入到模块中所有内容,一般不会使用
语法:from m import * 
  • 测试模块代码编写模板:
# 当模块为主模块的时候才执行
if __name__=='__main__':
    代码块

2.7,包(了解)

  • 包 (Package):包也是一个模块
  • 当我们模块中代码过多时,或者一个模块需要被分解为多个模块时,这时就需要使用到包, 普通的模块就是一个py文件,而包是一个文件夹
  • 当我们创建包的时候会生成两个文件:__init__.py 文件和__pycache__文件
    __init__.py 文件:这个文件中可以包含有包中的主要内容
  • __pycache__文件:是模块的缓存文件
    py代码在执行前,需要被解析器先转换为机器码,然后再执行,所以我们在使用模块(包)时,也需要将模块的代码先转换为机器码然后再交由计算机执行, 而为了提高程序运行的性能,python会在编译过一次以后,将代码保存到一个缓存文件中,这样在下次加载这个模块(包)时,就可以不再重新编译而是直接加载缓存中编译好的代码即可
# testPackage是一个包,包中有连个py文件:a.py和b.py
from testPackage import a , b
print(a.c)
print(b.d)

2.8,Python标准库(了解)

  • Python标准库:就是Python为我们提供的一个一个模块,我们直接可以使用
  • 标准库会随Python的安装一同安装
  • Python标准库可以在Python参考文档的Global Module Index里面查找
  • 常用模块介绍
sys模块,它里面提供了一些变量和函数,使我们可以获取到Python解析器的信息
或者通过函数来操作Python解析器
引入sys模块:import sys

pprint 模块,它给我们提供了一个方法 pprint() 该方法可以用来对打印的数据做简单的格式化
引入pprint模块:import pprint

os 模块,让我们可以对操作系统进行访问
引入os模块:import os
  • 模块的简单使用:
import sys
import pprint
import os
# sys.argv
# 获取执行代码时,命令行中所包含的参数
# 该属性是一个列表,列表中保存了当前命令的所有参数
print(sys.argv)

# sys.modules
# 获取当前程序中引入的所有模块
# modules是一个字典,字典的key是模块的名字,字典的value是模块对象
# print(sys.modules) # 直接打印
# pprint.pprint(sys.modules)

# sys.path
# 它是一个列表,列表中保存的是模块的搜索路径
# pprint.pprint(sys.path)

# sys.platform
# 表示当前Python运行的平台
# print(sys.platform)

# sys.exit()
# 函数用来退出程序
# sys.exit('程序出现异常,结束!')

# os.environ
# 通过这个属性可以获取到系统的环境变量
pprint.pprint(os.environ['path'])

# os.system()
# 可以用来执行操作系统的名字
os.system('dir') # 打开文件夹
#os.system('notepad') #打开记事本

03,异常

3.1,异常的概述

  • 何为异常:
    程序在运行过程当中,不可避免的会出现一些错误,
    比如:使用了没有赋值过的变量,使用了不存在的索引,除0,这些错误在程序中,我们称其为异常。
  • 程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行!
print('hello')

print(10/0)

print('你好')

3.2,如何处理异常

  • 程序运行时出现异常,目的并不是让我们的程序直接终止, Python是希望在出现异常时,我们可以编写代码来对异常进行处理,处理过之后程序可以正常运行
try语句
        try:
            代码块(可能出现错误的语句)
        except 异常类型 as 异常名:
            代码块(出现错误以后的处理方式)
        except 异常类型 as 异常名:
            代码块(出现错误以后的处理方式)
        except 异常类型 as 异常名:
            代码块(出现错误以后的处理方式)
        else:
            代码块(没出错时要执行的语句)    
        finally:
            代码块(该代码块总会执行)    

  • try是必须的 ,else语句有没有都行, except和finally至少有一个
  • 可以将可能出错的代码放入到try语句,这样如果代码没有错误,则会正常执行, 如果出现错误,则会执行expect子句中的代码,这样我们就可以通过代码来处理异常,避免因为一个异常导致整个程序的终止
print('程序运行')
l = []
try:
    # print(c)
    # l[10]
    # 1 + 'hello'
    print(10/0)
except NameError:
    # 如果except后不跟任何的内容,则此时它会捕获到所有的异常
    # 如果在except后跟着一个异常的类型,那么此时它只会捕获该类型的异常
    print('出现 NameError 异常')
except ZeroDivisionError:
    print('出现 ZeroDivisionError 异常')
except IndexError:
    print('出现 IndexError 异常')
except Exception as e :
    # Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常
    # 可以在异常类后边跟着一个 as xx 此时xx就是异常对象
    print('未知异常',e,type(e))
finally :
    print('finally语句:无论是否出现异常,该子句都会执行')

print('运行结束')

3.3,异常的传播

  • 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播,直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息
  • 当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中,而异常传播时,实际上就是异常对象抛给了调用处
    比如 :
    ZeroDivisionError类的对象专门用来表示除0的异常
    NameError类的对象专门用来处理变量错误的异常
    Python为我们提供了多个异常对象
  • 下面这个事例:异常本来在func1中,由于没有处理,逐步被抛出到调用处,在func3出还没有处理,异常被抛出。
def func1():
    print('Hello func1')
    # print(10/0)

def func2():
    print('Hello func2')
    func1()

def func3():
    print('Hello func3')
    func2()

func3()

3.4,抛出异常和自定义异常

  • 自定义异常:创建一个类继承Exception即可,Exception是所有异常类的父类
  • 抛出异常:使用 raise 语句来抛出异常,raise语句后需要跟一个异常类 或 异常的实例
  • 抛出异常的目的:告诉调用者这里调用时出现问题,希望你自己处理一下
# 也可以自定义异常类,只需要创建一个类继承Exception即可
class MyError(Exception):
    pass

def add(a, b):
    # 如果a和b中有负数,就向调用处抛出异常
    if a < 0 or b < 0:
        # raise用于向外部抛出异常,后边可以跟一个异常类,或异常类的实例
        # raise Exception    
        # 抛出异常的目的,告诉调用者这里调用时出现问题,希望你自己处理一下
        raise MyError('自定义的异常:有负数抛出')

        # 也可以通过if else来代替异常的处理
        # return None
    r = a + b
    return r

print(add(-123, 456))

04,文件

  • 通过Python程序来对计算机中的各种文件进行增删改查的操作
  • I/O(Input / Output)
  • 操作文件的步骤:
    ① 打开文件
    ② 对文件进行各种操作(读、写),然后保存
    ③ 关闭文件

4.1,打开文件

  • open()函数:Python内置函数
    参数:
    file 要打开的文件的名字(路径)
    返回值:
    返回一个对象,这个对象就代表了当前打开的文件
  • 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可
  • 在windows系统使用路径时,可以使用/来代替\, 或者可以使用 \\来代替\,或者也可以使用原始字符串
# 创建一个变量,来保存文件的名字
# 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可
file_name = 'demo.txt'

# 在windows系统使用路径时
# file_name = 'hello\\demo.txt'

# 表示路径,可以使用..来返回一级目录
# file_name = '../hello/demo.txt'

# 如果目标文件距离当前文件比较远,此时可以使用绝对路径
# 绝对路径应该从磁盘的根目录开始书写
# file_name = r'C:\Users\AISMALL\Desktop\hello.txt'

file_obj = open(file_name,encoding='utf-8') # 打开 file_name 对应的文件

# print(file_obj)

4.2,关闭文件

  • 当我们打开文件后,所有的操作都应该使用文件对象来进行操作
  • read()函数:用来读取文件中的内容,它会将内容全部保存为一个字符串返回
  • close()方法:关闭文件
# 打开文件
file_name = 'demo.txt'
file_obj = open(file_name,encoding='utf-8')

# 当我们获取了文件对象以后,所有的对文件的操作都应该通过对象来进行
content = file_obj.read()
print(content)

# 调用close()方法来关闭文件
file_obj.close()

  • 文件的另一种打开方式使用:with....as 语句
# with ... as 语句
# with open(file_name) as file_obj :
#     # 在with语句中可以直接使用file_obj来做文件操作
#     # 此时这个文件只能在with中使用,一旦with结束则文件会自动close()
#     print(file_obj.read())

file_name = 'demo.txt'
try:
    with open(file_name,encoding='utf-8') as file_obj :
        print(file_obj.read())
except FileNotFoundError:
    print(f'{file_name} 文件不存在~~')

4.3,文件读取

  • 调用open()来打开一个文件,可以将文件分成两种类型
    一种,是纯文本文件(使用utf-8等编码编写的文本文件)
    一种,是二进制文件(图片、mp3、ppt等这些文件)
  • open()打开文件时,默认是以文本文件的形式打开的,但是open()默认的编码为None,所以处理文本文件时,必须要指定文件的编码
    例如:open(file_name,encoding='utf-8')
  • 通过read()来读取文件中的内容,它会将文本文件的所有内容全部都读取出来,如果要读取的文件较大的话,会一次性将文件的内容加载到内存中,容易导致内存泄漏,所以对于较大的文件,不要直接调用read()
  • read()可以接收一个size作为参数,该参数用来指定要读取的字符的数量
    默认值为-1,它会读取文件中的所有字符,可以为size指定一个值,这样read()会读取指定数量的字符,每一次读取都是从上次读取到位置开始读取的,如果字符的数量小于size,则会读取剩余所有的,如果已经读取到了文件的最后了,则会返回’'空串"
file_name = 'demo.txt'
try:
    with open(file_name,encoding='utf-8') as file_obj:
        # help(file_obj.read)
        # content = file_obj.read(-1)
        content = file_obj.read(6)
        print(content)
        print(len(content))

        content = file_obj.read(6)
        print(content)
        print(len(content))

        content = file_obj.read(6)
        print(content)
        print(len(content))
except FileNotFoundError :
    print(f'{file_name} 这个文件不存在!')
  • 读取大文件的时候使用下面这种方式:
# 读取大文件的方式
file_name = 'demo.txt'
try:
    with open(file_name, encoding='utf-8') as file_obj:
        # 定义一个变量,来保存文件的内容
        file_content = ''
        # 定义一个变量,来指定每次读取的大小
        chunk = 100
        # 创建一个循环来读取文件内容
        while True:
            # 读取chunk大小的内容
            content = file_obj.read(chunk)

            # 检查是否读取到了内容
            if not content:
                # 内容读取完毕,退出循环
                break

            # 输出内容
            # print(content,end='')
            file_content += content

except FileNotFoundError:
    print(f'{file_name} 这个文件不存在!')

print(file_content)
  • readline():该方法可以用来读取一行内容
file_name = 'demo.txt'
with open(file_name , encoding='utf-8') as file_obj:
    # readline():该方法可以用来读取一行内容
    # end='',不让print执行之后换行
    print(file_obj.readline(),end='')
    print(file_obj.readline())
    print(file_obj.readline())
  • readlines():该方法用于一行一行的读取内容,它会一次性将读取到的内容封装到一个列表中返回
import pprint
import os
file_name = 'demo.txt'

with open(file_name , encoding='utf-8') as file_obj:
    r = file_obj.readlines()
    pprint.pprint(r[0])
    pprint.pprint(r[1])
    pprint.pprint(r[2])
  • for 循环逐行读取文件内容
file_name = 'demo.txt'

with open(file_name , encoding='utf-8') as file_obj:
    for t in file_obj:
        print(t,end='')

4.4,文件写入

  • 使用open()打开文件时必须要指定打开文件所要做的操作(读、写、追加)
    如果不指定操作类型,则默认是读取文件 , 而读取文件时是不能向文件中写入的
    r:表示只读的
    w:表示是可写的,使用w来写入文件时,如果文件不存在会创建文件,如果文件存在则会截断文件,截断文件指删除原来文件中的所有内容
    a:表示追加内容,如果文件不存在会创建文件,如果文件存在则会向文件中追加内容
    x:用来新建文件,如果文件不存在则创建,存在则报错
    +:为操作符增加功能
    r+:即可读又可写,文件不存在会报错
    w+:写的时候可读
    a+:追加的时候可读
    示例:
    open(file_name , 'w' , encoding='utf-8')
    open(file_name , 'r+' , encoding='utf-8')
  • write()函数:来向文件中写入内容,
    如果操作的是一个文本文件的话,则write()需要传递一个字符串作为参数
    该方法会可以分多次向文件中写入内容
    写入完成以后,该方法会返回写入的字符的个数
file_name = 'demo.txt'

with open(file_name,'w',encoding='utf-8') as file_obj:
	# \n为换行
    file_obj.write('aaa\n')
    r = file_obj.write(str(123)+'123123\n')
    print(r)
    r = file_obj.write('今天天气真不错')
    print(r)

4.5,二进制文件操作

  • open()函数的读取模式
    t:读取文本文件(默认值)
    b:读取二进制文件
    例如:
    读文本文件:rt,可简写为:r,读二进制文件:rb
    写文本文件:wt,可简写为:w,写二进制文件:wb
  • 读取文本文件时,size是以字符为单位的
  • 读取二进制文件时,size是以字节为单位
file_name = '小朋友你是否有很多问号.mp3'

with open(file_name , 'rb') as file_obj:
    print(file_obj.read(100))
    # 将读取到的内容写出来
    # 定义一个新的文件
    new_name = 'aa.mp3'
    
    with open(new_name , 'wb') as new_obj:
        # 定义每次读取的大小
        chunk = 1024 * 100
        while True :
            # 从已有的对象中读取数据
            content = file_obj.read(chunk)
            # 内容读取完毕,终止循环
            if not content :
                break
            # 将读取到的数据写入到新对象中
            new_obj.write(content)
  • tell()方法:用来查看当前读取的位置
    例如: file_obj.tell()
  • seek() 方法:可以修改当前读取的位置,指定从哪个位置开始读
    seek()需要两个参数
    第一个 是要切换到的位置
    第二个 计算位置方式
    可选值:
    • 0 从头计算,默认值
    • 1 从当前位置计算
    • 2 从最后位置开始计算

例如:file_obj.seek(9),从第9个字符开始读

with open('demo.txt','rb') as file_obj:
    print(file_obj.read(30))
    # tell() 方法用来查看当前读取的位置
    print('当前读取到了 -->', file_obj.tell())

    # seek():可以修改当前读取的位置
    file_obj.seek(55)
    # file_obj.seek(80, 0)
    # file_obj.seek(70, 1)
    # file_obj.seek(-10, 2)
    print(file_obj.read())

4.6,文件的其他操作

import os
from pprint import pprint
# os包中的方法

# os.listdir() 获取指定目录的目录结构
# 需要一个路径作为参数,会获取到该路径下的目录结构,默认路径为 . 当前目录
# 该方法会返回一个列表,目录中的每一个文件(夹)的名字都是列表中的一个元素
# r = os.listdir()

# os.getcwd() 获取当前所在的目录
r = os.getcwd()

# os.chdir() 切换当前所在的目录 作用相当于 cd
# os.chdir('c:/')

# 创建目录
# os.mkdir("aaa") # 在当前目录下创建一个名字为 aaa 的目录

# 删除目录
# os.rmdir('abc')

# 打开文件
# open('aa.txt','w')

# 删除文件
# os.remove('aa.txt')

# os.rename('旧名字','新名字') 可以对一个文件进行重命名,也可以用来移动一个文件
# os.rename('aa.txt','bb.txt')
# os.rename('bb.txt','c:/users/AISMALL/desktop/bb.txt')
pprint(r)

猜你喜欢

转载自blog.csdn.net/weixin_45583303/article/details/107197879
今日推荐