Python学习
数字运算符:+ – * / %(取余数) **(幂的n次方) //(取整数)
一、高级数据类型
1、序列:在python中,序列就是一组按照顺序排列的值【数据集合】
在python中 存在三种内置的序列类型:字符串、列表、元组
优点:支持索引和切片的操作
特征:第一个正索引为0,指向的是左端,第一个索引为负数的时候,指向的是右端
2、切片:截取字符串中其中一段内容,切片使用语法:[起始下标:结束下标:步长],左闭右开,起始下标<=value<结束下标
步长默认为1,步长为-1,可以倒叙输出
3、字符串及常用方法
3.1 capitalize() 首字母变大写
3.2 endswith/startswith() 是否x结束/开始
3.3 find() 检测x是否在字符串中 跟index都可以查找,但是find查不到返回-1.index差不到会报错
3.4 isalnum() 判断是否是字母和数字
3.5 isalpha() 判断是否是字母
3.6 isdigit() 判断是否是数字
3.7 islower() 判断是否是小写
3.8 join() 循环去除所有值用XX去连接
3.9 lower/upper 大小写转换
3.10 swapcase 大写变小写,小写变大写
3.11 lstrip/rstrip/strip 移除左/右/两侧空白
3.12 split() 切割字符串
3.13 title() 把每个单词的首字母变成大写
3.14 replace(old,new,count=None) old被换字符串,new替换字符串,count换多少个,无count表示全部替换
3.15 count() 统计出现的次数
4、list:python当中非常重要的数据结构,是一种有序的数据集合
特点:
4.1 支持增删改查
4.2 列表中的数据是可以变化的【数据项可以变化,内存地址不会改变】
4.3 用[]来表示数据类型,数据项之间用逗号来分割,注意:数据项可以是任何类型的数据
4.4 支持索引和切片来进行操作
5、列表及常用方法
5.1 append 追加元素
5.2 count 统计元素次数
5.3 extend 扩展,相当于批量添加
5.4 index 获取指定元素索引号 ,括号是具体数据值,返回查找的是下标
5.5 insert 在指定位置插入
5.6 pop 删除最后一个元素,也可以移除指定项(参数是索引值)
5.7 remove 移除左边找到的第一个元素,也可以移除指定元素(具体数据值)
5.8 reverse 反转列表
5.9 sort 列表排序(reverse=True,倒叙)
5.10 len 长度
5.11 del list[0] 删除列表中第一个元素
5.12 del listB[1:3] 批量删除第二第三位数据
6、元组:是一种不可变的序列,在创建之后就不能做任何的修改
6.1 不可变,但是可以对元组中的列表进行修改
6.2 用()创建元组类型,数据项用逗号来分割
6.3 可以是任何的类型
6.4 当元组中只有一个元素时,要加上逗号,不然解释器会当作整形来处理
6.5 支持切片操作
7、字典:可以存储任意对象,字典是以键值对的形式创建的{‘key’,’value’}利用大括号包裹,逗号分割
7.1 键值对的键key不能重复,value可以重复
7.2 字典是不可变类型
7.3 和list一样,支持对数据的添加、修改、删除
7.4 不是序列类型,没有下标的概念,是一个无需的键值集合,是内置的高级数据类型
7.5 每个键必定是唯一的,如果存在重复的键,后者会覆盖前者
8、字典及常用方法
8.1 修改元素,字典中的值可以修改,通过键key找到对应的值修改
8.2 删除元素 del删除指定元素,clear清空字典,dictA.pop(age)删除年龄
8.3 获取键:keys,可以用for循环取出每个key值
8.4 获取键值对。返回一个包含所有(键,值)元组的列表dict items对象
8.5 新增元素,如果在使用变量名[‘键’]=数据时,这个‘键’在字典中不存在,那么就会新增这个元素
8.6 统计个数 len()可以查看字典中有几个键值对
8.7 获取值:values python3版本中使用values返回一个包含所有制(value)dict values对象
8.8 删除指定键 pop(‘键’)删除指定键
8.9 dictA.values() 获取所有值
8.10 dictA.keys() 获取所有键
8.11 dictA.items() 获取所有键值对
8.11 for key,value in dict.items():
print (‘%s==%s’%(key,value)) 输出所有的键=值
8.12 dictA.update({‘age’:32}) 可以更新修改或者添加
9、公用方法
9.1 + 合并操作,两个对象相加操作,会合并两个对象,适用于字符串、列表、元组
9.2 * 复制,对象自身按指定次数复制,适用于字符串,列表、元组
9.3 in 判断元素是否存在,判断指定元素是否存在于对象中,适用于字符串、列表、元组、字典,结果是布尔类型数据True False
二、函数
1、参数的分类
1.1 必选参数:形参(定义的时候不占内存地址)、实参(在调用时赋值使用)
1.2 默认参数(缺省参数):始终存在于参数列表中的尾部,def sum(a,b=40),例如b=40为默认参数,调用时可以不加参数即调用默认的40
1.3 可选参数(不定长参数):def sum(*args): 接受元组类型参数
1.4 关键字可变参数:def keyFunc(**kwargs): 可变关键字参数(是一个字典类型,key是一个字符串,可以传0-n个参数),用两个星号来定义
调用的时候需要keyFunc(**dictA),在字典前加两个星号以此调用,
或者直接在代码里以命名参数的形式传 keyFunc(name=’peter’,age=26),最终输出的结果是个键值对,如果不传参数也可以,会输出空字典{}
1.5 也可以混合参数组合:def complexFunc(*args,**kwargs): 调用也可以不传参,会输出空元组和空字典,也可以分别传参
如,complexFunc(1,2,3,4,name=’刘德华’)
注意:可选参数必须放到关键字可选参数之前
2、函数返回值
2.1 概念:函数执行完以后会返回一个对象,如果在函数的内部有return就可以返回实际的值,否则返回None
2.2 类型:可以返回任意类型,返回值类型应该取决于return后面的类型
2.3 用途:给调用方返回数据
2.4 在一个函数体内可以出现多个return值,但是肯定只能返回一个return
2.5 如果在一个函数体内执行了return,意味着函数执行完成退出了,return后面的代码语句将不会执行
2.6 函数的分类:根据函数的返回值和函数的参数
2.6.1 有参数无返回值的,多用在设置某些不需要返回值的参数设置
2.6.2 有参数有返回值的,一般是计算型的,需要参数,最终也要返回结果
2.6.3 无参数无返回值的,一般用于提示信息打印
2.6.4 无参数有返回值的,多用在数据采集中,比如获取系统信息
3、全局变量和局部变量
3.1 局部变量:就是在函数内部定义的变量【作用域仅在函数内部】,不同的函数可以定义相同的局部变量,但是各自用各自的不会产生影响
3.2 局部变量的作用:为了临时的保存数据,需要在函数中定义来进行存储
3.3 当全局变量和局部变量出现重复定义的时候,程序会优先执行函数内部的变量
3.4 如果在函数的内部要想对全局变量进行修改的话,必须使用global关键字进行声明
3.5 在python中,万物皆对象,在函数调用的时候,实参传递的就是对象的引用
3.6 了解了原理之后,就可以更好的取把控在函数内部的处理是否会影响到函数外部的数据变化
3.7 参数传递是通过对象引用来完成!!!
4、匿名函数
4.1 python中使用lambda关键字创建匿名函数,所谓匿名就是这个函数没有名字不用def关键字创建标准的函数
4.2 lambda 参数1,参数2,参数3:表达式 (匿名函数冒号后面的表达式有且只有一个,是表达式不是语句)
4.3 匿名函数自带return,而这个return的结果就是表达式计算的结果
M=lambda x,y:x+y
print(M(23,19))
or
M=lambda x,y:x if x>y else y #如果x大于y,输出前面的x,否则输出y
print(M(12,2)) #输出12
or
M=(lambda x,y:x if x>y else y)(16,12) #如果x大于y,输出前面的x,否则输出y,可以放入参数直接调用
print(M) #输出16
4.4 lambda只能是单个表达式,只能实现简单的函数场景,仅仅能封装有限的逻辑,复杂的逻辑实现不了
5、递归函数
- 5.1 递归满足的条件:①自己调用自己、②必须有一个明确的结束条件
- 5.2 优点:逻辑简单、定义简单
- 5.3 缺点:容易导致栈溢出,内存资源紧张,甚至内存泄露
6、内置函数
- 6.1 python自带得函数
- 6.2 abs():绝对值输出函数
- 6.3 round(x,n):对浮点数进行近似取值,返回浮点数x得近似值,不一定是四舍五入,n为保留得位数
- 6.4 pow(3,3):求次方,求3的3次方可以等于3**3
- 6.5 max(x,y,z…):求最大值,参数可以是序列
- 6.6 divmod(a,b):求商和余数,返回(商,余数)
- 6.7 sum(range(50),3):求和,可以传入列表、元组、集合等,此处的3可省略(没指定默认为0),如果有代表每一项先加3再求和
- 6.8 eval(expression,[globals,[locals]]):执行字符串表达式(也可以函数),expression表达式,globals变量作用域,全局命名空间,必须是字典,locals局部变量作用域,可以是任何对象
- 6.9 类型转换函数:
- int()
- float()
- str()
- ord()
- chr() 数字转字符,即转化为ascii码
- bool() 转换为true false
- bin() 十进制转换为二进制
- hex() 十进制转换为16进制
- oct() 整数转8进制
- list() 将元组转换为列表
- tuple() 将列表转元组
- dict()
- bytes() 转为字节数组
6.10 序列操作内置函数:
- all():判断可迭代参数中”所有“元素非0、非空、非FALSE,才算TRUE,注意:空元组、空列表返回值为TRUE,类似and
- any():判断可迭代参数中是否全部为False,只要有一个为True则返回True(除0、空、false外都算true),类似or
- sorted():对可迭代对象进行排序操作,默认reverse=False为升序,reverse=True为降序
- sort与sorted区别:sort是应用于list商的方法,sorted可以对所有可迭代对象进行排序操作
- list的sort是对已存在的列表进行操作,而sorted是返回一个新的list
- reverse():反向列表中的元素
- range(start,stop,step):可以创建一个整数列表(左开右闭),一般用在for循环中
- zip():用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回这些元组组成的列表
- 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用*号操作符,可以将元组解压为列表,类似阵列
- enumerate():函数用于将一个可遍历的数据对象(如列表、元组、字符串)组合为一个索引序列,同事列出数据和数据下标,一般用在for循环当中
6.11 集合:是一个无序且不重复的元素集合set{}
- add():set1.add(‘python’)集合追加数据
- clear():set1.clear()清空集合
- difference():a.difference(b),两个集合的差集,a中存在,b中不存在的,去掉ab重复的,返回值会生成一个新的集合需要定义接收变量=set1-set2
- intersection():取交集,=set2&set1,返回一个新的值需要定义变量接收,set1.intersection(set2)
- union():取并集,包含a和b集合所有数据,a.union(b),并且去重=set1 | set2
- pop():随机移除某个元素并且获取那个参数,集合pop没有参数,a.pop(),直接在原有集合中操作
- discard():指定移除的元素,a.discard(3),指定移除3,在原有集合操作
- update():set1.update(set2)跟并集操作查不多,直接在原有集合操作
三、面向对象oop
1、面向过程——函数式——面向对象
面向过程:根据业务逻辑从上到下写代码
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
面向对象编程:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程。关注的式设计思维(不考虑细节,类似老板思维)
面向对象适合做大项目,面向过程不适合大项目
面向过程的关注点是:怎么做
面向对象的关注的是:谁来做
2、类和对象
2.1 类由3个部分构成:
类的名称:类名 (大驼峰),例如:人类
类的属性:一组数据 例如:身高、年龄
类的方法:允许对进行操作的方法(行为) 例如:吃、跑
2.2 类:是具有一组相同或者相似特征【属性】和行为【方法】的一系列[多个]对象组合
现实世界 计算机世界
行为—————>方法
特征—————>属性
2.3 对象:对象是实实在在的一个东西,类的实例化,具象化,
创建对象 :对象名=类名(),例如:dog=animals()
调用方法:dog.run(),这里的run()方法就是类里定义的函数
访问类属性:print(dog.name)
2.4 类是对象的抽象化 而对象是类的一个实例
3、实例方法与属性
3.1 实例方法:①在类的内部,②使用def关键字可以定义一个实例方法,与一般函数定义不同,③类方法必须包含参数self(self也可以叫其他名字),且为第一个参数
所属的权力归实例所有
3.2 类属性:定义在类里面&方法外面的属性称之为类属性
3.3 实例属性:定义在实例方法里面,使用self引用的属性称之为实例属性
4、__init__魔术方法
4.1 是一个初始化的方法,用来定义实例属性和初始化数据的,在创建对象的适合自动调用不用手动去调用
4.2 利用传参的机制可以让我们定义功能更加强大并且方便
5、self
5.1 self和对象指向同一个内存地址,可以认为self就是对象的引用
5.2 所谓self可以理解为对象自己,某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可
5.3 self只有再类中定义,实例方法的时候才有意义,在调用时候不必传入相应的参数,二十由解释器自动去指向
5.4 self的名字可以更改,可以定义成其他的名字,只是约定俗成的定义成了self
5.5 self指的时类实例对象本身,相当于java中的this
6、魔术方法
6.1 常见的魔术方法:
- __init__:初始化一个类,在创建实例对象为其赋值时使用
- __str__:在将对象转换成字符串str(对象)测试的时候,打印对象的信息
- __new__:创建并返回一个实例对象,调用了一次。就会得到一个对象,cls代表class类缩写,return object.__new__(cls)
- 场景:可以控制创建对象的一些属性限定,经常用来做单例模式的时候来使用
- __class__:获得已知对象的类(对象.__class__)
- __del__:对象在程序运行结束后进行对象销毁的时候调用这个方法,来释放资源
- __mro__:可以显示类的依次继承关系,通过类A.__mro__然后打印出来
- __call__:与str类似,调用有区别,call直接实例a()调用,str使用print(a)
6.2 先执行__new__,返回一个对象后,再执行__init__初始化(因为有了对象才能有后面的)
7、析构方法
7.1 析构方法概述:当一个对象被删除或者被销毁时,python解释器也会默认调用一个方法,这个方法为__del__()方法,也成为析构方法
7.2 当对象被手动销毁的时候也会自动调用__del__方法销毁对象回收内存
7.3 析构函数一般用于资源回收,利用__del__方法销毁对象回收内存等资源
8、继承
8.1 和生活中继承是一样的,子类可以继承父类【的属性和行为】,爸爸有的儿子都有,相反儿子有的爸爸不一定有
8.2 所有对于面向对的几次来说,其实就是将多个类共有的方法提取到父类中,子类仅需几次父类而不必一一去实现
8.3 这样就可以极大提交效率,减少代码的重复编写,精简代码的层级结构,便于拓展
8.4 class 类名(父类):通过这样做单继承
8.5 class 类名(父类A,父类B):多继承,继承查找先平级查(同名继承查找),A没有查B,如果AB都没有,再查AB的父类往上,最后查object
8.6 类的传递过程,把父类又称为基类,子类又成为派生类,父类的属性和方法可以一级一级的传递到子类
8.7 针对子类重写父类方法,如果重写方法名一样,以子类为准,子类重写父类有的__init__函数,父类定义会失效
如果此时还需要使用父类的__init__函数参数,可以父类.__init__(self,x,y)或者super.__init__(x,y)
用super就不需要self。因为super是自动找到父类,进而调用方法,如果继承多个父类。super会按照顺序查找继承
9、多态
9.1 所谓多态,顾名思义就是多种状态、形态,就是同一种行为,对于不同的子类【对象】有不同的行为表现
9.2 要实现多态,必须有两个前提需要遵守:
继承:多态必须发生再父类和子类之间
重写:子类重写父类的方法
9.3 多态可以增加程序的灵活性和拓展性
9.4 可以定义一个函数统一调用多态方法:只要这些多态class都有say_who()方法,不管是从哪里继承都可以统一调用
def commonInvoke(obj): obj.say_who() listObj=[Duck(),Dog(),Cat(),Bird(),Student()] for i in listObj: commonInvoke(i)
10、类方法和静态方法
10.1 类方法:类对象所拥有的方法,需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象
一般以cls作为第一个参数,类方法可以通过类对象,实例对象调用
class Person: country='china' #类方法 用classmethod来进行修饰 @classmethod def get_country(cls): return cls.country #访问类属性 pass pass print(People.get_country()) #通过类对象去引用 p=People() print('实例对象访问%s'%p.get_country()) #通过实例对象去引用
10.2 静态方法:类对象所拥有的方法,需要用@staticmethod来表示静态方法,静态方法不需要定义额外的参数
一般情况下,我们不会通过实例对象去访问静态方法,但是类对象和实例对象都是可以访问静态方法
静态方法主要用来存放逻辑性的代码,本身和类即实例对象没有交互
也就是说,在静态方法中,不会涉及到类中方法和属性的操作
可以使得资源能够得到有效的充分利用
11、私有化属性
11.1 为了更好的保存属性安全,即不能随意被修改,可以将属性定义为私有属性,添加一个可调用的方法去访问
11.2 私有属性语法:两个下划线开头,__age=18,声明该属性为私有,不能在类的外部被使用或直接访问
11.3 使用私有属性的场景:
把特定的一个属性隐藏起来,不想让类的外部进行直接调用
想保护这个属性,不想让属性的值随意的改变
保护这个属性,不想让派生类【子类】去继承
12、私有化方法
12.1 私有化方法和私有化属性概念一样,有些重要的方法不允许外部调用,防止子类意外重写,把普通的方法设置成私有化方法
12.2 语法:私有化方法,即在方法名前加两个下划线,def __myname(self): 私有化后只能在类的内部进行调用
13、下划线说明
13.1 _xxx,前面单下划线开头表示protected类型的变量,即保护类型只能允许其本身与子类进行访问,不能使用from xxx import *的方式导入
13.2 __xxx__前后两个下划线。魔法方法。一般是python自有,开发者不要创建这类型的方法
13.3 xxx_后面单下划线,避免属性名与python关键字冲突
14、属性函数
14.1 属性函数(property):假设age是私有属性
方式一:
@property #提供一个getter方法 def age(self): return self.__age @age.setter #提供一个setter方法 def age(self.parms): if parm<0: print('年龄不能小于0') else: self.__age=parms pass pass
方式二:
分别定义get_age()、set_age()函数
age=property(get_age,set_age),外部调用默认不输入就调用get获取,输入默认调用set修改
外部就可以正常调用或者修改了这个私有属性了
15、__new__与单例模式
15.1 在新式类__new__才是真正的Shiloh方法,为类提供外壳制造出实例框架,然后调用框架内的构造方法__init__进行丰满操作
比喻建房子__new__方法负责开发地皮 打地基 并将原料存放在工地,而__init__负责从工地取材料建造出地皮开发图纸规定的大楼,负责细节设计、建造,最终完成
#在python中,如果不重写__new__默认结构如下:
def __new__(cls,*args,**kwargs):
return super().__new__(cls,*args,**kwargs)
#或 return object.__new__(cls,*args,**kwargs)
此处不能把super写作cls自己,会导致深度无线递归报错
15.2 单例模式是常用设计模式的一种,单例就比如我们打开电脑的回收站,在系统中只能打开一个回收站,
也就是说这个整个系统中只有一个实例,重复打开也是这个实例
简单的说就是不管创建多少次对象,类返回的对象都是最初创建的,不会再新建其他对象,
三次db对象返回的id都是一样的,因为是单例模式,如果有子类继承也会一样效果
class DataBaseClass(object): def __new__(cls,*args,**kwargs): if not hasattr(cls,'_instance') #如果不存在就开始创建 cls._instance=super().__new__(cls,*args,**kwargs) return cls._instance pass db1=DataBaseClass() print(id(db1)) db2=DataBaseClass() print(id(db2)) db3=DataBaseClass() print(id(db3))
16、异常处理
16.1 有时候代码写错了。执行程序的时候,执行到代码错误的时候,程序直接终止报错,
这是因为python检测到一个错误,解释器就无法继续执行了,出现了错误的提示,这就是’异常‘
16.2 语法格式:
try:
可能出现错误的代码块
except 错误类型 as msg: #except在捕获错误异常的时候,只要根据具体的错误类型来捕获,Exception可以捕获所有的错误异常
出错之后执行的代码块
else:
没有出错的代码块
finally: #可以释放文件的自由、数据库连接的资源等等
不管有没有出错都执行的代码块
16.3 不需要在每个可能出错的地方取捕获,只要在合适的层次去捕获错误就可以了,这样的话,就大大减少了我们写trt–except的麻烦
16.4 如果在运行时发生异常,解释器会查找相应的异常捕获类型,如果在当前函数里面没有找的话,它会将异常传递给上层的调用函数,看能否处理
16.5 如果在最外层没有找的的话,解释器就会退出,程序宕
16.6 自定义异常,都要直接或者间接继承Error或Exception类,由开发者主动抛出自定义异常,在python中使用raise关键字
class ToolongMyException(Exception): def __init__(self,leng): self.len=leng pass def __str__(self): return '您输入姓名数据长度是'+str(self.len)+’超过长度了..‘ pass def name_Test(): name=input('请输入姓名.....') try: if len(name)>5: raise ToolongMyException(len(name)) else: print(name) pass pass except ToolongMyException as result: print(result) pass finally: print('执行完毕了....') name_Test()
17、动态绑定属性和方法
17.1 动态语言:运行时可以改变其结构的语言,例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化
如php、JavaScript、python都是动态语言,C,C#,java是静态语言
所以python可以在程序运行过程中添加属性和方法
17.2 动态添加方法:动态添加实例方法需要使用types
import types def dynamicMethod(self): print('{}的体重是:{}kg 在{}读大学'.format(self.name, self.weight, Student.school)) pass @classmethod def classTest(cls): print('这是一个类方法') pass class Student: def __init__(self, name, age): self.name = name self.age = age pass def __str__(self): return '{}今天{}岁了'.format(self.name, self.age) pass print('绑定类方法') Student.TestMethod=classTest Student.TestMethod() print('---------类方法结束----------') zyh = Student('张艳华', 20) zyh.weight = 50 # 动态添加实例属性 Student.school='北京邮电大学' #动态添加类属性 zyh.printInfo = types.MethodType(dynamicMethod,zyh) # 动态的绑定方法 zyh.TestMethod() print('--------实例对象调用 动态绑定类方法----------') zyh.printInfo()
18、__slot__
18.1 python是动态语言,在运行的时候可以动态添加属性。如果要限制在运行的时候给类添加属性,
python允许在定义class的时候,定义一个特殊的的__slot__变量,来限制该class实例能添加的属性
只有在__slot__变量中的属性才能被添加,没有在__slot__变量中的属性会添加失败。
可以防止其他人在调用类的时候胡乱添加属性或方法。__slot__属性子类不会继承父类,只有在当前类有效,子类还是可以随意赋值
如果子类声明了__slots__时,就会继承父类的__slots__限制,只需要在子类添加__slots__=()即可,那么子类的范围就是自身的+父类的,是个并集
class Student(object): __slots__ = ('name','age') def __str__(self): return '{}....{}'.format(self.name,self.age) pass xw=Student() xw.name='小王' xw.age=20 #xw.score=96 ,在定义slot的情况下添加不包含在内的属性会报错 print(xw)
#print(xw.__dict__) #所有可以用的属性都在这欧里存储,不足的地方就是占用的内存空间大,且需要把slots注销才不会报错
可以看到在定义了slots变量后,student类的实例已经不能随意创建不在slots定义的属性了
同时还可以看到实例当中也不再有dict结构了,slots可以节约空间
四、文件
1、文件打开
1.1 语法:open(‘文件名称’,’打开模式’),可以打开一个已经存在的文件,如果不存在会自动创建一个新文件
1.2 示例:open(‘test.txt’,’w’)
1.3 打开模式说明 r w a rb wb ab r+ w+ a+ rb+ wb+ ab+
fobj=open('./Test.txt','w',encoding='utf-8') #开始操作 读/写操作 fobj.write('在苍茫的大海上') fobj.write('狂风卷积着乌云') fobj.close() #保存并关闭文件,这样才算数据写入完成 #以二进制的形式去写数据 fobj1=open('Test1.txt','wb') #str-->bytes fobj1.write('在乌云和大海之间',encode('utf-8')) #二进制需要用到encode fobj.close() #以追加方式写数据 fobj1=open('Test.txt','a') #a用于追加,二进制追加用的是ab,且需要写入的时候用encode fobj1.write('在乌云和大海之间\n') #\n是换行 fobj.close() #读取 readlines():按行读取,一次性读取所有内容,返回一个列表,每一行内容作为一个元素 readline():读一行 read():一次性读取所有 read(n):读取n个字符,如果再次执行read(),会从n个字符后把剩下的展示出来,而不是从头开始 readlines(n):此处n为读取字符长度,如果n长度小于第一行,则返回第一行全部内容,如果n大于第一行长度少于第二行结尾,则返回前两行,以此类推 print(fobj1.read(2)) #以二进制读取解码 f=open('Test.txt','rb') #rb,以二进制形式读取 data=f.read() print(data.decode('gbk')) #读取所有的数据,decode解码为gbk形式,也可以换成utf-8,根据实际需求 f.close() #保存并关闭,如果一直不关闭会导致内存不释放可能导致错误,经常容易忘记close,可以用with来替代
1.4 with上下文管理
with语句不管在处理文件过程中是否发生异常,都能保证with语句执行完毕后已经关闭打开的文件句柄
def main(): with open('Test.txt','w') as f: content = f.read() print(content) main()
1.5 文件图片视频音频可以用二进制读取
2、备份文件
def copyFile(): #接收用户输入的文件名 old_file=input('请输入要备份的文件名:') file_list=old_file.split('.') #构造新的文件名.加上备份的后缀 new_file=file_list[0]+'_备份'+file_list[1] old_f=open(old_file,'r') #打开要备份的文件 new_f=open(new_file,'w') #以写的模式去打开新文件,不存在则创建 content=old_f.read() #将文件内容读取出来 new_f.write(content) #将读取的内容写入到备份文件 old_f.close() new_f.close() pass copyFile()
如果处理超大文件,一次将全部内容读取出来显然是不合适的,在上面需求的基础下改进代码,让他备份大文件也不会导致内存占满
def copyBigFile(): #接收用户输入的文件名 old_file=input('请输入要备份的文件名:') file_list=old_file.split('.') #构造新的文件名.加上备份的后缀 new_file=file_list[0]+'_备份'+file_list[1] try: #监视需要处理的逻辑 with open(old_file,'r') as old_f,open(new_file,'w') as new_f: while True: content=old_f.read(1024) #一次性读取1024个字符 new_f.write(content) if len(content)<1024: break except Exception as msg: print(msg) pass
3、文件定位
3.1 tell():文件定位,返回指针当前所在的位置,在读取文件的过程中,如果想知道当前的位置,可以使用tell()来获取
返回的是字符计算的位置,如果是字母就是一个字符,如果是gbk编码是一个汉字两个字符,utf-8是一个汉字三个字符
3.2 truncate():可以对源文件进行截取操作,会对源文件进行修改
fobjA=open('Test.txt','r+') #用读写的方式打开文件 fobjA.truncate(15) #对源文件截取前15个字符 print(fobjA.read()) #打印全部截取后的字符 fobjA.close() #保存关闭文件
3.3 seek():如果在操作文件的过程,需要定位到其他位置进行操作,用seek()
seek(offset,from)有2个参数,offset,偏移量单位字节,负数是往回偏移,正数是往前偏移,
from位置:0表示文件开头,1表示当前位置,2表示文件末尾
with open('Test.txt','rb') as f: data=f.read(2) print(data.decode('gbk')) f.seek(-2,1) #相当于光标有设置到了0的位置 print(f.read(4).decode('gbk'))
对于用’r‘模式打开文件,没有使用二进制选项打开的情况,只允许从文件的开头计算相对位置,从文件尾部计算或者当前位置计算就会引发异常
五、模块
1、模块导入方式
1.1 模块就是封装了一堆函数的py文件,就像是一个工具包,要使用里面的工具,得先将工具包拿过来。要使用模块就需要导入
1.2 模块导入使用import关键字
1.3 调用模块得方法,格式:模块名.函数名,这样调用可以防止不同模块有同名方法导致错误
1.4 import 首次导入模块得时候,会发生如下3个操作:import time =from time import *
①打开模块
②执行模块对应得文件,将执行过程中产生的名字都丢到模块的名称空间
③在程序中会有一个模块的名称指向模块的名称空间去
1.5 模块搜索路径,优先级如下:
①当前目录
②如果当前目录没有,到环境变量中搜索
cdm进入python,import sys,sys.path调用即可查看所有路径
③如果都找不到,搜索默认路径,linux系统,默认路径一般为:/usr/local/lib/python
第三方模块安装位置,在python安装目录下的lib/site-packages目录下(cmd下where python可以查看安装路径)
1.6 from … import导入模块的方法
一个模块可能会存在很多函数,如果只想导入其中几个函数,可以使用from xx import xx方式
例:from time import ctime,time
from … import首次导入模块得时候,会发生如下3个操作:
①打开模块
②执行模块对应得文件,将执行过程中产生的名字都丢到模块的名称空间
③在当前执行文件的名称空间中拿到一个名字,该名字直接指向模块中的某一个名字,意味着可以不用加任何前缀直接使用
1.7 可以给已有系统中的模块加别名
import time as myTime ,后续调用都要使用myTime了
1.8 使用from导入整个模块,如果函数名相同。后面导入的相同模块函数名会覆盖前面导入的模块函数名
2、os模块
2.1 对文件重命名、删除等一些操作,在python中可以利用os模块
2.2 常见的os使用函数
- os.rename(‘Test.txt’,’Test_重命名.txt’) 重命名文件
- os.remove(‘File_del.py’) 删除文件
- os.mkdir(‘d:/Python编程/sub核心’) 创建文件夹,但是不允许多级创建,此情况是d盘已存在Python编程文件夹
- os.rmdir(‘TestCJ’) 删除文件夹,只能删除空目录,如果里面有数据或者文本就无法删除
- os.makedirs(‘d:/Python编程/sub核心/三级sub’) 允许创建多级目录
- 如果要删除非空目录,就需要导入shutil模块import shutil,
- shutil.rmtree(‘d:/Python编程’) 可以实现多级删除
- print(os.getcwd()) 获取当前目录
- print(os.path) 可以打印当前os模块所在路径
- print(os.path.join(os.getcwd(),’venv’)) 路径拼接
- os.listdir(‘d:/’) 打印D盘根目录的所有文件或文件夹,只打印一级
with os.scandir('d:/') as entries: #scandir类似listdir效果 for entry in entries: print(entry.name)
#scandir和with一起来使用,这样的话,上下文管理器会在迭代器遍历完成后自动去释放资源
#判断文件,可以打印出D盘下所有的文件名 basePath='d:/' for entry in os.listdir(basePath): if os.path.isfile(os.path.join(basePath,entry)): print(entry)
2.3 模块制作
python文件都可以作为一个模块,模块的名字就是文件的名字,比如创建一个test.py文件,文件中创建一个add函数,test.py就是一个模块
__all__=['add','diff'] #如果模块中有声明all能导入的函数方法名时,通过from 模块 import *会受限只允许导入all中有的 #如果导入模块通过import 模块方式,就不受all的限制 def add(x,y): return x+y # 测试 要封装的模块的函数是否可以正确使用,可以通过以下,只锁定到本模块中,在其他模块调用此模块时不会把测试数据输出到其他模块中 if __name__='__main__': res=add(2,5) print(2,5) print('模块__name__变量=%s'%__name__) #通过这个可以看出,在本模块中__name__=__main__
#在其他要模块中如果打印这条,可以看到__name__=本模块名字
2.4 模块发布
①将写好的包放到一个指定目录下(可以自己新建一个专门的文件夹)
②在新建的文件夹下再创建一个setup.py文件,文件写入以下代码
from distutils.core import setup # name # version # description # author # py_modules setup(name='qiuzhijiangtang',version='1.0',description='文件统计模块',author='lilei',py_modules=['moduleTest']
#以上数据根据实际情况填写
③创建模块:通过cmd进入步骤①创建的文件目录,输入 python setup.py build
④生成压缩包:python setup.py sdist,这时候会生成一个qiuzhijiangtang-1.0.tar.gz名字的压缩包,这个压缩包发给别人安装就可以用了
到其他环境下安装:
⑤把④的压缩包拿来解压 tar-zxvf qiuzhijiangtang-1.0.tar.gz
⑥进入解压后的qiuzhijiangtang目录文件夹下cd进去
⑦执行python setup.py install
⑧查看是否安装成功,在python的安装目录下site-packages目录下是否存在
以上步骤5-8布可以等同于,进入压缩包所在目录下,一键安装pip install qiuzhijiangtang-1.0.tar.gz
六、垃圾回收机制
1、引用计数机制概述:现在得高级语言如java、c#等,都采用了垃圾手机机制,而不再是c,c++用户自己管理维护内存得方式。
自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患
python同java一样采用了垃圾收集机制,但是不一样得是,python采用得是”引用计数机制“为主
标记-清除 和 分代收集 两种机制为辅得策略
python里每一个东西都是对象,他们得核心就是一个结构体PyObject,ob_refcnt就是作为引用计数,当一个对象有新的引用时,
它得ob_refcnt就会+1,当引用他的对象被删除时,它得ob_refcnt就会减少,直到引用计数为0时,该对象生命就结束了
import sys a=[] # ob_refcnt=11 print(sys.getrefcount(a)) #ob_refcnt=2,打印完成后会释放一次,又变回1 b=a # ob_refcnt=2 print(sys.getrefcount(a)) # ob_refcnt=3,打印完成后会释放一次,又变回2
1.1 引用计数得优点:简单,实时性(一旦没有引用内存就直接释放了)且实时性带来一个好处:处理回收内存得实际分摊到了平时
1.2 引用计数得缺点:维护引用计数会消耗资源。会存在循环引用得情况。
例如:
list1=[] list2=[] list1.append(list2) list2.append(list1)
list1与list2相互引用,如果不存在其他对象对他们得引用,list1与list2得引用计数也仍然为1,所占用得内存用于无法被回收。
所以python还将引入新的回收机制(标记-清除 和 分代收集)
import psutil import sys import os import gc def showMemSize(tag): pid=os.getpid() # 获取进程PID print(pid) p=psutil.Process(pid) #此函数可以获取pid、进程名、进程状态、进程开始时间(即获取进程对象) print(p) #可打印出psutil.Process(pid=181956, name='python.exe', status='running', started='19:35:12') info=p.memory_full_info() #此函数可以获取rss、vms、num_page_faults、peak_wset、wset等多个参数,即获取进程信息 print(info) #可以打印出rss、vms、num_page_faults、peak_wset、wset、uss等参数 memory=info.uss/1024/1024 #info.uss,从进程信息中提取uss内存数据并转换为MB print('{} memory used:{} MB'.format(tag,memory)) pass # 验证循环引用得情况 def func(): showMemSize('初始化') a=[i for i in range(100000)] b=[i for i in range(100000)] a.append(b) b.append(a) showMemSize('创建列表对象a b之后') pass func() showMemSize('完成时候的') gc.collect() #手动调用垃圾回收功能,这样即使自动垃圾回收被关闭也会进行回收 showMemSize('手动释放后的')
# python默认时开启垃圾回收的,可以通过gc.disable()关闭
2、GC
2.1 GC负责得主要任务:
①为新生成得对象分配内存
②识别那些垃圾对象
③从垃圾对象那回收内存
2.2 零代处理最为频繁,其次时一代然后才是二代。
七、python内存优化
1、小整数与大整数对象池
python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。可以节省内存,提高执行效率,该池永远不会被垃圾回收机制回收
python对小整数得定义是[-5,256]这些整数对象是提前建立好的,不会被垃圾回收。
大整数池和小整数池的区别是:
①从结果来看是一样的,
②大整数池是没有提前创建好对象,是个空池子,需要我们自己去创建,创建好之后,会把整数对象保存到池子里面,后面都不需要再创建了,直接拿来用
八、python pep8规范
1、Guido的主要见解之一是代码读取的次数比写入次数多得多。这里提供的准则旨在提高代码的可读性并使其在各自python代码中保持一致
2、代码布局:
缩进:4个空格的缩进
不要使用tab,更不能混合使用tab和空格
连续行应使用python的隐式行连接括号,括号和大括号,或使用悬挂缩进来垂直对其包装元素
ctrl+alt+L可以一键调整代码格式
行宽:每行最大长度79,换行可以使用反斜杠,最好使用圆括号。换行点要在操作符后边敲回车。
文本长块,比如文档字符串或注释,行长度应限制为72个字符
空行:
①类和top-level函数定义之间空两行
②类中的方法定义之间空一行
③函数内逻辑无关段落之间空一行
④其他地方尽量不要再空行了
源文件编码:
①核心python发行版中的代码应始终使用UTF-8(或者python2中的ASCII)
②使用ASCII(在python2中)或UTF-8(在Python3中)的文件不应该有编码声明
③python标准库中的所有标识符必须使用纯ASCII标识符,并且应尽可能使用英文单词(在需要情况下,缩写和技术使用的术语不是英语)
④字符串文字和注释也必须使用ASCII
⑤这个主要是鼓励全球受众开放源码项目采取类似的政策,个人建议声明编码为utf-8
模块导入:
①导入顺序进行分组,内置模块放在前面,第三方模块放在后面导入,不建议使用import *会容易混淆
②本地应用程序/库特地的导入应该在每组导入之间流出空行
表达式与语句中的空格:
①避免无关空白,括号或者大括号内
②逗号、分号、冒号前面都不加空格
③函数的调用,小括号之前不加空格
④省略切片参数时,空格被省略,扩展切片参数时,两个冒号需要等量间距
⑤关键字参数和默认参数前面不加空格
注释:
①注释通常适合用于跟随他们的一些代码,并缩进到与该代码相同级别。
②块注释的每一行都以#和单个空格开头(除非它在注释内缩进文本)
③内联注释是对语句同一行的注释。内联注释应该与语句中的至少两个空格分隔
命名规范:
①模块名要简短,全部用小写字母,可使用下划线提高可读性。包名和模块名类似,但不推荐使用下划线
②类名通常使用大驼峰命名
③总是使用self作为实例方法的第一个参数,总是使用cls作为类方法的第一个参数
④使用函数命名规则:必要时用小写字母分隔下划线,以提高可读性
九、命令行参数
1、python可以用sys模块中的sys.argv来获取命令行参数
import sys
print(‘参数个数为’,len(sys.argv),’个参数。’)
print(‘参数列表’,str(sys.argv))
2、argparse模块可以轻松编写用户友好的命令行界面,该程序定义了它需要的参数。可以生成帮助和用法消息。在用户给出无效参数时发出错误
import argparse #创建一个解析器对象 parse=argparse.ArgumentParser(prog='my - 我自己的程序',usage='%(prog)s [options] usage', description='my-编写自定义命令的文件',epilog='my - epilog') #添加位置参数【必选参数】 parse.add_argument('name',type=str,help='你自己的名字') parse.add_argument('age',type=str,help='你的年龄') #添加可选参数 #parse.add_argument('-s','--sex',type=str,help='你的性别') parse.add_argument('-s','--sex',default='男',choices=['男','female','女','male'],type=str,help='你的性别') #还可以限定一个范围 #print(parse.print_help()) result=parse.parse_args() #开始解析参数 print(result)
- metaver:帮助信息中显示的参数名称
- const:保存一个常量
- default:默认值
- type:参数类型,默认为str
- choices:设置参数值的范围,如果choices中的类型不是字符串,记得指定type
- required:该选项是否必选,默认为True
- dest:参数名
例子:
import argparse #创建一个解析器对象 parse=argparse.ArgumentParser(prog='系统登录',usage='%(prog)s [options] usage', description='系统自定义命令行的文件',epilog='my - epilog') #添加位置参数【必选参数】 parse.add_argument('loginType',type=str,help='登录系统类型') #添加可选参数 #parse.add_argument('-s','--sex',type=str,help='你的性别') parse.add_argument('-u',dest='user',type=str,help='你的用户名') parse.add_argument('-p',dest='pwd',type=str,help='你的密码') result=parse.parse_args() #开始解析参数 if (result.user=='root' and result.pwd=='111111'): print('login sucess!') else: print('login fail!')