python基础-函数、面对对象、文件、异常
一、函数
1.1函数
python允许我们将常用的代码以固定的格式封装(包装)成一个独立的模块,只要知道这个模块的名字就可以重复使用它,这个模块就叫做函数(Function)。
1.2函数的定义和使用
此格式中,各部分参数的含义如下:
函数名:其实就是一个符合 Python 语法的标识符,但不建议读者使用 a、b、c 这类简单的标识符作为函数名,函数名最好能够体现出该函数的功能(如上面的 my_len,即表示我们自定义的 len() 函数)。
形参列表:设置该函数可以接收多少个参数,多个参数之间用逗号( , )分隔。
[return [返回值] ]:整体作为函数的可选参参数,用于设置该函数的返回值。也可以没有返回值,不写返回值,会有一个默认的返回值None,是否需要根据实际情况而定。return后面所有内容都不执行。
其中,函数名即指的是要调用的函数的名称;形参值指的是当初创建函数时要求传入的各个形参的值。如果该函数有返回值,我们可以通过一个变量来接收该值,当然也可以不接受。
需要注意的是,创建函数有多少个形参,那么调用时就需要传入多少个值,且顺序必须和创建函数时一致。即便该函数没有参数,函数名后的小括号也不能省略。
二、面对对象
2.1概述
对于面向过程的思想:需要实现一个功能的时候,看重的是开发的步骡和过程,每一个步蒸都需要自己亲力亲为,需要白己编写代码自己来做。
对于面向对象的思想:当需要实现一个功能的时候,看重的并不是过程和步骤,而是关心谁帮我做这件事。
面向对象的三大特征有:封结性,继承性.多志性。
2.2类、创建对象、属性和方法
1.在类内部获取属性和实例方法,通过self获取;
2.在类外部获取属性和实例方法,通过对象名获取。
3.如果一个类有多个对象,每个对象的属性是各自保存的,都有各自独立的地址;
4.但是实例方法是所有对象共享的,只占用一份内存空间。类会通过self来判断是哪个对象调用了实例方法。
init():实例化的时候需要一些自定义的属性,可以使用init()方法
2.3常用方法
__str__():将__str__()返回的内容以字符串形式输出
__str__()方法触发方式:
1、使用print()函数触发:触发时,会自动寻找实例对象的方法,若没有则直接按照默认内容输出,有则输出__str__方法的返回值。
2、使用str()函数触发:如上述代码所示,使用str()触发时,worlds类型是str,是一个字符串,打印输出的是一个字符串words。
print(zhang)
2.4 对象的继承
在程序中,继承描述的是多个类之间的所属关系。
如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。
2.4.1 单继承:子类只继承一个父类
子类在继承的时候,在定义类时,小括号()中为父类的名字。
父类的属性、方法,会被继承给子类。
2.4.2 多继承:新建的类可以支持一个或多个父类
多继承可以继承多个父类,也继承了所有父类的属性和方法
当继承了两个或两个以上的类的时候,如果继承的方法或属性有重名,选择继承的第一个。不重名的不受影响。
子类的魔法属性__mro__决定了属性和方法的查找顺序。
2.4.3子类重写父类属性/方法
如果子类和父类的方法名和属性名相同,则默认使用子类的。并称为子类重写父类的同名方法和属性。
2.4.5子类调用父类的同名属性和方法
当存在继承关系的时候,有时候需要在子类中调用父类的方法,此时最简单的方法是把对象调用转换成类调用,需要注意的是这时self参数需要显式传递。
无论何时何地,self都表示是子类的对象。在调用父类方法时,通过传递self参数,来控制方法和属性的访问修改。
但是这种方式在多层继承中就会有问题(下文super()中会提到),基类Base的构造函数被调用了多次次。这样做还有一些缺点,比如说如果修改了父类名称,那么在子类中会涉及多处修改,在多继承时就需要重复写多次,显得累赘。
2 .4.6 多层继承
允许多层继承
2.4.7 私有权限
私有权限:在属性名和方法名 前面 加上两个下划线 __
Python中没有像C++中 public 和 private, protected 这些关键字来区别公有属性和私有属性。Python是以属性命名方式来区分,如果在属性和方法名前面加了2个下划线'__',则表明该属性和方法是私有权限,否则为公有权限。
类的私有属性 和 私有方法,都不能通过对象直接访问,但是可以在本类内部访问;
类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问;
私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。
2.4.8通过super()来调用父类中的方法
默认情况下,python多继承super()方法只会调用第一个父类的方法(后面多继承需要类名.方法名(self))。
在super机制里可以保证公共父类仅被执行一次。
使用3.4.5中的方法,就会出现问题,先看看下面的例子:
class Base(object):
def __init__(self):
print("enter Base")
print("leave Base")
class A(Base):
def __init__(self):
print("enter A")
Base.__init__(self) #调用父类的构造函数进行初始化
print("leave A")
class B(Base):
def __init__(self):
print("enter B")
Base.__init__(self) #调用父类的构造函数进行初始化
print("leave B")
class C(A,B):
def __init__(self):
print("enter C")
A.__init__(self) #调用父类A的构造函数进行初始化
B.__init__(self) #调用父类B的构造函数进行初始化
print("leave C")
c=C()
运行结果:
enter C
enter A
enter Base
leave Base
leave A
enter B
enter Base
leave Base
leave B
leave C
从上面的运行结果可以看出,基类Base的构造函数被调用了两次,这是有问题的,正常的应该是:A的构造函数调用一次,B的构造函数调用一次,基类Base的构造函数调用一次。
接下来使用super()进行调用:
class Base(object): def __init__(self): print("enter Base") print("leave Base") class A(Base): def __init__(self): print("enter A") super(A,self).__init__() print("leave A") class B(Base): def __init__(self): print("enter B") super(B,self).__init__() print("leave B") class C(A,B): def __init__(self): print("enter C") super(C,self).__init__() print("leave C") c=C()
运行结果:
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
可见,父类多次被调用时只执行一次, 优化了执行逻辑。
具体原因可以看看张同学软件开发写的:彻底搞懂python super函数的作用
三、文件
3.1文件
使用文件的目的:保存数据存放在磁盘,把一些存储存放起来,可以让程序下一次执行的时候直接使用,而不必重新制作一份,省时省力
3.2文件的打开与关闭
3.3文件的读写
# read() 读文件 # 把硬盘里的文件加载到内存中 f = open('test.txt', 'r') # print(f.read()) 读取文件内所有内容 print(f.read(5)) # 读取5个 print(f.read()) # 读取文件剩余内容 f.close() # 当文件足够大的时候,内存不够加载整个文件 # 需要一部分一部分加载 f = open('test.txt', 'r') print(f.readline()) # 读取一行数据 print(f.readlines()) # 读取所有行 f.close() # 读取汉字时会乱码,需要设置编码格式 f = open('test.txt', 'r', encoding="utf-8") print(f.readlines()) # 读取所有行 f.close() # 写数据 # w 如果文件存在,则将其覆盖 f = open('test.txt', 'w') f.write('hello word, I am zhang') f.close()
3.4文件、文件夹的相关操作
# OS中的rename(需要修改的文件名,新的文件名)可以完成对文件的重命名操作 import os os.rename("test-复件.txt", "test1.txt") # OS模块中的remove(待删除的文件名)可以完成对文件的删除操作 os.remove("test1.txt") # OS模块中的mkdir(文件夹名)可以创建新的文件夹 os.mkdir("a") # 获取当前目录 os.getcwd() # 改变默认目录 os.chdir("../") # 获取目录列表(目录中的所有文件) print(os.listdir("./")) # 删除文件夹 os.rmdir("./a")
3.5 应用
# 文件的备份 # 复制文件 test.txt 文件 到test-复件.txt # 1.获取源文件的名字(包括路径) filename = input("请输入要备份文件的名称:") # 2.打开原文件 oldFile = open(filename, "rb") # 3.获取备份文件的名字 备份文件名字 = 源文件名字 + ”-复件“ + 后缀名 fileFlagNum = filename.rfind(".")
# 从右往左找找到的必是后缀名(从左往右可能会遇到text.text.txt这种情况) fileFlag = filename[fileFlagNum:] newFileName = filename[:fileFlagNum]+"-复件"+fileFlag# 4.写入备份文件 newfile = open(newFileName,"wb") for linecountent in oldFile.readlines(): newfile.write(linecountent) # 5.关闭文件释放资源 oldFile.close() newfile.close()
#批量在文件名前加前缀 import os folderName = './aa/' # 1.获取指定路径的所有文件名宁 dirlist = os.listdir(folderName) # 2.遍历输出所在文件名字 for name in dirlist: newName = '[猫熊出品]-'+ name os. rename ( folderName+name, folderName+newName )
四、异常处理
4.1 异常
当Python检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示, 这就是所谓的"异常”
4.2 捕获异常
可能产生的异常的代码,放在try中。如果产生异常,处理的方法放在except中。
此处as的作用可以看后文,4.4注。
4.3异常的传递
通过嵌套,实现异常向外传递。如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递。
如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推......如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样。
如图,test1函数内部产生了异常,异常在test1中没有处理,于是此异常被传递到test3函数完成异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行。
4.4 抛出自定义的异常
可以用raise语句来引发一个异常。异常/错误对象必须有一个名字,且它们应是Error或Exception类的子类。
class ShortInputException(Exception): '''自定义的异常类''' def __init__(self, length, atleast): super().__init__() self.length = length self.atleast = atleast def __str__(self): # 使用as查看异常信息的时候,print不会打印任何内容,需要添加一个__str__()使其能够打印出想要的信息 return 'ShortInputException: 输入的长度是 %d,长度至少应是 %d' % (self.length, self.atleast) def main(): try: s = input('请输入 --> ') if len(s) < 3: # raise引发一个你定义的异常 raise ShortInputException(len(s), 3) except ShortInputException as result: # x这个变量被绑定到了错误的实例 print(result) else: print('没有异常发生.') main()
注:as声明了一个将保存exception对象的变量。如果说except Exception as e
,那么e
将是Exception
类型的对象。
五、模块和包
5.1 模块
有过C语言编程经验的朋友都知道在C语言中如果要引用sgrt函敬 ,必须用语句#include <math.h> 引math.h这个头文件,否则是无法正常进行调用的。
那么在Python中,如果要引用一些其他的函数,该怎么处理呢?
在Python中有一个概念叫做模块(module) ,模块是在函数和类的基础上,将一系列相关代码组织到一起的集合体。在 Python 中,一个模块就是一个扩展名为 .py 的源程序文件。这个和C语言中的头文件以及Java中的包很类似,比如在Python中要调用sqrt用数,必须用import关键字引入math这个模块,下面就来了解一下Python中的模块。说的通俗点:模块就好比是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块
5.2 模块制作
5.3模块中的__all__
如果想要以from 自定义包名 import *,需要在包中的__init__.py文件中使用__all__
建议使用精准导入,多个可以使用逗号隔开。
重名可以使用as起个别名
5.4包