Python 语言
来源:python语言基础
文档:python官方文档
平台:华为云
Tips
- 1.一般三个字节表示一个中文字符;
- 2.通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素。
做切片操作时,总会返回一个新的列表,不会影响原来的列表。切片的索引也是从0开始的。 - ord() 函数返回的是其ASCII码值
- join() 将序列中的元素以指定的字符连接生成一个新的字符串:str.join(sequence)
wstr = "-"
seq = ("a", "b", "c")
print(wstr.join(seq)) # wstr为 a-b-c
- Python中提供了6种内置的数据类型:数值Number、字符串String、列表List、元祖Tuple、字典Dictionary、集合Set。
- Python中的复数由实数部分和虚数部分组成,二者都是浮点数;虚数不能单独存在,它们总是和一值为0.0的实数部分一起构成一个复数。复数对应的运算模块是cmath模块;
- Python中常见的内置函数有:求绝对值abs(x);四舍五入round(x); 返回两个数值的商和余数:divmod(y,x); 如果是不同的类型的数字(int,float)进行计算,则结果类型为精度较高的那个类型。
- Python中的字符串也是有序且不可变的。
- 元组是一个有序且不可变的序列,其中的元素可以是任意对象。元组的存储可以让数据更安全。元组中只有一个元素时,需要在元素后面加上[ , ],告诉解释器这不是运算符号中的括号。两个元组可以通过 + 拼接。
- 列表与数组:Python中列表和数组在形式上有点类似,但是本质不一样。Python中的内置数据结构中并没有数组,需要借助工具numpy实现。
- 集合有逻辑运算:交集:set1 & set2两个集合中相同的元素;对称差集:set1 ^ set2两个集合中不同的元素; 并集:set1 | set2两个集合内总共的元素(重复的删除); 差集:set1 - set2集合①中包含而集二②不包含的元素;
- 在Python中函数如果不使用return,不代表没有返回值,而是返回None;返回值不是必须的,可以没有返回值(即返回none);多个返回值时实际上返回值的是元组,如return a, b, c
- pop是有返回值的,而remove是没有返回值的;
- 定义函数def下面的注释“” 内容 “”,在下面加上help(函数名)之后,可以使用help(函数名)查看注释内容。
- strip函数的作用是去空格,把str前面后面的空格都去掉;
- Python区分代码块的空格是没有限制的,可以4个(常用),也可以是3个。
- Python定义字符串是可以采用单引号和双引号(没有区别),也可以使用三引号(支持换行)。
7 文件操作
文件打开
-
open(file, mode=‘r’, buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)
使用 open打开一个文件- 参数:file 表示要打开的文件的名字(路径)
- 返回值:返回一个对象,这个对象就代表了当前打开的文件
-
在windows系统下使用路径时,可以使用 /来代替 \,或者使用 \ 来代替 \,或者在原始字符串前面 +r 。
-
如果目标文件距离当前文件比较远,则此时可以使用绝对路径(从磁盘的根目录开始写)如:
file_name = r’D:\CODE\PycharmProjects\Python\test.txt’ file_obj = open(file_name) #打开file_name对应的文件
文件读取
-
方法1:调用open()来打开一个文件,可以将文件分为两种类型。open()默认的是以文本文件形式打开的:
- 1)纯文本文件(使用utf-8等编码编写的文本文件)
- 2)二进制文件(图片,mp3, ppt等这些文件)
-
如果需要读取中文,需要指定编码格式: with open(file_name, encoding=‘utf-8’) as file_obj:
-
如果是直接调用 read()来读取文件中的内容时,会将文本文件的所有内容全部都读取出来,read()可以接受一个参数size,
该参数用来指定要读取的字符的数量: content=file_obj.read(6)- 每一次读取都是从上次读取的位置开始读取的;
- 如果剩下的字符数量小于 size, 则会读取剩下所有的
- 如果已经读取到了文件的最后,则会返回 ‘’ 空串
-
如果待读取的文件很大时,会一次性将文件的内容加载到内容中,容易导致内存泄漏;所以可以用size指定大小;
-
如果读取的是大文件:可以创建一个循环来读取文件,每次读取指定大小size的文件内容,示例如下:
with open(file_name,encoding='utf-8') as file_obj: file_content = '' #定义一个变量来保存文件内容 chunk = 100 #指定每次读取文件的大小 while True: content = file_obj.read(size = chunk) #每次读取chunk大小的文件 if not content: #检查是否读取到了内容 break #读取完毕,退出循环 file_content += content #每次读取的内容拼接到一起
-
方法2:
-
readline() 每次只读取一行
-
readlines() 每次读取一行将读取到的内容封装到一个列表中返回
with open(file_name,encoding='utf-8') as file_obj: #r = file_obj.readlines() #pprint.pprint(r[0]) #pprint.pprint(r[1]) for t in file_obj: print(t)
文件写入
使用open() 打开文件时必须要指定打开文件所要做的操作(读,写,追加),如果不指定操作类型,则默认为 只读文件。
-
其他类型的操作:
-
r: 只读
-
w 可写,若文件不存在则创建文件,如果文件存在则会删除原文件内容,重新写入
-
a 追加内容,如果文件不存在则会创建文件,如果文件存在则会向文件中追加内容
-
x 用来新建文件,如果文件不存在则创建,存在则报错
-
+ 为操作符增加功能 r+ 既可读又可写,文件不存在则报错 w+ a+
with open(file_name,'w',encoding='utf-8') as file_obj: r = file_obj.readlines()
-
-
所有文本文件以外的文件都是二进制文件:音乐文件,视频文件都可以
-
b:读取二进制文件 <读取文本文件时,size以字符为单位,而读取二进制文件时,size是以字节为单位>
文件关闭
-
方式1:调用close()方法来关闭文件:file_obj.close()
-
方式2:with … as 语句:
with open(file_name) as file_obj: # 在with语句中可以直接使用file_obj来做文件操作,with结束则文件关闭 print(file_obj.read()) 示例: try: with open(file_name) as file_obj: # 在with语句中可以直接使用file_obj来做文件操作,with结束则文件关闭 print(file_obj.read()) except FileNotFoundError: print(f'{file_name} 文件不存在~~~')
文件的其他操作
- seek():可以修改文件读取的位置
- 参数1:要切换的位置:
- 参数2:计算位置的方式。可选值:0 从头开始,默认值 1:从当前位置计算 2:从最后位置开始计算
- tell(): 方法用来查看当前读取的位置
- print(‘当前读取到了 -->’,file_obj.tell())
- os.listdir() 获取指定目录的目录结构(所有文件结构)
- 需要一个路径作为参数,会获取到该路径下目录结构,默认路径为 . 当前目录
- 该方法会返回一个列表,目录中的每一个文件(文件夹)的名字都是列表中的一个元素;
- os.getcwd(): 获取当前所在的目录
- os.chdir(): 切换当前所在的目录,作用相当于cd
- os.mkdir(): 在当前目录下创建一个名字为 aaa 的目录
- os.rmdir(‘abc’):删除目录
- os.remove(‘aa.txt’):删除文件
- os.rename(‘旧名字’,‘新名字’) 可以对一个文件进行重命名,也可以用来移动一个文件
8 字典的使用
基本点
- 每个对象都保存了三个数据:id(标识)(相当于C中的内存地址) type(类型) value(值) 可变对象指的是【值】可变;
- a[0] = 10 通过变量去修改对象的值,这种操作不会改变变量所指向的对象,若有其他变量也指向该对象,则修改也会在其他的变量中体现
- a = [4,5,6] 给变量重新赋值,这种操作会改变变量所指向的对象,即a的id会重新分配一个;
- 一般只有在为变量重新赋值时才是修改变量,其余的都是修改对象;
- 运算符 == 和 != 比较的是对象的值是否相等,is 和 is not比较的是对象的id 是否相等,即比较的是同一个对象;
字典
字典属于一种新的数据结构,称为映射(mapping),其作用和列表类似,都是用来存储对象的容器;在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以快速查找到指定的元素。
key-value 每一项都有 键key和值value, 值可以是任意对象,而字典的键需要是任意不可变对象,且不能重复;
- 创建:
- { } 如:{k1: v1, k2:v2, k3:v3}
- d = dict(name=‘sun’,age=‘18’,gender='男‘)
- 将包含有双值子序列的序列转换为字典: d = dict([(‘name’,‘sun’),(‘age’,18)])
- 查询:in 和 not in
- 获取:根据键来获取值,语法:dict[key] 通过[]获取值时,若键不存在,则会抛出异常;通过get(key[ ,default])获取字典中的值,若键不存在,则返回None;
- 修改:d[key]=value 如果key存在则覆盖,如果key不存在,则加上即可;setdefault(key[ , default]) 若key存在于字典中,则返回key的值,不会对字典做任何操作,key不存在,则添加;
- 更新:update([other]):将其他字典中的key-value添加到当前字典中,如有重复的key,则后边的会替换到当前的;
- 删除:popitem() 删除最后一个键值对,删除之后,被删项以元组的形式返回; pop(key[, default])根据key删除字典中的key-value,没有组返回默认值
- 复制:copy() 对字典进行浅复制()
- 浅复制copy():复制以后的对象和原对象是独立的,修改一个不会影响另外一个(即两块不同的内存)。但浅复制只会简单的复制对象内部的值,若该值也是一个可变对象,则这个可变对象不会被复制;
拷贝父对象,不会拷贝对象内部的子对象。例:- d = {‘a’:{‘name’:‘sunwukung’,‘age’:18},‘b’:2,‘c’:3}
- d2 = d.copy()
- d2[‘a’][‘name’] = ‘bob’ //则都会改变
- 深复制deepcopy():完全拷贝了父对象及其子对象,连同内部的可变对象一起复制。复制以后的对象和原对象是独立的,修改一个不会影响另外一个。该复制性能差,一般都用浅复制;
- 浅复制copy():复制以后的对象和原对象是独立的,修改一个不会影响另外一个(即两块不同的内存)。但浅复制只会简单的复制对象内部的值,若该值也是一个可变对象,则这个可变对象不会被复制;
- 遍历:
- keys() 该方法会返回字典中所有的key: for k in d.keys(): print(k, d[k])
- items() 该方法会返回字典中所有的项,返回序列在包含有双值子序列,双值就是字典中的key,value. for k, value in d.items():print(k,’:’,value)
集合set
集合和列表非常相似,其不同点在于:1)集合中只能存储不可变对象(列表啥的不行); 2)集合中存储的对象是无序的; 3)集合中不能出现重复元素;
集合运算:在集合作运算时不会对集合本身产生影响;
- 交集运算 & :两个集合重复的部分: ret = s & s2
- 并集运算 | :两个集合的和部分: ret = s | s2
- 差集运算 - :一个集合去除另一个集合没有的部分: ret = s - s2
- 异或运算 ^ : 两个集合不同的部分: ret = s ^ s2
- <=: 检查一个集合是否是另外一个集合的子集
9 函数
基本点
-
不定长的函数参数,def sum(*nums) 可以求任意个数的数字和 此时nums是一个元组(装包) def fn(a,b,*c) 实参1给a,实参2给b,其他的给c;
-
带星号的参数只能有一个,可以和其他参数配合使用,带星号的参数后的所有参数,必须以关键字参数的形式传递;若形参的开头有一个*,则要求所有
的参数必须要以关键字参数的形式传递;即在实参传递的时候需要指定; -
*形参只能接受位置参数,而不能接受关键字参数,而**形参可以接受关键字参数,它会将这些参数统一保存到一个字典中,字典的key就是参数的名字,
字典的value就是参数的值;例如:def fn(**a): …… 调用时:fn3(b=1,d=2,c=3) 返回:a={b:2,d:2,c:3} 类型为字典; -
**形参只能有一个,且必须写在所有参数的最后;
-
参数的解包(拆包)😗 传递参数时,可以在序列类型的参数前面添加*号,这样就自动将序列中的元素一次作为参数传递;
不过要求序列中的元素的个数必须和形参个数一致;**:通过**可以对字典进行解包操作;
如:d={‘a’:100,‘b’:200,‘c’:300} function(**d) -
函数的返回值return后可以跟任意对象,返回值甚至可以是一个函数,即返回对象就是一个函数;
-
若仅仅写一个return 或者不写return ,相当于return None;
-
def func1():…… print(func1)和print(func1())的区别:前者func1是函数对象,打印func1实际是在打印函数对象,<function func1 at 0x1111>
而后者是调用函数,返回是调用函数后的结果。
###文档字符串: -
定义的文档字符串:在函数的第一行,一般都是对该函数的说明。
-
def fn(a:int, b:bool, c:str=‘hello’) -> int: 显性表示形参的类型和返回值类型,非强制,建议使用
作用域:作用域指的是变量生效的区域
- python中只有两种作用域:全局作用域 和 函数作用域
- 全局作用域:
- 全局作用域在程序执行时创建,在程序执行结束时销毁
- 所有函数以外的区域都是全局作用域
- 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
- 函数作用域:
- 函数作用域在函数调用时创建,在调用结束时销毁
- 函数每调用一次就会产生一个新的函数作用域
- 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
- 在函数内部为变量赋值,默认都是为局部变量赋值,若希望是在函数内部修改全局变量,则需要使用global关键字,来声明该变量为全局变量
- 变量的查找:
- 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用;
- 如果没有则继续去上一级作用域中寻找,如果有则使用,
- 如果依然没有则继续去上一级作用域中寻找,以此类推
- 直到找到全局作用域,依然没有找到,则会抛出异常;
命令空间:变量存储的位置
- 命名空间实际上是一个字典,专门用来存储变量的字典 scope = locals() print(type(scope)) 即为字典
- 每一个变量都需要存储到指定的命名空间中,每一个作用域都会有一个其对应的命名空间
- 全局命名空间:用来保存全局变量
函数命名空间:保存函数中的变量 - locals()用来获取当前作用域的命名空间,全局中调用就是获取的全局命名空间,局部中调用就是获取局部命名空间。其返回的是一个字典;
- 向字典中添加一个key-value就相当于在对应的作用域中创建一个变量,不过一般开发不建议这样做;
- globals()函数可以用来在任意位置获取全局的命名空间。
10 递归与其他函数知识
递归:自己引用自己,递归式函数:在函数中调用自己
- 递归式函数的两个要件
- 基线条件
- 问题可以被分解为的最小问题,当满足基线条件时,递归就不再执行
- 递归条件
- 将问题继续分解的条件
- 递归和循环类似,基本是可以互相代替的,
- 循环编写起来比较容易,阅读起来稍难
- 递归编写起来难,但是方便阅读
- 例如:斐波那契数列、回文字符串等
高阶函数:接受函数作为参数,或者返回值为函数的函数
- 当使用一个函数作为参数的时,实际上是将指定的代码传递进了目标函数
- filter() 函数:可以从序列中过滤出符合条件的元素,保存到一个新的序列中
- 入参:参数1:函数,使用该函数来过滤序列 参数2:待过滤的序列(可迭代结构)
- 返回值:过滤后的新序列(可迭代结构)
- 例如:返回list_a中的所有偶数: ret_2 = list(filter(lambda i: i % 2 == 0, list_a))
- 匿名函数lambda:专门用来创建一些简单的函数,函数创建的另一种方式
- 语法: lambda 参数列表:返回值
- 匿名函数一般都是作为函数使用,其他地方一般不会使用
- map()函数:map函数可对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
- 例如:r = list(map(lambda i: i**2, list_a)) 将list_a中所有的元素求平方
- sort():对列表中的元素进行排序,默认比较的是列表中元素的大小
- 可以接受关键字参数key,作为指定排序因子
- sorted():作用和sort()几乎一样,但是sorted可以对任意的序列进行排序
- 使用sorted()函数排序不会对原来的对象有影响,而是返回一个新的对象
- 例如:l = [2,5,‘1’,3,‘6’,‘4’] print(sorted(l,key=int)) 不会对l产生影响
闭包
- 将函数作为返回值返回也是高阶函数,高阶函数也是一种闭包,通过闭包可以创建一些只有在当前函数才能访问的变量,即将私有数据藏到闭包中;
- 形参闭包的要素:
- 1)函数需要嵌套
- 2)将内部函数作为返回值返回
- 3)内部函数必须要使用到外部函数的变量
装饰器:可以在不修改源代码的情况下,来对函数进行扩展
- 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展,在实际开发中,都是通过装饰器来扩展函数功能的;
- 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数;
- 可以同时为一个函数指定多个装饰器,这样函数将会安排从内向外的顺序被装饰;越靠近函数的越先被执行
- 我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
- ① 如果要修改的函数过多,修改起来会比较麻烦
- ② 并且不方便后期的维护
- ③ 并且这样做会违反开闭原则(OCP)
-
程序的设计,要求开发对程序的扩展,要关闭对程序的修改。即在不修改函数的情况下实现对函数扩展,示例: # 后面需要是有begin_end 则只需要在函数开头加上 @begin_end 即可被其装饰 def begin_end(old): ''' 用来对其他函数进行扩展,使得其他函数可以在执行前后做点啥 参数: old 待扩展的函数 ''' def new_function(*args, **kwargs): # *args 和 **kwargs分别表示是位置参数和关键字参数 print('开始执行……’) result = old(*args, **kwargs) #待扩展的函数 #此处的* 和** 分别表示序列和字典的拆包 print(‘执行结束……‘) return result #返回新的函数 return new_function
11 面向对象编程-基础
对象 是内存中专门用来存储数据的一块区域,可以存储任何类型数据(数字,布尔值,代码)。类是一个type类型的对象。
- Python面向对象__new__()和__init__()的使用
-
__new__()被用来创建新的实例对象,在类的方法定义中经常被定义为静态方法。第一个参数是cls,其余参数是创建实例所需的信息,
必须有一个返回值作为后续使用的对象实例:object.__new__(cls,[,…]) -
__init__()被用来初始化被__new__()创建出来的实例对象,它的处理过程在用户拿到对象实例之前完成。
-
__new__()和__init__()都是Python基础对象object已经实现的方法,我们平时在自定义类的书写过程属于“override”。
__init__()的使用更为频繁,导致大家经常会把__init__()方法认为是构造的全部过程。实际上__new__()偏重对象实例的创建过程,
__init__()偏重对象实例的初始化过程,两者加起来才是Python中一个类构造对象实例的全部过程。
-
- 类 class
- int() float() bool() str() list() dict() 这些都是python的内置类
- isinstance() 用来检查一个对象是否是一个类的实例:ret = isinstance(cla,class) #检查cla是不是class的一个实例
- 实例化之后对象,其类型就是母类。如 myclass = MyClass() 其类型就是MyClass
- 类和对象实际上有两部分组成,1)数据(属性) 2)行为(方法)
- 方法调用和函数调用的区别:
- 函数调用,调用时传递几个参数,就会有几个参数;
- 方法调用,默认传递一个参数(第一个参数有解析器自动传递),所以在方法中至少需要定义一个形参;
特殊方法(魔法方法)
- 特殊方法的都是以__开头,以__结尾的方法;
- 特殊方法不需要我们自己调用,不需要尝试调用特殊方法,其会在特殊时刻自己调用;
封装:
隐藏对象中一些不希望被外界所访问的属性和方法,面向对象的三大特性之一
- 如何获取(修改)对象中的属性:
- 需要提供一个getter和setter方法使外部可以访问到属性
- getter 获取对象中的指定属性(get_属性名)
- setter 用来设置对象的指定属性(set_属性名)
- 使用封装,虽然复杂程序增加,但是确保了数据的安全性
- 1.隐藏了属性名,使调用者无法随意的修改对象中的属性
- 2.增加了getter和setter方法,很好的控制的属性是否是只读的
- 如果希望属性是只读的,则可以直接去掉setter方法
- 如果希望属性不能被外部访问,则可以直接去掉getter方法
- 3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
- 4.使用getter方法获取属性,使用setter方法设置属性
- 可以在读取属性和修改属性的同时做一些其他的处理
- 5.使用getter方法可以表示一些计算的属性
-
class Dog: ''' Dog 大类 hidden_name 和 hidden_age不对外暴露 ''' def __init__(self, name, age): self.hidden_name = name self.hidden_age = age def say_Hi(self): print("Hi,I am %s"% self.hidden_name) #print("Hi,I am " + self.hidden_name, ", and I am "+ str(self.hidden_age)+" years old!") def get_name(self): # get_name()用来获取对象的 name属性 return self.hidden_name def set_name(self, name): self.hidden_name = name def get_age(self): return self.hidden_age def set_age(self, age): if age > 0: #这里可以对age作一个检查 self.hidden_age = age
隐藏属性
可以为对象的属性使用双下划线开头,__xxx,这种属性就是对象的隐藏属性,
- 隐藏属性只能在类的内部访问,无法通过对象访问;
- 隐藏属性其实就是python为属性改了一个名字,将属性名字改为: _类名__属性名。如:_Person__name
- 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
- 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
-
class Person: def __init__(self, name): self._name = name # _name即为私有属性 def get_name(self): return self._name
Property装饰器
将一个方法变成一个静态属性,给用户更简单的调用方式,隐藏具体的实现细节。
- 添加为property装饰器以后,我们就可以像调用属性一样使用get方法;
- 使用property装饰以后,必须和属性名一样
-
class Person: def __init__(self, name, age): self._name = name self._age =age @property def name(self): return self._name # setter方法的装饰器:@属性名.setter # 有setter则必须要有 @property @name.setter def name(self,name): self._name = name # 后面在调用的时候: P = Person() P.name ='sun' #即可以像其属性一样直接用
12 面向对象编程-继承/多态
继承与多重继承
继承是面向对象的三大特性之一,通过继承可以使一个类获取到其他类中的属性和方法:
- 在定义类时,可以在类名后的括号中指定当前类的父类(超类,基类,Super),子类(衍生类)可以直接继承父类中的所有属性和方法
- 继承可以直接让子类获取到父类的方法和属性,避免编写重复性的代码,并且也符合OCP原则,在实际代码开发中经常需要对一个类进行扩展。
- 在创建类时,如果忽略了父类,则默认父类就是object
- issubobject(A, B) #检查一个类A 是否是另一个类B的子类。(不能反着检查)
- 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法。以扩展多余的属性;
- super:通过super 可以动态的获取当前类的父类,通过super返回对象调用父类方法时,不需要传递self。
-
class Dog(Animal): def __ini__(self,name,age): # 可以直接调用父类的__init__来初始化父类中定义的属性,super()可以用来获取当前类的父类 super().__init__(name) #相当于Animal.__init__(name) self._age = age
- 多重继承:使子类同时拥有多个父类,并且会获取所有父类中的方法。(实际开发中尽量少用,避免对于复杂)
- python中是支持多重继承的,可以同时为一个类指定多个父类:在类名后面的()后边添加多个类,来实现多重继承;
- 如果有多个父类中的有同名的方法,则会出现第一个父类中寻找,然后找第二个,第三个,前面父类的方法会覆盖后面父类的方法。
重写
重写(覆盖,override)
- 如果在子类中如果有父类同名的方法,则可以通过子类实例去调用方法时,会调用子类的方法
而不是父类的方法。 - 当我们调用一个对象的方法时,
会优先去当前对象中寻找是否具有该方法,如果有则直接调用;
如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法;
如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错;
多态
面向对象的三大特征之一,多种形态:一个对象可以以不同的形态去呈现
- isinstance(obj, A) 若对其他类型做出限制,使得其他类型的对象都无法使用这个函数,则该函数违反了多态原则;
- 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型的对象,这样导致函数的适应性很差。
- isinstance 在实际开发中基本不用,因为一旦用了就违反了多态。
- 多态名言:如果一个对象走路像鸭子,叫声像鸭子,形态像鸭子,那么它就是鸭子。
###面向对象三大特征: - 封装:确保对象中的数据安全
- 继承:保证了对象的可扩展性
- 多态:保证了程序的灵活性
###垃圾回收
在程序中没有被引用的对象就是垃圾,垃圾对象过多会影响到程序的运行的性能; - 删除特殊方法: def __def__(self):
print('A()对象被删除……'self)
特殊方法
-
str(self): 作用是用来指定对象转换为字符串的结果(print函数)
-
特殊方法(魔法方法)会自动执行,不需要手动调用;
-
可以修改其内部特殊函数以满足特殊情况:
class A(): def __gt__(self,other): return self.age > other.age #根据两个对象的age比较,self的age大于other即返回True;
模块与包
模块化:在python中一个PY文件就是一个模块,想创建模块就是创建一个python文件。可以将容器理解为一个容器,在容器里面的都可以被引用
- 从一个模块中引入另一个模块: 1)import 模块名 2)import 模块名 as 模块别名
- 可以引入同一个模块多次,但是模块的实例只会创建一个
- import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
- 在每一个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
- __name__属性值为 __main__的模块是主模块,一个程序中只会有一个主模块
- 引入一个模块中的部分内容: from 模块名 import 变量,变量……
- print(test_module) #可以打印出该模块的位置
包:当模块中代码过多时,或者一个模块需要被分解为多个模块时,就需要使用到包
- 普通的模块就是一个py文件,而包是一个文件夹
- 包中必须要有一个 __init__文件,这个文件可以包含包中的主要内容
- from test import * #从test 中引入所有的内容(相当于把test中的代码都拷贝进来)
13 面向对象编程-模块化/异常
在Python中,一个类可以有:类属性,实例属性,类方法,实例方法,静态方法
- 类属性:直接在类中定义的属性。类属性可以通过类或类的实例访问到,但只能通过类对象来修改,无法通过实例对象修改;
- 类属性中一般存储公共的属性部分;
- 实例属性:通过实例对象添加的属性属于实例属性。实例属性只能通过实例对象来访问和修改,类对象无法访问修改;
- 类方法:在类内部使用 @classmethod 来修饰的方法属于类方法。
- 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象;
- 类方法和实例方法的区别:实例方法的第一个参数是self,类方法的第一个参数是cls;
- 类方法可以通过类调用,也可以通过实例调用,没有区别;
- 实例方法:在类中定义,以self为第一个参数的方法都是实例方法。
- 实例方法在调用时,python会将第一个参数self自动传入;
- 实例方法可以通过实例和类去调用;
- 通过实例调用时,会自动将当前对象作为self传入;
- 通过类调用时,不会自动传递self,需要手动传递self参数;
- 静态方法:在类中使用 @staticmethod 来修饰的方法属于静态方法
- 静态方法基本上是一个与当前类无关的方法,只是保存在当前的类中的函数;
- 静态方法不需要指定任何默认参数,静态方法可以通过使用类和实例去调用;
- 静态方法一般都是工具方法,和当前类无关;
python类中Staticmethod Classmethod 和 property的区别:
@Staticmethod 和 @Classmethod可以不需要实例化一个对象,直接用类名.方法名()来调用, staticmethod不需要表示自身对象的self和自身类的cls参数,
就和使用函数一样;classmethod不需要self参数,但是第一个参数需要表示自身类的cls参数;
1)在类中使用 @staticmethod 来修饰的方法属于静态方法,可以看成是一个完全独立的函数,只是调用的时候必须通过这个类,
一般是为了规范代码而实现的,类中定义函方法 PyCharm 提示Method xxx may be ‘static’, 原因是该方法不涉及对该类属性的操作,编译器建议声明为@staticmethod,面向对象思想体现。----就是作为一般的工具函数来使用
静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
静态方法一般都是一些工具方法,和当前类无关
2)classmethod类方法:只能访问类变量,不能访问实例变量, 也就是跟类有关,跟实例无关:
在类内部使用 @classmethod 来修饰的方法属于类方法
类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
类方法可以通过类去调用,也可以通过实例调用,没有区别
3)property属性方法的作用通过@property把一个方法变成一个静态属性;
@property属性方法 封装类中的方法,给用户更加简单的调用方式,隐藏具体的实现细节。
@method.getter 获取属性
@method.setter 设置属性, 可以写更多逻辑(比如格式转换,类型判断),并提醒其他人这里面可能有magic
@method.deleter 删除属性
标准库
开箱即用,为Python提供了一个模块的标准库,如 sys模块提供了变量和函数,可以获得python解析器的信息
- os.environ() #通过该属性可以获取到系统的环境变量
- os.system() #可以用来执行操作系统的名字 os.system(‘dir’)
- _c = 30 # 添加了_c的变量,只能在模块内部访问,在通过 import *引入时,不会引入_开头的变量
主模块
- 这部分代码只有当前文件作为主模块的时候才需要执行,而当其他模块引入时,不需要执行,我们就必须要检查当前
模块是否是主模块
if name == “main”:
……
__pycache__文件
模块的缓存文件,py代码在执行前,需要被解析器先转换为机器码,然后再执行,我们在使用模块(包)时,也需要将模块代码
先转换为机器码,然后再交给计算机执行。
- 为了提高程序运行的性能,python会在编译过一次后,将代码保存在一个缓存文件中(.pyc文件)
异常及异常对象
程序在执行过程中难免会出现异常:使用了没有复制过的变量;使用了不存在的索引;除 0等
-
将可能出现错误的代码放在 try 中:
try: print(10 / 0) # 将可能出错的代码放在try中 except: print('HaHaHa,出错了') else: print('程序正常执行没有错误’)
-
当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播;如果函数中没有对异常进行处理,
则异常会继续向函数调用处传播;若调用处处理了则不再传播,否则报错时都会显示出错误的行数。
异常对象
-
我们可以针对异常对象类型做出调整,常见的异常对象类型有:
- NameError 异常
- ZeroDivisionError 异常
- IndexError 异常
-
如果except后不跟任何的内容,则此时它会捕获到所有的异常
-
Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常
-
如果后面跟着一个异常类型,则它只会捕获该类型的异常
示例:try: print(10 / 0) # 将可能出错的代码放在try中 except NameError: # 如果except后不跟任何的内容,则此时它会捕获到所有的异常 print('NameError 异常') except ZeroDivisionError: print('ZeroDivisionError 异常') except IndexError: print('IndexError 异常') except Exception as e: print('未知异常',e,type(e)) finally: print('无论是出现异常,该语句都会执行到')
-
也可以自己定义自决定异常类,只需要创建一个类继承Exception即可
-
raise 用于向外部抛出异常:raise(’两个参数中不能有负数‘)
class MyErro(Exception): pass def add(a, b): if a < 0 or b < 0: raise MyError('自定义异常’) r = a + b return r print(add(-123,345)) #会抛出自定义的异常
Python 基础进阶
平台:华为云
函数
不定长参数:有时候需要处理一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数,声明时不会命名。
- *args:args会存放所有未命名的变量参数,args为元组;
- **kwargs:kwargs会存放命名参数(以字典的方式传值),即形如key=value的参数,kwargs为字典。
- 在函数中,各种参数的存放位置为:def func(必备参数,关键字参数,默认参数,不定长参数)
对象
- 在默认情况下,属性在Python中都是public,类所在模块和导入了类所在模块的其他模块都可以访问到。如果类中的某些属性不想被外界访问或者继承可以对其私有化;
- 模块级的私有化:在属性或方法前加上一个下划线_即可。防止模块的属性用“from mymodule import *”来加载,它只可以在本模块中使用。
- 完全私有化:只能自己访问。在方法或属性前加双下划线__。Python中的完全私有化是一个假的私有化,它的作用其实是将之前的属性或方法名改为了‘类名._属性/方法’
- 常用的魔法方法:
- new(cls[,]):创建实例时首先调用的方法(构造方法)
- init(self[,]):对象初始化方法(new方法返回对象后,调用init方法进行属性的初始化)。
- del(self):析构方法,当实例化对象被彻底销毁时调用(实例化对象的所有指针都被销毁时调用)
- getattr__(self,name)定义当用户试图获取一个不存在的属性时的行为;
- setattr__(self,name,value)定义当一个属性被设置时的行为。
- getattribute__(self,name)定义当该类的属性被访问时的行为。访问对象属性或方法时,首先被调用的方法。
-
设计模式
单例模式:单例模式中单例类只有一个实例(单例类必须自己创建自己的唯一实例)
- 单例类必须给所有其他对象提供这一实例。
- 在python中可以使用__new__来实现单例。
Python中的轮子/模块/包
轮子:在程序中,我们将封装好的组件、库称之为轮子。可以直接拿来用,实现对应的功能。
模块:一个.py文件就是一个模块。 模块是Python中的最高级别组织单元,它将程序代码和数据封装起来以便重用。模块的三个作用:1)代码复用 2)系统命名空间的划分 3)实现共享服务和数据。
包:是一个目录,要被Python视为包,目录中必须含有__init__.py文件,包的导入会首先执行__init__.py文件。其他模块加入包中,放入包的目录即可。
- import搜索的路径顺序:以下四个组件组合起来就变成了sys.path,其保存了模块搜索路径在机器上的实际配置。可以通过打印内置的sys.path列表来查看这些路径。
- 程序的主目录
- PythonPath(环境变量)目录
- 标准链接库目录
- 任何.path文件内容
Python场景内置工具包
- os:负责程序与操作系统的交互,提供了访问操作系统底层的接口;
- os.getcwd():获取当前所在路径
- os.chdir(path):改变当前工作目录
- os.listdir():返回目录下所有的文件
- os.walk():返回目录下所有文件(包括子文件夹中的文件)
- os.path.join(path):按照当前系统所能识别的方式链接目录名 根据系统的不同加的连接符号是不一样的,适应性更强。
- os.path.abspath(path):返回绝对路径
- os.path.exists(path):文件存在则返回True,不存在则返回False
- os.path.getsize(path):返回文件大小 - sys:负责程序与Python解释器的交互,提供了对解释器的一系列的函数和变量的访问,用于操控Python运行时的环境。
- sys.exit([n]):此方法可以是当前程序退出
- sys.path:获取模块搜索路径列表 path是一个目录列表,供Python从中查找模块
- sys.argv:从程序外部向程序传递参数,参数以列表的形式传递,第一个为当前文件名。如python m.py argv1 m.py是第一个参数。
文件读写
常见操作
- f.tell():返回当前文件读写位置
- f.seek(off,where):定位文件读写位置。off表示偏移量,正数向尾部移动,负数向开头移动。where为0表示起始位置开始,1表示当前位置,2表示结尾位置。
- with open(file_name, mode,encoding) as f:
文件操作语句 使用后会自动关闭文件 - with open(“数据分析/data.csv”,‘r’) as f:
print(f.read())
借助pandas库可以更好的读取数据
其他技巧
小整数对象池
Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。小整数范围[-5,256]。在此范围之内的数据,指向同一块内存地址。如:
a = 0 b = 0 id(a) == id(b) 返回True。在此范围之外的一般为False。
- 这些整数对象会被事先建立好,不会被回收,为变量赋值时直接指向这些建立好的地址。
- 这些优化在简单字符串上也有。简单字符串(不含空格和其他特殊字符)在内存地址中是一起的。如:
a = “python” b = "python” a is b 返回True。
动态语言的体现
- 在Python中声明变量时不需要指定类型。
- 在类和对象的使用中可以动态的为对象添加属性和方法。
- Python中的垃圾回收机制以引用计数为主,以隔代回收为辅进行的。
其他技巧
- eval函数会将输入的字符串拆除两边引号,直接计算其值。
- 在Python字典中,key具有等效性。6 == 6.0 = 6 + 0j
- Python可以这样给元组排序:
l = [(1,2), (2,4),(2,3),(3,2)]
l.sort(key = lambda x:(x[0], x[1])) # key指定排序关键字 指派x[0] x[1]
- Python是动态语言,在运行过程中是实时变换的。如在删除列表元素的过程中,列表的长度是实时变化的:
l = [99, 100, 46,68,44,50,78,50,59,66,51,89,54]
for i in s:
s.remove(i) #删除一个元素后,列表的长度实时变化
常见应用
正则表达式
正则表达式是一个由特殊字符串组成的字符串,这个特殊的字符串描述了匹配的一系列字符的规则。正则表达式为高级的文本模式匹配、抽取、与/或文本形式的搜索和替换功能提供了基础。大多数编程语言中的正则表达式的书写规则形式和规则是一样的。
大致匹配过程:
依次将文本中的字符和正则表达式做匹配,如果所有字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。
- python中通过正则表达式对字符串进行匹配的时候,需要使用标准库re模块:re模块中通过给定的匹配规则,匹配文本中符合规则的字符并进行操作。匹配的规则可以是字符串,也可以是正则表达式。