Python学习

 Python是一种面向对象解释性计算机程序设计语言.

目录

变量和数据类型

Python基本运算符

Python的输入与输出

判断语句与循环控制

字符串操作

列表及常用方法

元组

字典

 公用方法

函数

全局变量和局部变量

 Python内置函数

面向对象(oop:object oriented programming)

异常处理

文件操作

导入模块

os模块操作文件

模块制作、发布、安装


Python的缺点:

  1. 运行速度慢:代码执行时需要一行一行翻译成CPU能理解的计器码.
  2. 代码不能加密:由于python是解释型语言,发布的程序时,实际发布的是源代码.
  3. 强制的缩进:python有非常严格的缩进语法,只要缩进错误,会导致程序立马崩溃.
  4. GIL全局解释锁:在任意时刻,只有一个线程在解释器中运行.对python虚拟机的访问由全局解释锁(GIL)来控制,并能保证同一时刻只有一个线程在运行.遇到I/O阻塞时会释放掉GIL所以Python的多线程并不是真正的多线程,而是CPU执行速度非常快,让人感觉不到GIL的存在.

变量和数据类型

变量相当于一个盒子,里面可以装各种东西,变量的概念与初中代数方程变量是一致的.在写程序的时候,变量不仅仅可以是数字,还可以是其他任意类型.

变量+逻辑-->python解释器-->软件的功能

变量=存储的数据

顾名思义:变量是一段有名字的连续存储的空间,我们可以通过定义变量来申请并命名存储空间,并通过变量名来使用这段存储空间,在程序中用于临时存放数据的场所.

定义变量: 变量名=值

变量可以多次赋值,在程序执行的过程中,值可以改变.

Python基本数据类型:

  1. 数字(num):int,long(python3取消),float,complex(复数),bool(True,False)
  2. 字符串(str----'')
  3. 字典(dict----{})
  4. 元组(Tuple----())
  5. 列表(list----[])

Python提供了type方法查看变量的类型,使用方式:type(变量名)

命名规则:

  1. 变量必须以字母或下划线开头;
  2. 其他字符可以是字母,数字,下划线;
  3. 变量区分大小写;
  4. Python关键字不能用作变量名;

命名规范:

  1. 见名知意
  2. 小驼峰命名法,如userName
  3. 大驼峰命名法,如UserName
  4. 下划线命名法,如user_name

Python基本运算符

算术运算符:

  • +加法
  • -减法
  • *乘法
  • **指数:左边的数是底数,右边是指数,如2**3=8;
  • %取余:x%y表示x除以y的余数
  • /除法:x/y结果包含小数点后面的数
  • //地板除:x//y结果是忽略小数点后面的小数位,只保留整数位

比较运算符:

  • == 等于
  • !=  不等于
  • >  大于
  • < 小于
  • >=  大于或等于
  • <=  小于或等于

逻辑运算符:

  • and : x and y表示当x,y同为真,结果为真,如果一个为假,则结果为假;
  • o r: x or y表示当x,y同为假,结果为假,如果一个为真,则结果为真;
  • not : not x 表示取反,如果x为真,则结果为假,如果x为假,则结果为真;

优先级: ()->not->and->or

优先级高时,先从优先级高的部分开始计算,优先级相同时,从左往右计算.

赋值运算符:

  • =
  • += 例如:c+=a等效于 c=c+a;
  • -=
  • *=
  • /=
  • %=
  • **=
  • //=

Python的输入与输出

输出:使用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

Python学习_第1张图片

 使用.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)))

判断语句与循环控制

流程是指计算机执行代码的顺序;流程控制是对计算机代码的执行顺序进行有效的管理。只有流程控制才能实现在开发当中的业务逻辑。

流程控制的分类:

  • 顺序流程:是代码自上而下的执行结构,是Python默认的流程。
  • 选择流程/分支流程:根据在某一步的判断,有选择的去执行相应的逻辑的一种结构。
    1. 单分支:if ……
    2. 双分支:if ……else……
    3. 多分支:if……elif……elif……else……

              条件表达式:比较运算符/逻辑运算符/复合的运算符  

  • 循环流程:在满足一定的条件下,一致重复的去执行某段代码的逻辑。

                while 条件表达式:

                        一条条的Python代码

                        一条条的Python代码

                         ……

                for  ...  in  可迭代的对象:

                        一条条的Python代码

                        一条条的Python代码

                         ……

循环的语法特点:

  1. 有初始值
  2. 条件表达式
  3. 变量【循环体内计数变量】的自增或自减,否则会造成死循环

使用条件:循环的次数不确定,依靠循环条件来结束。

使用目的:为了将相似或者相同的代码操作变得更加简洁,使得代码可以重复利用。

range()函数可以生成一个数据集合列表

range(起始,结束,步长) 步长不能为0,数据范围是 :【起始,结束)

 break与continue关键字:

break:退出循环;

continue:跳过本次循环。

while适用于未知的循环次数;for使用于已知的循环次数【可迭代对象遍历】

for----else----的使用

Python学习_第2张图片

Python学习_第3张图片

从以上两个图中的打印结果显示,当顺利遍历结束后便会执行else中的语句,当for循环被break退出时,则不会执行else中的语句。使用场景:需要遍历查找某个值,当找到值时退出循环,没有找到时则打印提示消息。

 while----else----的使用:

Python学习_第4张图片

Python学习_第5张图片

 while---else---执行结果与for---else---相似。

字符串操作

Python中的序列:是一组按顺序排列的值【数据集合】。

Python中的三种内置的序列类型:字符串、列表、元组

优点:可以支持索引和切片的操作

特征:第一个正索引为0,指向的是左端,第一个索引为负数的时候,指向的是右端

切片:是指截取字符串中的一段内容。用法:[起始下标,结束下标,步长]  切片截取的内容不包括结束下标对应的数据,步长指的是隔几个下标获取一个字符。

字符串常用方法:

Python学习_第6张图片

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循环可将列表中的元素一个一个取出,取完后退出循环。

Python学习_第7张图片

# 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))  # 获取指定元素的索引值,第二个参数是查找起始位置,第三个参数是查找长度

元组

元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,元组也是通过下标进行访问。

元组创建:在括号中添加元素,并使用逗号隔开。

方法:

  1. count(),统计元素在元组中出现的次数;
  2. index(),查找指定元素在元组中的下标索引。
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方法,还可以设置默认值。

特点

  1. 不是序列类型,没有下标的概念,是一个无序的键值对集合,是内置的高级数据类型;
  2. 用{}来表示字典对象,每个键值对用逗号分隔;
  3. 字典的键不能重复,值可以重复;
  4. 字典的键只能是可不变类型,如数字,字符串,元组。

字典中的常用方法:

Python学习_第8张图片

# 创建字典
# 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]))

 公用方法

Python学习_第9张图片

# 公有方法 +  *  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:说明函数返回的内容
    '''
    代码块

参数:函数为了实现某项功能,进而得到实现功能所需要的数据,参数是为了得到外部数据的。

  1. 缺省参数:在调用函数时如果没有传参数,会使用定义函数时给的缺省值。缺省参数必须在参数列表的最后面,否则会报错。
  2. 不定长参数:一个函数有时会处理比当初声明的参数要多,这就是不定长参数。定义函数是不用声明参数名,加了星号(*)的变量args会存放所有未命名的变量参数,args为元组,而加**的变量kwargs会存放命名参数,为关键字可选参数,即形如key=value的参数,kwargs为字典。
  3. 引用传参:Python中函数参数是引用传递(不是值传递)。对于不可变类型,因变量不能修改,所以运算不会影响变量自身;对于可变类型来说,函数体中的运算有可能会更改传入的参数变量。
# 必选参数
# 形式参数:只是意义上的一种参数,在定义的时候是不占内存地址的
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))

函数的四种基本类型

  1. 无参数,无返回值,一般用于提示信息打印
  2. 无参数,有返回值,多用于数据采集中
  3. 有参数,无返回值,多用于设置某些不需要返回值的参数设置
  4. 有参数,有返回值,一般是计算型的,需要参数,最终也要返回结果

在Python中,值是靠引用来传递的,可以用id()查看一个对象的引用是否相同,id是保存在内存中的内存地址的标识。

匿名函数:使用lambda关键字创建匿名函数,这个函数没有名字,不用def关键字创建的标准函数。

特点:

  1. 使用lambda关键字创建函数
  2. 没有名字的函数
  3. 匿名函数冒号后面表达式有且只有一个
  4. 匿名函数自带return,return的结果是表达式计算后的结果
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

 Python内置函数

 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方法的区别:

  1. sort是应用在list上的方法,sorted可以对所有可迭代的对象进行排序操作
  2. list的sort方法返回的是对已经存在的列表进行操作,而内建函数sorted方法返回的是一个新的list,而不是在原来的基础上进行的操作

set集合

set(集合)也是Python中的一种数据类型,是一个无序且不重复的元素组合,类似于字典,但是只有key,没有value。

集合操作函数:

add(),clear(),difference()等效于'"-",intersection()等效于'"&",union()等效于'"|",pop(),discard(),update()

创建方式

# 创建集合
# 方式一
set1 = {'1', '2'}
# 方式二
list1 = ['1', '2', '3', '4']
set2 = set(list1)

面向对象(oop:object oriented programming)

面向过程:根据业务逻辑从上到下写代码。

函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可。

面向对象编程:将数据与函数捆绑到一起,进行封装,这样能够更快速的开发程序,减少了重复写代码的过程。

Python学习_第10张图片

 类和对象是面向对象编程中重要的概念。

类是一个模板,模板里面可以包含多个函数,函数里实现一些功能。

对象是根据模板创建的实例,通过实例对象可以执行类中的函数。

类(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)方法:

  • 是初始化方法,实例化对象的时候自动调用,完成一些初始化设置。
  • 是Python自带的内置函数,具有特殊功能的函数,使用双下划线抱起来的【魔术方法】。
  • 可以利用传参机制,可以定义一个功能更加强大且更方便的类。
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

  • self和对象指向一个内存地址,可以认为self就是对象的引用
  • self只有在类中定义,只有在实例方法中才有意义,在调用的时候不必传入相应的参数,而是由解释器自动去指向
  • self的名字是可以更改的,可以定义成其他的名字,只是约定俗成的定义成了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()

魔术方法(用双下划线包起来的方法)

常见的魔术方法:

  • __init__方法:初始化一个类,在创建实例对象为其赋值时使用
  • __str__方法:在将对象传换成字符串str(对象)测试的时候,打印对象的信息。当在类中没有定义该方法时,直接打印对象,】会输出一串类似id的地址信息;当在类中定义了方法后,直接打印对象,会输出方法中返回的内容。
  • __new__方法:创建并返回一个实例对象,调用一次就会得到一个对象。与__init__的区别:__new__函数是类的实例化方法,必须要返回该实例,否则对象创建不成功,至少有一个参数cls是代表要实例化的类,该参数在实例化时由python解释器自动提供;__init__用来做初始化工作,也可以认为是实例的构造方法,接受类的实例,通过self并对其进行构造;__new__函数要先于__init__执行。
  • __class__方法:获得一致对象的类(对象.__class__)
  • __del__方法:对象在程序运行结束后进行对象销毁的时候调用这个方法来释放资源
  • ……
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('程序等待中:')  # 当完成输入后,默认结束程序

Python学习_第11张图片

对于面向对象的继承来说,起始就是将多个类共有的方法提取到父类中,子类仅需继承父类,而不必一一实现每一个方法。

动态添加属性

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()

多态

多态是指定义时的类型和运行时的类型不一样,是同一种行为对于不同的子类【对象】有不同的行为表现,关注的不是对象的类型本身,而是它是如何使用的。

要实现多态,必须遵守两个前提:

  1. 继承:多态必须发生在父类和子类之间
  2. 重写:子类重写父类的方法

多态的用处:

  • 增加程序的灵活性
  • 增加程序的扩展性
# 案例演示
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())  # 注意一般情况下,我们不会通过实例对象去访问静态方法

私有化属性

为了更好的保护属性安全,即不能随意修改,将属性定义为私有属性,添加一个可调用的方法去访问。

语法:两个下划线开头,声明该属性为私有,不能再类的外部被使用或直接访问。

使用私有属性的场景:

  1. 把特定的一个属性隐藏起来,不想让类的外部进行直接调用
  2. 想保护这个属性 不想让属性的值随意被改变
  3. 保护这个属性,不让派生类【子类】去继承
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中单下划线、双下划线、头尾双下划线的说明:

  • _xxx前面加一个下划线,以单下划线开头的表示的是protected类型的变量,即保护类型只能允许其本身与子类进行访问,不能使用form xxx import * 的方式导入。
  • __xxx__前后两个下划线,魔术方法,一般是Python自有,开发者不要创建这类型的方法。
  • xxx_后面单下划线,避免属性名与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__是在一个对象实例化的时候所调用的一个方法
  • __new__至少必须要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供,其他的参数是用来直接传递个__init__方法
  • __new__决定是否要使用该__init__方法,因为__new__可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果__new__没有返回实例对象,则__init__不会被调用
  • 在__new__方法中,不能调用自己的__new__方法,即:return cls.__new__(cls),否则会报错(RecursionError:maximum recursion depth exceeded:超过最大递归深度)

单例模式:是常用的一种程序设计模式,在该模式下能确保系统中某个类只有一个实例对象,并且提供了一个全局的访问点,例如计算机中的回收站、资源管理器、网络计数器、权限验证模块,数据库连接池等。

# 创建一个单例对象,基于__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()

Python学习_第12张图片

 捕获自定义异常:

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()

Python学习_第13张图片

文件操作

文件操作一般步骤:

  • 打开文件:open('文件名称','打开模式')[名称是一个完整的路径],返回一个文件对象
  • 读/写文件:
    • 文件对象.write('要写入的数据');
    • 文件对象.read(num) [num表示要读取的字符数量,默认全部读取];文件对象.readlines() 一次性读取所有内容,返回一个列表,每一行内容作为一个元素
  •  保存文件:文件对象.close() 保存并关闭文件
  • 关闭文件:

文件打开模式:

Python学习_第14张图片

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导入一个模块时,会完成以下步骤:

  1. 打开模块文件
  2. 执行模块对应的文件,将执行过程中产生的名字都丢到模块的名称空间
  3. 在程序中会有一个模块的名称指向模块的名称空间去

搜索路径:

  1. 当前目录
  2. 如果当前目录没有,到环境变量中搜索,可以使用sys模块中的path查看所有的路径
  3. 如果都找不到,搜索默认路径,linux系统,默认路径一般为/usr/local/lib/python (在命令窗口使用 where python 可以获得Python的地址)

第三方模块的安装位置:在Python安装目录下的lib/site-packages/目录下

使用from ... import ...导入模块

  • from 模块 import 函数名 导入模块下的指定函数
  • 使用from导入,如果函数名相同,后面导入的会覆盖前面导入的
  • 把模块中的所有函数一次性全部导入:from 模块名 import *
  • 从模块中选择性导入多个函数:form 模块名 import 函数1,函数2

调用时直接使用函数名.

当from ... import ...导入时,会完成以下步骤:

  1. 以模块为准,创建一个模块的名称空间
  2. 执行模块对应的文件,将执行过程中产生的名字都丢到模块的名称空间
  3. 在当前执行文件的名称空间中,该名字直接指向模块的某个名字,意味着可以不用加任何的前缀,可以直接使用

导入模块并取别名: import 模块名 as 别名  之后通过别名指向模块的名称空间,通过别名调用函数。

os模块操作文件

操作命令: 

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__中声明的方法)

 模块发布:

  1. 将写好的模块放在一个目录下(目录名可以和模块一致)
  2. 在该目录下创建setup.py文件,并写入以下代码Python学习_第15张图片
  3. 创建(构建)模块:python setup.py build (通过终端进入当前目录执行该代码),执行成功后会创建一个build目录
  4. 生成压缩包:python setup.py sdist
  5. 完成压缩后会生成dist目录,把目录下的压缩包发布后,别人就可以使用了

安装模块:

  1. 获取生成的模块压缩包并解压
  2. 进入解压后的模块文件,终端进入该文件目录,执行:python setup.py install (也可以不用解压,直接在终端目标目录运行 pip install 模块压缩包)
  3. 查看是否安装成功:在python的安装目录下的site-packages目录下查看是否有模块文件

学习视频:求知讲堂python+人工智能 99天完整版 学完可就业_哔哩哔哩_bilibili

你可能感兴趣的:(Python,python,开发语言,后端)