Python是一种面向对象的解释性计算机程序设计语言.
目录
变量和数据类型
Python基本运算符
Python的输入与输出
判断语句与循环控制
字符串操作
列表及常用方法
元组
字典
公用方法
函数
全局变量和局部变量
Python内置函数
面向对象(oop:object oriented programming)
异常处理
文件操作
导入模块
os模块操作文件
模块制作、发布、安装
Python的缺点:
变量相当于一个盒子,里面可以装各种东西,变量的概念与初中代数方程变量是一致的.在写程序的时候,变量不仅仅可以是数字,还可以是其他任意类型.
变量+逻辑-->python解释器-->软件的功能
变量=存储的数据
顾名思义:变量是一段有名字的连续存储的空间,我们可以通过定义变量来申请并命名存储空间,并通过变量名来使用这段存储空间,在程序中用于临时存放数据的场所.
定义变量: 变量名=值
变量可以多次赋值,在程序执行的过程中,值可以改变.
Python基本数据类型:
Python提供了type方法查看变量的类型,使用方式:type(变量名)
命名规则:
命名规范:
算术运算符:
比较运算符:
逻辑运算符:
优先级: ()->not->and->or
优先级高时,先从优先级高的部分开始计算,优先级相同时,从左往右计算.
赋值运算符:
输出:使用print()方法
注意:使用print()打印数据时,默认换行,如果想自定义打印结束后的字符,可以设置该方法的end参数。
# %表示占位符,后面跟要输出数据的类型
name='xixi'
comeFrom='四川'
age=18
print('我的名字是%s,来自%s,今年%d'%(name,comeFrom,age))
print('我的名字是%s,来自%s,今年%d'%(name,comeFrom),end=',')
print('今年%d'%age)
常用的格式化符号,其中最常用%s,%d,%f
使用.format()格式化输出
name = 'xixi'
comeFrom = '四川'
print('姓名:{},来自:{}'.format(name, comeFrom))
输入:Python中提供了input 方法来获取键盘的输入,input中的参数用来提示输入.
注意:input接收的键盘输入结果都是str类型的,如果接收数字类型需要将str转成int.
name=input('请输入你的姓名:')
age=input('请输入你的年龄:')
print('姓名:%s,年龄:%d'%(name,int(age)))
流程是指计算机执行代码的顺序;流程控制是对计算机代码的执行顺序进行有效的管理。只有流程控制才能实现在开发当中的业务逻辑。
流程控制的分类:
条件表达式:比较运算符/逻辑运算符/复合的运算符
while 条件表达式:
一条条的Python代码
一条条的Python代码
……
for ... in 可迭代的对象:
一条条的Python代码
一条条的Python代码
……
循环的语法特点:
使用条件:循环的次数不确定,依靠循环条件来结束。
使用目的:为了将相似或者相同的代码操作变得更加简洁,使得代码可以重复利用。
range()函数可以生成一个数据集合列表
range(起始,结束,步长) 步长不能为0,数据范围是 :【起始,结束)
break与continue关键字:
break:退出循环;
continue:跳过本次循环。
while适用于未知的循环次数;for使用于已知的循环次数【可迭代对象遍历】
for----else----的使用
从以上两个图中的打印结果显示,当顺利遍历结束后便会执行else中的语句,当for循环被break退出时,则不会执行else中的语句。使用场景:需要遍历查找某个值,当找到值时退出循环,没有找到时则打印提示消息。
while----else----的使用:
while---else---执行结果与for---else---相似。
Python中的序列:是一组按顺序排列的值【数据集合】。
Python中的三种内置的序列类型:字符串、列表、元组
优点:可以支持索引和切片的操作
特征:第一个正索引为0,指向的是左端,第一个索引为负数的时候,指向的是右端
切片:是指截取字符串中的一段内容。用法:[起始下标,结束下标,步长] 切片截取的内容不包括结束下标对应的数据,步长指的是隔几个下标获取一个字符。
字符串常用方法:
test = 'python'
# print(type(test))
# print(test[0])
# print(test[-1])
# for item in test:
# print(item, end=' ')
# capitalize
# print('首字母转换大写%s'%test.capitalize())
a = ' he llo '
# print('去除字符串前后的空格%s'%a.strip())
# print('去除字符串左边的空格%s!!!!'%a.lstrip())
# print('去除字符串右边的空格%s!!!!'%a.rstrip())
# 复制字符串
b = a # 只是把a的内存地址赋给了b
# print('a的内存地址%d' % id(a)) # id函数可以查看一个对象的内存地址
# print('b的内存地址%d' % id(b))
# 查找数据
dataStr = 'I love Python'
# 使用find函数
# print(dataStr.find('o')) # 在序列中查找第一个出现的目标对象的下标
# print(dataStr.find('m')) # 在序列中没有查找目标对象就返回-1
# 使用index函数
# print(dataStr.index('o'))
# print(dataStr.index('m')) # 当index函数没有找到目标对象会报异常
# print(dataStr.startswith('I ')) # 判断开头
# print(dataStr.endswith('n')) # 判断结尾
# print(dataStr.lower()) # 转换小写
# print(dataStr.upper()) # 转换大写
# 切片操作
strMsg = 'hello world'
# slice[start:end:step] 左闭右开区间:start<=value
列表是一种有序的集合,可以随时添加和删除其中的元素。
创建列表:用中括号"[]"括起来,在括号中添加元素,并且用逗号分隔不同的数据项,列表中的数据项可以是任何类型的数据。
列表的下标取值/切片是否越界与字符串一致,区别就是列表获取元素。
用for循环可将列表中的元素一个一个取出,取完后退出循环。
# li = [] # 空列表
# li = [1, 2, 3, 4, '你好']
# print(len(li)) # len函数可以获取到列表对象中的数据个数
# strA = '我喜欢Python'
# print(len(strA))
# 查找
listA = ['abcd', 785, 12.23, 'quzhi', True]
# print(listA) # 输出完整的列表
# print(listA[0]) # 输出第一个元素
# print(listA[1:3]) # 输出第2个元素到第3个元素
# print(listA[2:]) # 输出第三个元素到最后的元素
# print(listA[::-1]) # 倒序从右往左输出
# print(listA * 2) # 多次输出列表中的数据
# print('---------常用的函数-----------')
# listA.append(['fff','ddd']) # 向列表中追加任意类型的数据
# listA.append(888)
# print(listA)
# listA.insert(1,'这是我刚插入的数据') # 指定列表位置插入
# print(listA)
# rsData=list(range(10)) #强制转换为list对象
# print(type(rsData))
# listA.extend(rsData) #扩展 等于批量添加
# listA.extend([11,22,33])
# print(listA)
# print('-------------修改-----------------')
# print('修改之前',listA)
# listA[0]='peter'
# print('修改之后',listA)
print('-------------删除列表数据项-----------------')
listB = list(range(10, 50))
print('删除之前', listB)
# del listB[0] # 删除列表中的第一个元素
# del listB[1:3] # 批量删除,第二到第三个元素
# listB.remove(20) #移除指定的元素,参数具体值
# listB.pop(0)
listB.pop(1) # 移除指定项,参数是索引值
print('删除之后', listB)
print(listB.index(19,20,25)) # 获取指定元素的索引值,第二个参数是查找起始位置,第三个参数是查找长度
元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,元组也是通过下标进行访问。
元组创建:在括号中添加元素,并使用逗号隔开。
方法:
tupleA = () # 空元组
# print(id(tupleA))
tupleA = ('abcd', 89, 9.12, 'peter', [1, 2, 3])
# print(id(tupleA))
# print(type(tupleA))
# print(tupleA)
# 元组的查询
# for item in tupleA:
# print(item,end=' ')
# print(tupleA[2])
# print(tupleA[2:4])
# print(tupleA[::-1]) # 倒序输出元组
# print(tupleA[::-2]) # 倒序输出元组,步长为2
# print(tupleA[-2:-1:]) # 从右往左取值 取-2到-1区间
# print(tupleA[-4:-2:]) # 从右往左取值 取-4到-2区间
# print(type(tupleA[4]))
# tupleA[4][2] = 22 # 可以对元组中的列表进行修改
# print(tupleA)
# 当元组中只有一个元素时,必须要加一个逗号,才会被认为是元组
# tupleB = (1)
# print(type(tupleB)) #
#
# tupleC = ('1')
# print(type(tupleC)) #
#
# tupleD = (1,)
# print(type(tupleD)) #
tupleE = (1, 2, 3, 4, 3, 4, 4, 1)
print(tupleE.count(4)) # 可以统计元素出现的次数
字典是Python的一种重要的数据类型,可以存储任意对象。字典是以键值对的形式创建的{'key':value}利用大括号包裹,通常使用键来访问数据。
访问值的安全方式是使用get方法,在我们不确定字典中是否存在某个键而又想获取其值时,可以使用get方法,还可以设置默认值。
特点
字典中的常用方法:
# 创建字典
# dictA = {} # 空字典
# print(type(dictA))
# 添加字典数据
dictA={'pro':'艺术','school':'北京电影学院'}
dictA['name'] = '李易峰'
dictA['age']='30'
dictA['pos']='歌手'
# print(dictA) # 输出完整的字典
# print(len(dictA))
# print(dictA['name']) # 通过键获取对应的值
# dictA['name']='谢霆锋' # 修改键对应的值
# print(dictA['name'])
# dictA.update({'age':32}) # 更新字典
# dictA.update({'height':1.80}) # 添加键值对
# print(dictA)
# # 获取所有的键
# print(dictA.keys())
# # 获取所有的值
# print(dictA.values())
# # 获取所有的数据项(键值对)
# print(dictA.items())
#
# for key,value in dictA.items():
# print('%s==%s'%(key,value))
# # 删除操作
# del dictA['name'] # 通过指定键进行删除
# print(dictA)
# dictA.pop('age') # 通过指定键进行删除
# print(dictA)
# 最字典进行排序
# 按照key排序
print(dictA)
print(sorted(dictA.items(),key=lambda d:d[0]))
# 按照value排序
print(sorted(dictA.items(),key=lambda d:d[1]))
# 公有方法 + * in
# # 字符串合并
strA='人生苦短'
# strB='我用Pyhon'
# print(strA+strB)
# # 列表合并
listA=list(range(10))
# listB=list(range(11,20))
# print(listA+listB)
# # 元组合并
tupleA=tuple(range(10))
# tupleB=tuple(range(11,20))
# print(tupleA+tupleB)
#
# # 复制
# print(strA*3)
# print(listA*3)
# print(tupleA*3)
# in 判断元素是否存在
print('生' in strA)
print(10 in listA)
print(3 in tupleA)
dictA={'name':'peter'}
print('age' in dictA)
概念:为了降低代码的重复率和提高代码编写效率和复用,将具有独立功能的代码块组织为一个小模块,这就是函数。
函数的定义:
def 函数名():
代码块
函数的调用:
函数名() # 即可调用该函数
函数的说明文档:
函数内部的第一行可以用字符串进行函数说明。
def 函数名():
'''
函数的说明
:return:说明函数返回的内容
'''
代码块
参数:函数为了实现某项功能,进而得到实现功能所需要的数据,参数是为了得到外部数据的。
# 必选参数
# 形式参数:只是意义上的一种参数,在定义的时候是不占内存地址的
def sum(a, b):
sum = a + b
print(sum)
pass
# 必选参数调用 在调用的时候,必须要给必选参数赋值
# sum(1, 2) # 1,2 就是实际参数,简称实参,是实实在在的参数,是实际占用内存地址的
# 缺省参数【默认参数】 默认参数必须放在参数列表中的最后面,如不能写成 sum1(a=10,b)
def sum1(a=1, b=2):
sum = a + b
print(sum)
pass
# 默认参数调用
# sum1() # 在调用时,如果没有赋值,就会使用定义函数时给定的默认值
# sum1(3,5)
# 可选参数 当不确定参数个数时使用
def getComputer(*args):
'''
计算累加和
:param args: 可变长的参数类型
:return:
'''
result = 0
for item in args:
result += item
print(result)
pass
# getComputer(1,2,3,4,5)
# 关键字可变参数
# 用**来定义,在函数体内,参数关键字是一个字典类型 key是一个字符串
def keyFunc(**kwargs):
print(kwargs)
pass
# 调用
# keyFunc(1,2,3) # 不可以这样传递
dictA = {'name': 'Leo', 'age': 35}
# keyFunc(**dictA)
# keyFunc(name='peter',age=26)
# keyFunc()
def complexFunc(*args, **kwargs):
print(args)
print(kwargs)
pass
# complexFunc()
# complexFunc(1, 2, 3, 4, name='刘德华')
# complexFunc(name='刘德华')
# def TestMup(**kwargs,*args):
# '''
# 可选参数必选放到关键字可选参数之前
# 可选参数:接受的数据是一个元组类型
# 关键字可选参数:接受的数据是一个字段类型
# :param kwargs:
# :param args:
# :return:
# '''
# pass
函数传参时,实际传的是实参的地址,是对同一个对象的引用。
a = 1
def func(x):
print('x的地址:{}'.format(id(x)))
x=2
print('x修改后的地址:{}'.format(id(x)))
pass
print('a的地址:{}'.format(id(a)))
func(a)
函数的返回值:程序中函数完成后返回给调用者的结果。如果函数需要返回多个结果,将要返回的值用逗号隔开,最终会返回一个包含所偶有返回值的元组。
函数的嵌套调用:一个函数中可以调用另一个函数。
函数的使用实例:
# 接收n个数字,并且计算参数数字的和
def sumFunc(*args):
'''
处理接收的参数
:param args: 接收的是一个可变参数
:return:一个数字
'''
rs = 0
for item in args:
rs += item
return rs
pass
# print(sumFunc(1, 2, 3, 4))
# 找出传入的列表或元组的奇数位对应的元素,并返回一个新的列表
def newList(con):
'''
处理列表或元组数据
:param con:一个列表或元组
:return:返回一个新的列表
'''
li = []
index = 1
for item in con:
if index % 2 == 1: # 判断奇数位
li.append(item)
index += 1
return li
def newList1(con):
return con[0::2]
# print(newList([1, 2, 3, 4, 5]))
# print(newList(tuple(range(1, 20))))
# print(newList1([1, 2, 3, 4, 5]))
# 处理字典
def dictFunc(dicParams): # **kwargs
'''
处理字典值的长度
:param dicParams:字典
:return:
'''
result={}
for key,value in dicParams.items():
if len(value)>2:
result[key]=value[:2]
else:
result[key]=value
return result
dic={'name':'peter','age':'20','height':'1.78','hobby':['唱歌','跳舞','编程']}
print(dictFunc(dic))
函数的四种基本类型
在Python中,值是靠引用来传递的,可以用id()查看一个对象的引用是否相同,id是保存在内存中的内存地址的标识。
匿名函数:使用lambda关键字创建匿名函数,这个函数没有名字,不用def关键字创建的标准函数。
特点:
lambda 参数1,参数2,参数3:执行代码表达式
test = lambda x, y: x + y
print(test(1, 3))
# 对应的普通函数
def test(x, y):
return x + y
三元运算符与匿名函数:
# 三元运算符
isGirl = True
sex = 'girl' if isGirl else 'boy'
print(sex)
# 匿名函数
isGirl = lambda arg: 'girl' if arg else 'boy'
print(isGirl(True))
递归函数:如果一个函数再内部调用自己,这就是递归函数。
递归函数必须有一个结束条件,否则递归无法结束会一致递归下去,直到到达最大递归深度报错。
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5))
递归实例
# 递归案例 模拟实现 树形结构的遍历
import os # 引入文件操作模块
def findFile(file_path):
listRs = os.listdir(file_path) # 得到该路径下所有的文件和文件夹
for fileItem in listRs:
full_path = os.path.join(file_path, fileItem) # 获取完整的文件路径
if os.path.isdir(full_path): # 判断是否是文件夹
findFile(full_path) # 如果是一个文件夹,再次去递归
else:
print(fileItem)
pass
pass
else:
return
# 调用搜索文件对象
findFile('D:\Python爬虫')
局部变量:在函数内部定义的变量,作用域仅仅局限在函数的内部。不同的函数可以定义相同的局部变量,相互不会影响。作用是在函数中保存临时的数据。
全局变量:全局变量是在定义函数的同级定义的,可在不同的函数中访问。
当函数中使用的变量既在函数内部定义作为一个局部变量,也在函数外部有定义时,函数使用的是局部变量。
函数中不可以直接修改全局变量,需要使用global关键字后才能修改
va=11
def change():
global va
va=22
pass
Built-in Functions — Python 3.10.2 documentation
数学运算:
abs(),round(),pow(),divmod(),max(),min(),sum(),eval()
类型转换函数:
int(),float(),str(),ord(),ch r(),bool(),bin(),hex(),oct(),list(),tuple(),dict(),bytes()
序列(str,元组,列表)操作函数:
all(),any(),sorted(),reverse(),range(),zip(),enumerate()
sort与sorted方法的区别:
set集合
set(集合)也是Python中的一种数据类型,是一个无序且不重复的元素组合,类似于字典,但是只有key,没有value。
集合操作函数:
add(),clear(),difference()等效于'"-",intersection()等效于'"&",union()等效于'"|",pop(),discard(),update()
创建方式
# 创建集合
# 方式一
set1 = {'1', '2'}
# 方式二
list1 = ['1', '2', '3', '4']
set2 = set(list1)
面向过程:根据业务逻辑从上到下写代码。
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可。
面向对象编程:将数据与函数捆绑到一起,进行封装,这样能够更快速的开发程序,减少了重复写代码的过程。
类和对象是面向对象编程中重要的概念。
类是一个模板,模板里面可以包含多个函数,函数里实现一些功能。
对象是根据模板创建的实例,通过实例对象可以执行类中的函数。
类(Class)由3部分组成:
类的抽象:具有相同或相似属性和行为的一系列对象的集合都可以抽象出一个类
定义类和对象
# 定义类和对象
# 类名采用大驼峰命名
class Person:
'''
特征
'''
name = '小明'
age = 20
'''
对应人的行为
'''
def eat(self):
print('大口吃饭')
pass
def run(self):
print('大步跑')
pass
# 创建一个对象【类的实例化】
# 规则格式 对象名=类名()
xm = Person()
xm.eat() # 调用函数
print('{}的年龄是{}'.format(xm.name,xm.age))
实例方法:在类的内部,使用def关键字来定义,第一个参数默认是self【名字表示可以是其他的名字,但是这个位置必须被占用】,实例方法是归于类的实例所有。
属性:定义在类里面的变量,在方法外面的属性,称之为类属性;定义在方法里面使用self引用的属性称之为实例属性。
类属性可以通过类对象或实例对象访问,实例属性必须通过实例对象才能访问。
所有实例对象的类对象指针指向同一类对象。实例属性在每个实例中独有一份,而类属性是所有实例对象共有一份。
当修改类属性时,只能通过类对象进行修改,如果直接用实例对象对属性进行修改,相当于增加了一个同类属性同名的实例属性,类属性并没有改变。
class Person:
'''
特征
'''
# name = '小明' # 类属性
age = 20 # 类属性
def __init__(self):
self.name = '小明' # 实例属性
pass
__init__方法
__init__(self)方法:
class Person():
def __init__(self):
# 实例属性
self.name = '小倩'
self.age = 20
self.sex = '女'
pass
xm = Person()
print('{}:年龄是{},性别是{}'.format(xm.name, xm.age, xm.sex))
# 修改实例属性
xm.name='小明'
print('{}:年龄是{},性别是{}'.format(xm.name, xm.age, xm.sex))
通过将属性以参数的形式在实例化时传递给__init__方法,使类更加通用:
class Person1:
def __init__(self, name, age, sex):
# 实例属性
self.name = name
self.age = age
self.sex = sex
pass
xm1 = Person1('小倩', 20, '女')
print('{}:年龄是{},性别是{}'.format(xm1.name, xm1.age, xm1.sex))
理解self
class Person1:
def getSelf(self):
print('self=%s'%id(self))
def __init__(self, name, age, sex):
# 实例属性
self.name = name
self.age = age
self.sex = sex
pass
xm1 = Person1('小倩', 20, '女')
print('对象=%s'%id(xm1))
xm1.getSelf()
魔术方法(用双下划线包起来的方法)
常见的魔术方法:
class Person:
def __init__(self, name, age, sex):
# 实例属性
self.name = name
self.age = age
self.sex = sex
print('init函数的执行')
pass
def __str__(self):
return '我的名字是%s,我的年龄是%d' % (self.name, self.age)
def __new__(cls, *args, **kwargs):
'''
创建对象实例的方法,每调用一次会生成一个新的对象,cls是class的缩写
场景:可以控制创建对象的一些属性限定,经常用来做单例模式的时候使用
:param args:
:param kwargs:
:return:
'''
print('new函数的执行')
return object.__new__(cls) # 在这里是真正创建对象实例的
pass
xm1 = Person('小倩', 20, '女')
print(xm1)
析构方法:
当一个对象被删除或者被销毁时,Python解释器也会默认调用一个方法,这个方法为__del__()方法,也称为析构方法。
class Animal:
def __init__(self, name):
self.name = name
print('这是构造初始化方法')
pass
def __del__(self):
# 主要用作对象的释放,一旦释放完毕,对象便不能再使用
print('当在某个作用域下面 没有被使用【引用】的情况下 解释器会自动调用此函数 来释放内存空间')
print('这是析构方法')
print('%s 这个对象被彻底清理了 内存空间也释放了'%self.name)
pass
cat = Animal('猫猫')
input('程序等待中:') # 当完成输入后,默认结束程序
对于面向对象的继承来说,起始就是将多个类共有的方法提取到父类中,子类仅需继承父类,而不必一一实现每一个方法。
动态添加属性
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
pass
def __str__(self):
return '{}今年{}岁了'.format(self.name,self.age)
zs=Student('张三','20')
zs.weight=80 # 动态添加实例属性
print(zs)
print(zs.weight)
print('----------创建一个新实例对象--------------')
ls=Student('李四','22')
print(ls)
# print(ls.weight) # ls不具备weight属性
print('------------给类对象动态添加属性------------')
Student.school='北大' # 通过类对象动态添加类属性
print(zs.school)
print(ls.school)
动态添加方法
动态添加实例方法需要使用types中的MethodType模块,如果要添加类方法,定义方法时要用装饰器@classmethod修饰该方法,至少有一个参数,第一个参数默认是类,然后将该方法直接赋值给类中对应命名的方法;添加静态方法和添加类方法相似,用@staticmethod方法修饰,但可以不传参数:
print('-------------动态添加实例方法------------')
import types
def dynamicMethod(self):
print('{}的体重是{}kg 在{}读大学'.format(self.name, self.weight, Student.school))
zs.printInfo = types.MethodType(dynamicMethod, zs) # 绑定方法
zs.printInfo() # 调用动态绑定的实例方法
ls.printInfo=types.MethodType(dynamicMethod,ls) # 由于ls没有weight实例属性,调用时会报错
# ls.printInfo()
print('-------------动态添加类方法------------')
@classmethod
def classTest(cls,oth):
print('这是一个类方法')
print('绑定后还可以访问类属性',cls.school)
print(oth)
pass
Student.TestMethod=classTest
Student.TestMethod('这是动态绑定类方法的其他参数')
print('实例对象调用:')
zs.TestMethod('该类的实例对象也可以调用')
print('-------------动态添加静态方法------------')
@staticmethod
def staticMethodTest():
print('这是一个静态方法')
pass
Student.staticMethodTest=staticMethodTest;
Student.staticMethodTest()
Python是动态语言,在运行时可以动态添加属性。如果要限制在运行时给类添加属性,Python允许在定义class的时候,定义一个特殊的__slots__变量,用以限制该class实例能添加的属性。
只有在__slots__变量中的属性才能被添加,没有在__slots__变量中的属性会添加失败。可以防止他人在调用类的时候胡乱添加属性或方法。__slots__属性子类不会继承,只有在当前类中有效。
# __slots__属性作用
# 限制要添加的实例属性
class Student(object):
__slots__ = ('name', 'age')
def __str__(self):
return '{}{}'.format(self.name, self.age)
pass
zs = Student()
zs.name = "小王"
zs.age = 20
print(zs)
try:
# 不可以添加除了name age之外的其他属性
zs.school = 'dfsa'
except AttributeError as msg:
print(msg)
finally:
print(zs)
# 如果没有加__slots__属性,所有可用的属性不过都在这里存储,不足在于:占用的内存空间大
# print(zs.__dict__)
# 在定义了__slots__属性后,Student类的实例已经不能随意创建不在__slots__定义的属性,
# 同时,实例中不再有__dict__属性,可以节约内存空间
# 在继承关系中的使用 __slots__
# 当子类未声明 __slots__时,是不会继承父类的__slots__,此时子类是可以随意的属性赋值的
# 子类声明__slots__时,继承父类的__slots__,子类的__slots__的范围是本身定义的范围和父类__slots定义范围的并集(在限定时,最好不要重复限定)
class subStudent(Student):
__slots__ = ('gender','pro') # 会继承父类已经限制的条件
pass
ls = subStudent()
ls.gender = '男'
ls.pro = '计算机'
print(ls.gender)
单继承
class Dog(Animal): # 继承Animal父类 此时dog就是子类
'''
狗的独有行为
'''
def wwj(self):
print('小狗汪汪叫')
pass
class Cat(Animal):
'''
猫的独有行为
'''
def mmj(self):
print('小猫喵喵叫')
pass
d1 = Dog()
d1.eat() # 继承了父类吃的行为
c1 = Cat()
c1.drink() # 继承了父类喝的行为
c1.mmj() # 猫的独有行为
多继承
子类可以继承多个父类。
class Animal:
def eat(self):
print('动物都要吃东西')
pass
class People:
def talk(self):
print('人类可以说话')
pass
class Boy(Animal, People):
pass
xm = Boy()
xm.eat()
xm.talk()
# 当多个父类中存在多个相同方法时,该去调用哪一个
class D(object):
def eat(self):
print('D.eat')
pass
pass
class C(D):
def eat(self):
print('C.eat')
pass
pass
class B(D):
pass
class A(B,C):
pass
a=A()
a.eat()
print(A.__mro__) # 可以依次显示A的继承顺序
# 在执行eat的方法时,查找顺序是:
# 首先到A里面查找,如果A中没有,则继续到B类中去查找,如果B类中没有
# 则去C类中查找,如果C类中没有,则去D类中查找,如果还是没有找到 就会报错
# A->B->C->D 也是继承的顺序
类的传递:在类的传递过程中,我们把父类又称为基类,子类又称为派生类,父类的属性和方法可以一级一级的传递到子类,也称为间接继承
class GrandFather:
def eat(self):
print('爷爷吃的方法')
pass
pass
class Father(GrandFather):
pass
class Son(Father):
pass
xm = Son()
xm.eat() # 此方法是从GrandFather继承来的
重写父类的方法:就是在子类中有一个和父类相同名字的方法,在子类的方法会覆盖掉父类中同名的方法
class GrandFather:
def eat(self):
print('爷爷吃的方法')
pass
pass
class Father(GrandFather):
def eat(self):
print('父亲吃的方法')
pass
pass
xf=Father()
xf.eat() # 调用Father类中的eat()方法
父类方法的调用
class Dog:
def __init__(self, name, color):
self.name = name
self.color = color
def bark(self):
print('汪汪叫……')
class Keji(Dog):
def __init__(self, name, color, age):
# Dog.__init__(self,name, color)
# super是自动找到父类,进而调用方法
super().__init__(name, color)
self.age = age
def bark(self):
super().bark()
print('柯基叫')
def __str__(self):
return '这只%s的%s已经%d岁啦' % (self.color, self.name, self.age)
pass
xk = Keji('柯基犬', '黄色', 1)
print(xk)
xk.bark()
多态
多态是指定义时的类型和运行时的类型不一样,是同一种行为对于不同的子类【对象】有不同的行为表现,关注的不是对象的类型本身,而是它是如何使用的。
要实现多态,必须遵守两个前提:
多态的用处:
# 案例演示
class Animal:
'''
父类【基类】
'''
def say(self):
print('我是一个动物……')
pass
pass
class Duck(Animal):
'''
鸭子类【子类/派生类】
'''
def say(self):
'''
在这里重写父类的方法
:return:
'''
print('我是一只漂亮的鸭子')
pass
pass
class Dog(Animal):
'''
狗类【子类/派生类】
'''
def say(self):
'''
在这里重写父类的方法
:return:
'''
print('我是一只可爱的小狗')
pass
pass
class Bird(Animal):
'''
鸟类【子类/派生类】
'''
def say(self):
'''
在这里重写父类的方法
:return:
'''
print('我是一只黄鹂鸟')
pass
pass
def commonInvoke(obj):
'''
统一调用的方法
:param obj: 对象的实例
:return:
'''
obj.say()
# duck1 = Duck()
# duck1.say()
#
# dog=Dog()
# dog.say()
listObj=[Duck(),Dog(),Bird()]
for item in listObj:
'''
循环调用函数
'''
commonInvoke(item)
类方法和静态方法
类方法:类对象所拥有的方法,需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数,类方法可以通过类对象、实例对象调用。
class People:
country = 'China'
# 类方法 用classmethod修饰
@classmethod
def get_country(cls):
return cls.country # 访问类属性
pass
@classmethod
def set_country(cls):
cls.country = 'America'
pass
pass
print('通过类对象访问:%s' % People.get_country()) # 通过类对象直接引用
p = People()
print('通过实例对象访问:%s' % p.get_country()) # 通过类对象直接引用
# 通过类方法修改类属性
print('修改前的类属性:%s'%People.country)
People.set_country()
print('修改后的类属性:%s'%People.country)
静态方法:类对象所拥有的方法,需要使用@staticmethod来标识静态方法,静态方法不需要任何参数
注意:一般情况下,我们不会通过实例对象去访问静态方法
静态方法的作用:由于静态方法主要来存放逻辑性的代码,本身和类及实例对象没有交互,在静态方法中,不会涉及到类中方法和属性的操作,数据资源能够得到有效的充分利用。
class People:
country = 'China'
@staticmethod
def getData():
return People.country # 通过类对象去引用
pass
pass
print(People.getData())
p = People()
print(p.getData()) # 注意一般情况下,我们不会通过实例对象去访问静态方法
私有化属性
为了更好的保护属性安全,即不能随意修改,将属性定义为私有属性,添加一个可调用的方法去访问。
语法:两个下划线开头,声明该属性为私有,不能再类的外部被使用或直接访问。
使用私有属性的场景:
class Person:
def __init__(self):
self.__name = '李四' # 加两个下划线,将此实例属性私有化,私有化之后就不能在外部直接访问了,在类的内部可以访问
self.age = 30
pass
def __str__(self):
# 私有化属性可以在类的内部访问
return '{}的年龄是{}'.format(self.__name, self.age)
# 修改私有化属性
def setPrivacy(self):
self.__name='张三'
pass
xl = Person()
# print(xl.__name) # 通过实例对象在外面无法访问私有属性
print(xl.age)
print(xl)
print('私有属性修改前:',xl)
xl.setPrivacy()
print('私有属性修改后:',xl)
class Student(Person):
def printInfo(self):
print(self.age)
print(self.__name) # 在此访问父类中的私有属性
pass
pass
stu=Student()
# stu.printInfo() # Student并没有继承Person的name属性
私有方法:跟私有化属性概念一样,有些重要的方法,不允许外部调用,防止子类意外重写,把普通的方法设置成私有化方法。
语法:在方法名前面加两个下划线
class Animal:
def eat(self):
self.__run() # 在类的内部可以调用私有化方法
print('Animal吃东西')
pass
def __run(self):
print('Animal飞快地跑')
pass
pass
class Bird(Animal):
pass
b1=Bird()
# b1.__run() # 私有化属性不会被继承
b1.eat()
Python中单下划线、双下划线、头尾双下划线的说明:
Property属性
上面提到的私有变量,一般要写两个方法,一个用于访问,一个用于修改,由方法控制访问。给调用者的感觉是调用了一个方法,而不是访问属性。
Python中的属性函数(Property)可以通过属性的方式访问私有化的属性和方法。
方式1:在类中定义值为property对象的类属性
class Person:
def __init__(self):
self.__age = 10
pass
def set_age(self, age):
if age < 0:
print('年龄不能小于0')
else:
self.__age = age
pass
def get_age(self):
return self.__age
pass
age = property(get_age, set_age)
xm = Person()
print('修改之前的age:%s' % xm.age)
xm.age = 9
print('修改之后的age:%s' % xm.age)
方式2:在方法上使用装饰器
class Person:
def __init__(self):
self.__age = 10
pass
@property # 使用装饰器对age进行装饰,提供一个getter方法
def age(self):
return self.__age
pass
@age.setter # 使用装饰器对age进行装饰,提供一个setter方法
def age(self, age):
if age < 0:
print('年龄不能小于0')
else:
self.__age = age
pass
xm = Person()
print('修改之前的age:%s' % xm.age)
xm.age = 0
print('修改之后的age:%s' % xm.age)
__new__方法
作用:创建并返回一个实例对象,如果__new__值调用了一次,就会得到一个实例对象。继承自object的新式类才有new这一魔术方法。
注意
单例模式:是常用的一种程序设计模式,在该模式下能确保系统中某个类只有一个实例对象,并且提供了一个全局的访问点,例如计算机中的回收站、资源管理器、网络计数器、权限验证模块,数据库连接池等。
# 创建一个单例对象,基于__new__实现【推荐方式】
class DataBaseClass(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_instance'): # 如果不存在就开始创建
# cls._instance=cls.__new__(cls) # 切记不能这样写(用自身的new方法),容易造成深度递归,堆栈溢出。
# 应该调用父类的new方法
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
pass
class DBopSingle(DataBaseClass):
pass
# 当没有使用if判断时,可以创建多个不同实例对象
# db1=DataBaseClass()
# print(id(db1)) # 1863567180104
# db2=DataBaseClass()
# print(id(db2)) # 1863567180104
# 添加if条件后,这个类只能创建一个实例对象
# db1=DataBaseClass()
# print(id(db1)) # 2948817846920
# db2=DataBaseClass()
# print(id(db2)) # 2948817846920
# 子类也只能创建一个实例
db1=DBopSingle()
print(id(db1)) # 1990560250952
db2=DBopSingle()
print(id(db2)) # 1990560250952
异常:是指程序执行过程中发生的错误。
语法格式:
try:
可能出错的代码块
except:
出错之后执行的代码块
else:
没有出错的代码块
finally:
不管有没有出错都执行的代码块
try...except...语句:将可能出错的代码放到try里面,except可以指定类型捕获异常。except里面的代码是捕获到异常时执行,将错误捕获,这样的程序就不会因为一段代码报异常而导致整个程序崩溃。
# try:
# print(b) # 捕获逻辑的代码
# pass
# except:
# # 捕获到错误了才会执行下面的代码
# print('b当前没有被声明')
# print(b)
try:
print(b)
pass
except NameError as msg: # NameError是可能出现异常类型
print(msg)
try:
list=[1,2,3,4]
print(list[10])
pass
except NameError as msg: # 一个try后面可以跟多个except
print(msg)
except IndexError as msg:
print(msg)
except在捕获异常的时候,是要根据具体的错误类型来捕获的。可以用 Exception来捕获所有的异常,当出现的问题不确定的情况下,可以用Exception,注意:如果捕获到异常要尽量在except中去处理掉异常:
try:
list=[1,2,3,4]
print(list[10])
pass
except Exception as msg:
print(msg)
不需要在每一个可能出错误的地方使用try……exception,只要在合适的层次去捕获就可以了:
def A(s):
return 10 / s
def B(s):
return A(s) * 2
def main():
try:
B(0)
except Exception as msg:
print(msg)
main()
如果在运行时发生异常,解释器会查找相应的异常捕获类型,如果在当前函数里面没有找到,会将异常传递给上层的调用函数。
try……except……else:
try:
print('我没有错误')
except Exception as msg:
print(msg)
else:
print('当try里面的代码,没有出现异常的情况下执行该代码')
try……exception……finally:
int('ffff')
except Exception as msg:
print(msg)
finally:
print('不管怎样,都会执行')
print('一般在这里释放文件的资源、数据库连接资源等等')
自定义异常
# 自定义异常要直接或者间接继承Error或Exception
class TooLongException(Exception):
def __init__(self,leng):
'''
:param leng:长度
'''
self.len=leng
pass
def __str__(self):
return '您输入的数据长度是'+str(self.len)+'已经超过长度了'
pass
def nameTest():
name=input('请输入姓名……')
if len(name)>5:
# 使用raise关键字抛出异常
raise TooLongException(len(name))
else:
print(name)
pass
nameTest()
捕获自定义异常:
def nameTest():
name=input('请输入姓名……')
try:
if len(name)>5:
# 使用raise关键字抛出异常
raise TooLongException(len(name))
else:
print(name)
pass
except TooLongException as msg:
print(msg)
finally:
print('执行结束')
nameTest()
文件操作一般步骤:
文件打开模式:
r r+ 只读 适用于普通读取场景
rb rb+ 适用于 文件 图片 视频 音频 这样的文件读取
w wb w+ 每次都会创建文件,二进制读写的时候要注意编码问题,默认情况下写入文件的编码是gbk
a ab a+ 在原有的文件基础上【文件指针的末尾】去追加
写入数据:
# # 打开文件,返回一个文件对象
# # 默认编码是gbk(中文编码),最好的习惯是,我们打开一个文件的时候指定编码格式
# fobj=open('./Test.txt','w',encoding='utf-8')
#
# # 读/写操作
# # w模式下,如果打开的路径没有对应文件,则会创建一个新文件;
# # 如果打开的文件存在,添加的内容会覆盖掉原有的内容
# fobj.write('这是添加到文件中的内容')
# fobj.write('这是第二次添加')
#
# # 保存并关闭文件
# fobj.close()
# #以二进制的形式写数据
# fobj=open('./Test.txt','wb')
# fobj.write('这是二进制形式添加数据'.encode('utf-8'))
# fobj.close()
# 追加数据
# fobj=open('./Test.txt','a',encoding='utf-8')
# fobj.write('\n还添加了数据')
# fobj.close()
#以二进制的形式追加数据
fobj=open('./Test.txt','ab')
fobj.write('\n二进制形式追加数据'.encode('utf-8'))
fobj.close()
读数据
# 读取数据
# f = open('./Test.txt', 'r')
# print(f.read()) # 读取所有的数据
# print(f.read(10)) # 读取10个字符(包括换行符)
# print(f.read()) # 第二次读取将从第一次读取的位置继续读取
# print(f.readline()) # 读取一行
# print(f.readline()) # 从第一次读取的位置继续读取一行
# print(f.readlines()[0]) # 读取所有行,打印第一行
# 二进制读取
f = open('./Test.txt', 'rb')
cb=f.read() # 二进制数据
print(cb.decode('gbk'))
f.close()
with上下问问管理:
with语句,不管在处理文件过程中是否发生异常,都能保证with语句执行完毕后已经关闭打开的文件句柄。
def main():
with open('Test.txt','r') as f:
print(f.read())
main()
文件操作实例:
# def copyFile():
# # 接受用户输入的文件名
# oldFile=input('请输入要备份的文件名:')
# fileList=oldFile.split('.')
# # 构造新的文件名.备份的后缀
# newFile=fileList[0]+'_备份.'+fileList[1];
# with open(oldFile,'r') as of: # 打开需要备份的文件
# with open(newFile,'w') as nf: # 以写的模式打开新文件,不存在则创建
# nf.write(of.read()) # 将需要备份文件的内容写入新文件
# print('文件已完成备份')
# pass
# copyFile()
# 如果文件很大,一次读出文件的所有内容会很占内存
# 优化:限制每次读取内容的数量
def copyFile():
# 接受用户输入的文件名
oldFile = input('请输入要备份的文件名:')
fileList = oldFile.split('.')
# 构造新的文件名.备份的后缀
newFile = fileList[0] + '_备份.' + fileList[1];
try:
with open(oldFile, 'r') as oldf, open(newFile, 'a') as newf:
while True:
# 每次读取1024个字符
# 每次从上次读取结束的位置开始读取
content = oldf.read(1024)
newf.write(content)
# 当读取字符数小于1024时,说明已经读取完毕
if len(content) < 1024:
print('文件已完成备份')
break
except Exception as msg:
print(msg)
pass
copyFile()
文件定位:指当前文件指针读取到的位置(光标位置)
tell():获取当前文件指针的位置
truncate() :用于截断文件,如果指定了可选参数 size,则表示截断文件为 size 个字符。 如果没有指定 size,则从当前位置起截断;截断之后 size 后面的所有字符被删除。
seek():在文件操作过程中定位到其他位置。seek(offset,from),offset表示单位字节偏移量,负数是往回偏移,正数是往后偏移;from位置:0表示文件开头,1表示当前位置,2表示文件末尾。
# with open('./Test.txt', 'r') as f:
# content = f.read(3) # 读取3个字符
# print(content)
# cur = f.tell() # 获取当前光标所在的位置
# print(cur) # 6 (每个中文占两个字符,每个英文占一个字符)
#
# content = f.read(3)
# print(content)
# cur = f.tell() # 获取当前光标所在的位置
# print(cur) # 12
# truncate()
# fobj=open('Test.txt','r')
# print(fobj.read())
# fobj.close()
# print('----------截取之后---------------')
#
# fobj=open('Test.txt','r+',errors='ignore')
# fobj.truncate(16)
# print(fobj.read())
# fobj.close()
# seek可以控制光标所在的位置
# 注意:用'r'的模式打开文件,由于在文本文件中,如果没有使用二进制的选项打开文件,
# 移动的指针只允许从文件的开头计算相对位置,从当前位置或尾部计算会引发异常
with open('Test_备份.txt', 'rb') as f:
f.seek(4,0) # 光标从开始像后移动4个字符
data = f.read(2)
print(data.decode('gbk'))
f.seek(-2, 1) # 相当于光标有设置到了0的位置
print(f.read(4).decode('gbk'))
f.seek(-6, 2) # 表示光标从最后向前移6个字符(每个中文占两个字符)
print(f.read(4).decode('gbk'))
pass
导入:import 模块名 例如:import time 在该python文件中导入在时间模块
调用: 模块名.函数名 这样调用可以防止不同模块中有同名方法导致报错
当import导入一个模块时,会完成以下步骤:
搜索路径:
第三方模块的安装位置:在Python安装目录下的lib/site-packages/目录下
使用from ... import ...导入模块
调用时直接使用函数名.
当from ... import ...导入时,会完成以下步骤:
导入模块并取别名: import 模块名 as 别名 之后通过别名指向模块的名称空间,通过别名调用函数。
操作命令:
Python OS 文件/目录方法 | 菜鸟教程 (runoob.com)
常用方法:
os.remame(需要修改的文件名,新的文件名)
os.remove(待删除的文件名):待删除的文件必须存在
os.mkdir(文件夹名称):不允许创建多级目录
os.mkdirs(路径):创建多级目录
os.rmdir(文件夹名称):待删除的文件夹必须存在且只能删除空目录
多级删除非空目录,需要使用shutil模块: shutil.retree(路径)
os.getcwd():获取当前目录
os.path:获取当前路径
os.path.join(os.getcwd(),目录2,目录3,...):拼接路径
os.listdir(路径):获取路径下的目录、文件列表
os.scandir(路径):返回一个对象,需要通过迭代打印,最好结合with使用,通过上下文管理器在迭代遍历完成后自动释放资源
os.path.isfile(os.path.join(基本路径,当前文件名)):判断是否是一个文件
os.path.isdir():判断是否是路径
模块制作:
Python文件都可以作为一个模块,模块的名字就是文件的名字。
作用:使我们有逻辑的去组织我们的Python代码,以库的形式取封装功能,方便开发者调用;可以定义函数 类 不变量,也能包含可执行的代码;
注意:不同的模块可以定义相同的变量名,但是每个模块中的变量名作用域只是在本模块中。
模块分类:内置模块 自定义模块 第三方模块
模块中的__name__和__all__:
__name__魔术变量的作用:用于判断模块的功能是自己执行(__name__==__main__)还是被别的文件调用(__name__==该模块名)
__all__=['方法1','方法2',......]魔术变量作用:指定了其他模块通过:form XXX import * 可引用的方法,如果其他模块使用了该模块中未在__all__中声明的方法,会报错:NameError: name 'XXX' is not defined (其他导入方式可以导入并使用未在__all__中声明的方法)
模块发布:
安装模块:
学习视频:求知讲堂python+人工智能 99天完整版 学完可就业_哔哩哔哩_bilibili