跳至主要內容

02.python的基础知识(二)

pinia原创大约 18 分钟pythonpython

BUG

Bug的由来及其分类

Bug的常见类型

  • 粗心导致的语法错误:SyntaxError
    1. 末尾的冒号
    2. 缩进错误
    3. 英文写成中文
    4. 字符串拼接
    5. 没有定义变量
    6. ==和=混用
  • 知识点不熟练的错误
    1. 索引越界的错误:IndexError
    2. append()方法使用不熟练的错误
  • 思路不清楚导致的问题
  • 被动掉坑:程序逻辑没有问题,只是因为用户错误操作或者一些“例外操作”而导致程序崩溃

不同异常类型的处理方式

  • python提供了异常处理机制,可以在异常出现时及时捕获,然后内部消化,让程序继续运行
  • 捕获异常的顺序按照先子类后父类的顺序,为了避免可能出现的异常,可以在最后增加BaseException
  • try...except...else结构
    • 如果try块中没有抛出异常,则执行else块,如果try中抛出异常,执行except块
try:
    n1 = int(input('请输入一个整数:'))
    n2 = int(input('请输入一个整数:'))
    result = n1 / n2
    print("结果为",result)
except ZeroDivisionError:
    print('输入的整数不能为0')
except ValueError:
    print('输入的不是整数')
except BaseException as e:
    print('未知错误',e)
    
  • try...except...else...finally结构
    • finally块无论是否发生异常都会被执行,通常用来释放try块中申请的资源
try:
    n1 = int(input('请输入一个整数:'))
    n2 = int(input('请输入一个整数:'))
    result = n1 / n2
except BaseException as e:
    print('未知错误',e)
else:
    print("结果为",'%.2f'%result)
finally:
    print('无论程序是否出错,都会执行的代码')
  • python常见的异常类型
    1. ZeroDivisionError:除(或取模)零(所有的数据类型)数学运算时的异常
    2. IndexError:序列中没有此索引(index)
    3. KeyError:映射中没有这个键
    4. NameError:未声明/初始化对象(没有属性)
    5. SyntaxError:Python的语法错误
    6. ValueError:传入无效的参数

异常处理机制

  • traceback模块
    • 使用traceback模块打印异常信息
import traceback as back
try:
    print(1/0)
except Exception as e:
    back.print_exc()

PyCharm的调试模式

  • 断点
    • 程序运行到此处,暂时挂起,停止执行,可以详细观察程序的运行情况,方便做出进一步的判断
  • 进入调试视图
    • 进入调试视图的三种方式
      • 点击工具栏上的按钮
      • 右键单击编辑区,点击“debug模块名”
      • 快捷键Shift+F9

编程界的俩大思想

俩大编程思想

  • 面向过程
    • 事务比较简单,可以用线性思维去解决问题
  • 面向对象
    • 事务比较复杂,使用简单的线性思维无法解决问题
  • 面向过程和面向对象都是解决实际问题的一种思维方式,二者相辅相成,不是对立的,解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间的复杂关系,方便我们分析整个系统,具体到微观操作,我们仍然使用面向过程方式来处理

类和对象的创建

  • 类:是多个类似事物组成的群体的统称,能够帮助我们快速处理和判断事物的性质
  • 对象:Python一切皆对象
  • 类创建的语法:
    • 类名可以由一个或多个单词组成,每个单词首字母大写,其余都小写
class 类名:
	pass

class Stuednt:
    pass

print(id(Stuednt)) #1168198039840
print(type(Stuednt)) #<class 'type'>
print(Stuednt) #<class '__main__.Stuednt'>
  • 类的组成
    • 类属性
      • 直接写在类里的变量,称为类属性
      • 类中方法外的变量称为属性,被该类的所有对象所共享
    • 实例方法
      • 在类之外定义的称为函数,在类之外定义的称为方法
    • 静态方法
      • 使用@static修饰的方法,使用类名直接访问的方法
    • 类方法
      • 使用@classmethod修饰的方法,使用类名直接访问的方法
class Stuednt:
    # 类属性
    native_pace = '吉林' # 直接写在类里的变量,称为类属性
    #初始化方法
    def __init__(self,name,age):
        # 实例属性
        self.name = name  #self.name称为实例属性,进行了一个赋值操作,将局部变量的name的值赋值给实例变量的name
        self.age = age
    #实例方法
    def eat(self): # self 形参,代表类的实例对象
        print('我是eat方法')
    # 类方法
    @classmethod
    def cm(cls):
        print('我是一个类方法,因为我使用了@classmethod装饰器')
    #静态方法
    @staticmethod
    def sm():
        print('使用了@staticmethod定义的方法,我是一个静态方法')
  • 对象的创建

    • 对象的创建又称为对象的实例化
    • 语法
    实例化=类名()
    
    class Stuednt:
        # 类属性
        native_pace = '吉林' # 直接写在类里的变量,称为类属性
        #初始化方法
        def __init__(self,name,age):
            # 实例属性
            self.name = name  #self.name称为实例属性,进行了一个赋值操作,将局部变量的name的值赋值给实例变量的name
            self.age = age
        #实例方法
        def eat(self): # self 形参,代表类的实例对象
            print('我是eat方法')
        # 类方法
        @classmethod
        def cm(cls):
            print('我是一个类方法,因为我使用了@classmethod装饰器')
        #静态方法
        @staticmethod
        def sm():
            print('使用了@staticmethod定义的方法,我是一个静态方法')
    
    # 创建Stuednt类的实例对象
    stul = Stuednt('张三',20)
    print(id(stul)) # id()可以获取对象的内存地址
    print(type(stul)) # type()可以获取对象的类型
    print(stul) # 打印对象,会自动调用对象的__str__()方法
    stul.eat() # 调用对象中的eat()方法
    Stuednt.eat(stul) # 用类调用对象中的eat()方法
    
  • 动态绑定属性和方法

    • python语言是动态语言,在创建对象之后,可以动态地绑定属性和方法
class Student:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
    def eat(self):
        print(self.name+"吃饭")
student1 = Student("张三", 18, 100)
student1.gender = "男"
def show():
    print("我是show函数")
student1.show = show
print(student1.name, student1.age, student1.score,student1.gender,student1.show)

面向对象

封装

  • 封装:提高程序的安全性
    • 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度
    • 在Python中没有专门的修饰符用于属性的私有性,如果该属性不希望在类对象的外部被访问,前边使用俩个“_”.
class Car:
    def __init__(self, brand, color):
        self.brand = brand
        self.__color = color # 加__会变为,私有属性

    def run(self):
        print(self.brand + " is running")

car01 = Car("BMW", "red")
car01.run()
print(car01.brand)
# print(car01.__color) # 会报错,因为__color是私有属性,不能直接访问
print(dir(car01)) # 通过dir()函数可以查看对象的所有属性
print(car01._Car__color) # 通过这种方式可以访问私有属性

继承

  • 继承:提高代码的复用性

  • 语法格式:

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

  • Python支持多继承

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

class animal:
    def __init__(self, name, color):
        self.name = name
        self.color = color

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


class reptile(animal):
    def __init__(self, name, color, length):
        super().__init__(name, color)
        self.length = length
    def run(self):
        print("爬行")

animal01 = reptile("蜥蜴", "绿色", 0.5)
print(animal01.name,animal01.color,animal01.length)

多态

  • 多态:提高程序的可扩展性和可维护性
  • 简单地说,多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态地决定调用哪个对象中的方法

面试题

静态语言(java)和动态语言(Python)关于多态的区别

  • 静态语言实现多态的三个必要条件
    • 继承
    • 方法重写
    • 父类引用指向子类对象
  • 动态语言的多态崇尚“鸭子类型”,在鸭子类型中,不需要关心是什么类型,到底是不是鸭子,只关心对象的行为

方法重写(继承)

  • 如果子类对继承自父类的某个属性或方法不满意时,可以在子类中对其(方法体)进行重新编写
  • 子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法
class animal:
    def __init__(self, name, color):
        self.name = name
        self.color = color

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


class reptile(animal):
    def __init__(self, name, color, length):
        super().__init__(name, color)
        self.length = length
    def info(self):
        super().info() 
        print('长度:', self.length)

animal01 = reptile("蜥蜴", "绿色", 0.5)
animal01.info()

object类

  • Object类是所有类的父类,因此所有的类都有object类的属性和方法
  • 内置的dir()函数可以查指定对象的所有属性
  • Object有一个__ str __()方法,用于返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对__ str __()进行重写
class animal:
    def __init__(self, name, color):
        self.name = name
        self.color = color

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

    def __str__(self):
        return 'animal{0}{1}'.format(self.name, self.color)


class reptile(animal):
    def __init__(self, name, color, length):
        super().__init__(name, color)
        self.length = length

    def info(self):
        super().info()
        print('长度:', self.length)


animal01 = reptile("蜥蜴", "绿色", 0.5)
print(dir(animal01))
print(animal01)  # 默认会调用__str__方法

特殊方法和特殊属性

名称描述
特殊属性__ dict __获得类对象或实例对象所绑定的所有属性和方法的字典
__ class __输出对象所属的类
__ base __输出第一个父类类型所属的类(所有基类)
__ bases __输出所有父类类型所属的类(第一个基类)
__ mor __输出类的层次结构
__ subclasses __输出所有子类类型所属的类
特殊方法__ len __通过重写__ len __()方法,可以让内置函数len()的参数可以是自定义类型
__ add __通过重写__ add __()方法,可使用自定义对象具有“+”功能
__ new __用于创建对象
__ init __对创建的对象进行初始化
class Student:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

    def __add__(self, other):
            return self.score + other.score

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

student1 = Student('张三', 18, 100)
student2 = Student('李四人', 20, 90)
print(student1.score,student2.score)
score1 = int(student1.score) + int(student2.score) # 两个对象的成绩相加(因为在类中定义了__add__方法,所以可以直接相加)
score2 = (int(student1.score)).__add__(int(student2.score))
print(score1,score2)
print(len(student1.name),student2.name.__len__()) # 打印学生姓名的长度(因为在类中定义了__len__方法,所以可以直接调用len方法)
class Student:
    def __new__(cls, *args, **kwargs):
        print('__new__被调用执行了,cls的id值为{0}'.format(id(cls))) #3.__new__被调用执行了,cls的id值为1753397861392
        obj = super().__new__(cls)
        print('创建的对象的id为:{0}'.format(id(obj))) #4.创建的对象的id为:1753398456400
        return obj
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
        print('__init__被调用执行了,self的id值为{0}'.format(id(self)))# 5.__init__被调用执行了,self的id值为1753398456400

print('object这个类对象的id为:{0}'.format(id(object))) #1.object这个类对象的id为:140718958743024
print('Student这个类对象的id为:{0}'.format(id(Student))) #2.Student这个类对象的id为:1753397861392

student1 = Student('张三', 20, 100)
print('student1这个对象的id为:{0}'.format(id(student1))) #6.student1这个对象的id为:1753398456400

类的浅拷贝和深拷贝

变量的赋值操作

  • 只是形成俩个变量,实际上还是指向同一个对象

浅拷贝

  • Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象

深拷贝

  • 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象的所有子对象也不相同
class CPU:
    def __init__(self, model, frequency, core):
        self.model = model
        self.frequency = frequency
        self.core = core

    def show(self):
        print("CPU型号:", self.model)
        print("CPU频率:", self.frequency)
        print("CPU核数:", self.core)
class Disk:
    def __init__(self, model, capacity):
        self.model = model
        self.capacity = capacity

    def show(self):
        print("硬盘型号:", self.model)
        print("硬盘容量:", self.capacity)
class Computer:
    def __init__(self, cpu, disk):
        self.cpu = cpu
        self.disk = disk

    def show(self):
        print("电脑CPU信息:")
        self.cpu.show()
        print("电脑硬盘信息:")
        self.disk.show()

#类对象的赋值操作
cpu1 = CPU("Intel i5", "3.5GHz", 4)
cpu2 =cpu1
print(cpu1,cpu2) # 两个变量指向同一个对象<__main__.CPU object at 0x000001A703CC3A10> <__main__.CPU object at 0x000001A703CC3A10>

#类对象的浅拷贝
disk = Disk("三星", "1T")#创建一个Disk对象
computer1 = Computer(cpu1, disk)#computer1对象的cpu属性指向cpu1对象,disk属性指向disk对象
import copy
computer2 = copy.copy(computer1)#浅拷贝,computer2对象的cpu属性指向cpu1对象,disk属性指向disk对象
print(computer1, computer1.cpu,computer1.disk) #<__main__.Computer object at 0x000001A703CC3B50> <__main__.CPU object at 0x000001A703CC3A10> <__main__.Disk object at 0x000001A703CC3A90>
print(computer2, computer2.cpu,computer2.disk) #<__main__.Computer object at 0x000001A703CC3B80> <__main__.CPU object at 0x000001A703CC3A10> <__main__.Disk object at 0x000001A703CC3A90>

#类对象的深拷贝
computer3 = copy.deepcopy(computer1)#深拷贝,computer3对象的cpu属性指向cpu1对象,disk属性指向disk对象
print(computer3, computer3.cpu,computer3.disk) #<__main__.Computer object at 0x000001A703CC3C10> <__main__.CPU object at 0x000001A703CC3A50> <__main__.Disk object at 0x000001A703CC3AF0>

模块化

模块的定义

  • 模块的应为为Modules
  • 函数与模块的关系
    • 一个模块中可以包含N多个函数
  • 在Python中一个扩展名为.py的文件就是一个模块
  • 使用模块的好处
    • 方便其他程序和脚本的导入并使用
    • 避免函数名和变量名的冲突
    • 提高代码的可维护性
    • 提高代码的可重用性

自定义模块

  • 创建自定义模块
    • 新建一个.py文件,名字尽量不要与Python自带的标准模块名称相同
  • 导入模块
import 模块名称 [as 别名]
from 模块名称 import 函数/变量/

以主程序的形式执行

  • 以主程序形式运行程序
    • 在每个模块的定义中都包括一个记录模块名称的变量__ name __ ,程序可以检查到该变量,已确定他们在哪个模块中执行。如果一个模块不是被导入到其他程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的__ name __ 变量的值为__ main __
if __name__ == '__main__':
    print(add(1, 2)) #只有在当前模块中才会执行

python中的包

  • 包时一个分层次的一个目录,它将一组功能相近的模块组织在一个目录下

  • 作用

    • 代码规范
    • 避免模块名称的冲突
  • 包与目录的区别

    • 包含__ init __.py文件的目录称为包
    • 目录里通常不包含__ init __.py文件
  • 包的导入

    import 包名.模块名
    
  • 导入带有包的模块时注意事项

    • 使用import方式进行导入时,只能导入包名或者模块名
    • 使用form...import导入时可以导入函数/变量/模块名

python中常用的内置模块

模块名描述
sys与Python解释器及其环境操作相关的标准库
time提供与时间相关的各种函数的标准库
os提供了访问操作系统服务功能的标准库
calendar提供了与日期相关的各种函数的标准库
urllib用于读取来自网上(服务器)的标准数据库
json用于使用JSON序列化和反序列化对象
re用于在字符串中执行正则表达式匹配和替换
math提供标准运算函数的标准库
decimal用于进行精确控制运算精度,有效数位和四舍五入操作的十进制运算
logging提供了灵活的记录事件,错误,警告和调试信息等日志信息的功能

第三方模块的安装与使用

  • 第三方模块的安装

    pip install 模块名
    
  • 使用

    import 模块名
    

文件

编码格式的介绍

  • 常见的字符编码格式
    • Python的解释器使用的是Unicode(内存)
    • .py文件在磁盘上使用的UTF-8存储(外存)
  • 常见的编码
    • ASCII:7位表示1个字符,最高位是0,只能表示128字符
    • ISO8859-1:8位表示1个字符,能表示256个字符,兼容ASCII
    • Unicode:字长编码,2个字节表示1个字符,不兼容ISO8859-1
    • GB2312,GBK,GB18030兼容ISO8859-1英文1个字节,汉字2个字节
    • UTF-8:变长编码,1-4个字节表示一个1个字符,英文1个字节,汉字3个字节,UTF-8是基于Unicode实现的

文件的读写原理

  • 文件的读写俗称“IO操作”
  • 文件读写操作流程
  • 操作原理
    • python操作文件——》打开或新建文件——》读写文件——》关闭资源

文件的读写操作

  • 内置函数open()函数创建文件对象

  • 语法

    file = open(filename [,mode,encoding])
    
    file = open('a.txt', 'r' ,encoding='utf-8')
    print(file.readlines()) # 读取所有行['中国\n', '美丽']
    print(file.readline()) # 读取一行
    file.close()
    

常用的文件打开模式

  • 文件类型
    • 按文件中数据的组织形式,文件可以分为以下俩大类
      • 文本文件:存储的是普通“字符”文本,默认为unicode字符集,可以使用记事本程序打开
      • 二进制文件:把数据中内容用“字节”进行存储,无法用记事本打开,必须使用专业的软件打开,eg:mp3,jpg,doc
打开模式描述
r以只读模式打文件,文件的指针会放在文件的开头
w以只写模式打开文件,如果文件不存在则创建文件,如果文件存在,则覆盖原有内容,文件的指针在文件的开头
a以追加模式打开文件,如果文件不存在则创建文件,文件指针在文件开头,如果文件存在,则在文件末尾追加内容,文件指针在原文件末尾
b以二进制方式打开文件,不能单独使用,需要与其他模式一起使用,rb或wb
+以读写方式打开文件,不能单独使用,需要与其它模式一起使用,a+

文件对象的常用的方法

方法名说明
read([size])从文件中读取size个字节或者字符的内容返回,若省略size,则读取到文件末尾,即一次读取文件的所有内容
readline()从文本文件中读取第一行内容
readlines()把文本文件中每一行都作为独立的字符串对象,并将这些对象放入列表返回
write(str)将字符串str内容写入文件
writelines(s_list)将字符串列表s_list写入文本文件,不添加换行符
seek(offset,[,whence])把文件指针移动到新的位置,offset表示相对于whence的位置:offset:为正往结束方向移动,为负往开始方向移动,whence不同的值代表不同含义,0:从文件头开始计算,1:从当前位置开始计算,2:从文件尾开始计算
tell()返回文件指针的位置
flush()把缓存区的内容写入文件,但不关闭文件
close()把缓存区的内容写入文件,同时关闭文件,释放文件对象相关资源

with语句(上下文管理器)

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

  • 语法

    with 上下文表达式 as 格式化文件名
    with open('b.txt', 'r', encoding='utf-8') as file:
        print(file.read())
    
  • 原理

    """
    MyContentMgr类中定义了__enter__和__exit__方法,这个类遵守了上下文管理器协议,这个类对象的实例对象称为上下文管理器
    """
    class MyContentMgr:
        def __enter__(self):
            print('enter方法被调用执行了')
            return self
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('exit方法被调用执行了')
        def show(self):
            print('show方法被调用执行了')
    
    with MyContentMgr() as file:
        file.show()
    """
    enter方法被调用执行了
    show方法被调用执行了
    exit方法被调用执行了
    """
    
  • 图片的复制

    # 1.打开文件
    with open('logo1.png', 'rb') as file1:
        # 2.读取文件
        with open('logo2.png', 'wb') as file2:
            # 3.写入文件
            file2.write(file1.read())
    

目录操作

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

#直接调用可执行文件
os.startfile('C:\Users\pinia\Desktop\python\python\pageage\demo1.py')

os模块操作目录相关函数

函数说明
getcwd()返回当前的工作目录
listdir(path)返回指定路径下的文件和目录信息
mkdir(path[,mode])创建目录
makedirs(path1/path2...[,mode])创建多级目录
rmdir(path)删除目录
removedirs(path1/path2...)删除多级目录
chdir(path)将path设置为当前工作目录
walk(path)深层遍历文件目录

os.path模块操作目录相关函数

函数说明
adspath(path)用于获取文件或目录的绝对路径
exists(path)用于判断文件或目录是否存在,如果存在返回True,否则返回False
join(path,name)将目录与目录或者文件名拼接起来
split()分离目录名与文件名
splitext()分离文件名和扩展名
basename(path)从一个目录中提取文件名
dirrname(path)从一个路径中提取文件路径,不包括文件名
isdir(path)用于判断是否为路径
上次编辑于:
贡献者: 林深不见鹿