🐍Python
2023-6-26
| 2024-5-26
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
password
category
Property
May 26, 2024 10:19 AM
icon

面向对象编程

  • 把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。对封装的理解是"隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口
  • 程序中的数据和操作数据的函数是一个逻辑上的整体,我们称之为“对象”,而我们解决问题的方式就是创建出需要的对象并向对象发出各种各样的消息,多个对象的协同工作最终可以让我们构造出复杂的系统来解决现实中的问题。
  • __init__是一个特殊方法用于在创建对象时进行初始化操作
  • 写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。
  • 大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻,
  • 在Python的类中,self是一个特殊的参数,用于指代对象本身。当调用一个方法时,Python会自动将调用该方法的对象传递给self参数,以便在方法内部可以访问该对象的属性和方法。因此,在类中定义方法时,第一个参数通常都是self。例如,在类中定义一个名为foo的方法,其定义应该类似于def foo(self, arg1, arg2):,其中self参数可以访问该方法所属的对象的属性和方法,而arg1和arg2则是该方法的其他参数。
 

一、数据类型

1.1、字符串

  • 可以在字符串中使用\(反斜杠)来表示转义,也就是说\后面的字符不再是它原来的意义,例如:\n不是代表反斜杠和字符n,而是表示换行;而\t也不是代表反斜杠和字符t,而是表示制表符。所以如果想在字符串中表示'要写成\',同理想表示\要写成\\
  • 如果不希望字符串中的\表示转义,我们可以通过在字符串的最前面加上字母r来加以说明,如:s1 = r'\'hello, world!\'' 前缀 r 和 f 可以一起使用
  • Python为字符串类型提供了非常丰富的运算符,我们可以使用+运算符来实现字符串的拼接,可以使用*运算符来重复一个字符串的内容,可使用innot in来判断一个字符串是否包含另外一个字符串(成员运算),我们也可以用[][:]运算符从字符串取出某个字符或某些字符(切片运算)
  • 格式化输出字符串:占位符 ◦ a, b = 5, 10print(f'{a} * {b} = {a * b}') python3.6之后的写法 ◦ print('%d * %d = %d' % (a, b, a * b))print('{0} * {1} = {2}'.format(a, b, a * b))
  • 在Python中,我们还可以通过一系列的方法来完成对字符串的处理:

1.2、列表

  • 列表(list),也是一种结构化的、非标量类型,它是值的有序序列,每个值都可以通过索引进行标识,定义列表可以将列表的元素放在[]中,多个元素用,进行分隔,可以使用for循环对列表元素进行遍历,也可以使用[][:]运算符取出列表中的一个或多个元素。
  • 列表生成式: ◦ f = [x for x in range(1, 10)]f = [x*2 for x in range(1, 10) if x>5]f = [x*2 if x>5 else x for x in range(1, 10)]f = [x + y for x in 'ABCDE' for y in '1234567']f = [(name, sex) for name, sex in zip(list1, list2)]

1.3、元组

Python中的元组与列表类似也是一种容器数据类型,可以用一个变量(对象)来存储多个数据,不同之处在于元组的元素不能修改
这里有一个非常值得探讨的问题,我们已经有了列表这种数据结构,为什么还需要元组这样的类型呢?
  • 元组中的元素是无法修改的,事实上我们在项目中尤其是多线程环境(后面会讲到)中可能更喜欢使用的是那些不变对象(一方面因为对象状态不能修改,所以可以避免由此引起的不必要的程序错误,简单的说就是一个不变的对象要比可变的对象更加容易维护;另一方面因为没有任何一个线程能够修改不变对象的内部状态,一个不变对象自动就是线程安全的,这样就可以省掉处理同步化的开销。一个不变对象可以方便的被共享访问)。所以结论就是:如果不需要对元素进行添加、删除、修改的时候,可以考虑使用元组,当然如果一个方法要返回多个值,使用元组也是不错的选择。
  • 元组在创建时间和占用的空间上面都优于列表。我们可以使用sys模块的getsizeof函数来检查存储同样的元素的元组和列表各自占用了多少内存空间,这个很容易做到。我们也可以在ipython中使用魔法指令%timeit来分析创建同样内容的元组和列表所花费的时间,

1.4、集合

Python中的集合跟数学上的集合是一致的,不允许有重复元素,而且可以进行交集、并集、差集、补集等运算。
notion image

1.5、字典

Python中的字典跟我们生活中使用的字典是一样一样的,它可以存储任意类型对象,与列表、集合不同的是,字典的每个元素都是由一个键和一个值组成的“键值对”,键和值通过冒号分开。

1.6、json

将python类型数据转换成json
将json类型转换成Python数据类型

二、模块/函数

2.1、zip 函数

  • 传入一个列表时,zip函数会将这个列表内每个元素单独构成元组,返回由这些元组组成的列表。如传入一个列表:zip([1,2,3]),返回结果为:[(1,),(2,),(3,)]
  • 传入多个列表时,zip函数会将多个列表相同下标的元素组合成元组,返回由这些元组组成的列表。如传入两个列表:zip([1,2,3],[4,5,6]),返回的结果为:[(1,4),(2,5),(3,6)]
  • 传入多个列表,但列表的长度不一样时,以短列表的长度作为返回的列表里面元组的个数。如传入不同长度的列表:zip([1,2],[3,4,5]),返回值是:[(1,3),(2,4)]
  • 传入一个二维的数据类型:zip(*[[1,2],[3,4]]),返回的结果为:[(1,3),(2,4)]。*表示处理二维或多维数据

2.2、chain 函数

chain 函数它将所有可迭代对象组合在一起,并生成一个可迭代对象作为输出。
当输入只有一个参数,但参数是一个二维的可迭代对象是前面加个星号(*)*表示处理二维或多维数据
常规用法
一个参数不带*
一个参数带*

2.3、itertools 模块

2.4、sorted 函数

sorted() 函数对所有可迭代的对象进行排序操作。
参数说明:
  • iterable -- 可迭代对象。
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
你也可以使用 list 的 list.sort() 方法
另一个区别在于list.sort() 方法只为 list 定义。而 sorted() 函数可以接收任何的 iterable。
示例:

三、类和对象

简单的说,类是对象的蓝图和模板,而对象是类的实例。这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的东西。在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做“类”的东西。

3.1、定义类

在Python中可以使用class关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。
说明:写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。

3.2、创建和使用对象

3.3、类的方法

3.3.1、魔法方法

3.3.2、实例方法

类的实例方法由实例调用,至少包含一个self参数,且为第一个参数。执行实例方法时,会自动将调用该方法的实例赋值给self。self 代表的是类的实例,而非类本身。self不是关键字,而是Python约定成俗的命名

3.3.3、静态方法

实际上,我们写在类中的方法并不需要都是对象方法,例如我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。
静态方法由类调用,无默认参数。将实例方法参数中的self去掉,然后在方法定义上方加上@staticmethod,就成为静态方法。它属于类,和实例无关。建议只使用类名.静态方法的调用方式。

3.3.4、类方法

类方法由类调用,采用@classmethod装饰,至少传入一个cls(代指类本身,类似self)参数,通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象。执行类方法时,自动将调用该方法的类赋值给cls(相当于是类调用了自己)。建议只使用类名.类方法的调用方式。

3.4、类的封装、继承和多态

面向对象有三大支柱:封装、继承和多态。
简单的说,类和类之间的关系有三种:is-a、has-a和use-a关系。
  • is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。
  • has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
  • use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。

四、文件/异常

4.1、文件读写的两个问题

打开什么样的文件(字符文件还是二进制文件)以及做什么样的操作(读、写还是追加)
  • 文件类型:t(文本类型)、b(二进制类型)
  • 操作模式:r(读)、w(写)、a(追加)、+(更新(可读可写))
  • 以上两种可以相互组合:(r、w、a默认是操作文本文件t的,所以下面t被省略了)
    • r, r+, rb, rb+
    • w, w+, wb, wb+
    • a, a+, ab, ab+
  • 多种模式的区别对比
    • 模式
      r
      r+
      w
      w+
      a
      a+
      写文件
      读文件
      ✓(有坑,详见下文)
      ✓(有坑,详见下文)
      创建文件
      覆盖文件
      r+
      读写模式
      能写,打开不存在的文件会报错;新写入的内容会覆盖原文件中的内容,写入几个字符,则覆盖几个字符
      w+
      写读模式
      能读,但是读不到内容,因为w先把文件内容清空了
      a+
      追加读模式
      能读,但读不到内容,因为文件指针默认在最后一行,可用seek移动文件指针位置;只针对读取文件,写文件还是只能从最后开始写

4.2、文件读写的两种方式

需要写入,直接将参数'r' 改为'w',追加改为'a'

4.2.1、直接读写

4.2.2、with关键字

4.2.3、按行读取

除了使用文件对象的read方法读取文件之外,还可以使用for-in循环逐行读取或者用readlines方法将文件按行读取到一个列表容器中

4.3、异常捕获

在Python中,我们可以将那些在运行时可能会出现状况的代码放在try代码块中,在try代码块的后面可以跟上一个或多个except来捕获可能出现的异常状况。例如在上面读取文件的过程中,文件找不到会引发FileNotFoundError,指定了未知的编码会引发LookupError,而如果读取文件时无法按指定方式解码会引发UnicodeDecodeError,我们在try后面跟上了三个except分别处理这三种不同的异常状况。最后我们使用finally代码块来关闭打开的文件,释放掉程序中获取的外部资源,由于finally块的代码不论程序正常还是异常都会执行到(甚至是调用了sys模块的exit函数退出Python环境,finally块都会被执行,因为exit函数实质上是引发了SystemExit异常),因此我们通常把finally块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。

4.4、读写文本文件

读取文本文件时,需要在使用open函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为'r'(如果不指定,默认值也是'r'),然后通过encoding参数指定编码(如果不指定,默认值是None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与encoding参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。

4.5、读写二进制文件

4.6、读写JSON文件

使用Python中的json模块就可以将字典或列表以JSON格式保存到文件中
json模块主要有四个比较重要的函数,分别是:
  • dump - 将Python对象按照JSON格式序列化到文件中
  • dumps - 将Python对象处理成JSON格式的字符串
  • load - 将文件中的JSON数据反序列化成对象
  • loads - 将字符串的内容反序列化成Python对象

五、使用经验

5.1、函数传参

单星号(*):*agrs;将所有参数以元组(tuple)的形式导入:
单星号的另一个用法是解压参数列表:
双星号(**):**kwargs;双星号(**)将参数以字典的形式导入
单星号和双星号一起使用:

5.2 *号的作用

在Python中,星号*有多种用途,具体取决于它的上下文:
  • 重复
  • 打包
  1. 在打包序列时,*于获取序列的一部分。例如:
    1. 在函数参数列表中,* 用于收集所有的位置参数到一个元组中。 将传入的多个值打包为一个序列。 例如:
      1. 在函数参数列表中,**用于收集所有的关键字参数到一个字典中。例如:
        • 解包
        1. 在函数调用时,*用于将一个序列(如列表或元组)拆分为单独的位置参数。例如:
          1. 用于合并两个序列
            1. 在函数调用时,**用于将一个字典拆分为单独的关键字参数。例如:
              1. notion image
            1. **多个字典的合并
            • 其它
            1. 在导入模块时,*用于导入模块中的所有内容。例如:
              1. 在数学运算中,*用作乘法运算符。例如:
                1.  
            2. Python
            3. 效率工具AI绘画Stable Diffusion上手
              Loading...
              目录