python面向对象目录
一、类和对象
类和对象的关系:⽤类去创建⼀个对象,类是对⼀系列具有相同特征和⾏为的事物的统称,是⼀个抽象的概念,不是真实存在的事物,对象是类创建出来的真实存在的事物
1. 定义类
- 类名要满⾜标识符命名规则,同时遵循⼤驼峰命名习惯
- 语法
class 类名():
代码
# 例:定义类
class A():
def test(self):
print('hello world')
1、理解self
- self指的是调⽤该函数的对象,打印对象和self得到的结果是⼀致的,都是当前对象的内存中存储地址
class TestClass():
def test1(self):
print('hello world')
print(self)
testclass= TestClass()
print(testclass)
testclass.test1()
# <__main__.Washer object at 0x000001C1820D1850>
# hello world
# <__main__.Washer object at 0x000001C1820D1850>
2. 创建对象
- 语法:
对象名 = 类名()
# 例:创建对象
class A():
def test(self):
print('hello world')
a = A()
2、添加和获取对象属性
-
类外⾯添加和获取对象属性,语法:
对象名.属性名 = 值
-
类外面获取对象属性,语法:
对象名.属性名
-
类⾥⾯获取对象属性,语法:
self.属性名
class TestClass():
def test1(self):
print(f'hello world {self.attribute1}')
testclass= TestClass()
testclass.attribute1 = 100
testclass.test1()
# hello world 100
3. 魔法方法
1、__init__()
- 不带参数的
__init__()
,作⽤:初始化对象
- 在创建⼀个对象时默认被调⽤,不需要⼿动调⽤
- self参数不需要手动传递,python解释器会⾃动把当前的对象引⽤传递过去
class TestClass():
def __init__(self):
self.attribute1 = 100
def test1(self):
print(f'hello world {self.attribute1}')
testclass= TestClass()
testclass.test1()
# hello world 100
- 带参数的
__init__()
,作⽤:对不同的对象设置不同的初始化属性
class TestClass():
def __init__(self,num):
self.attribute1 = num
def test1(self):
print(f'hello world {self.attribute1}')
testclass= TestClass(100)
testclass.test1()
# hello world 100
2、__str__()
- 当使⽤print输出对象的时候,默认打印对象的内存地址;如果类定义了
__str__ ()
方法,那么就会打印出在这个方法中 return的数据
class TestClass():
def __init__(self,num):
self.attribute1 = num
def __str__(self):
return 'hello world'
testclass= TestClass(100)
print(testclass)
# hello world 100
3、__del__()
- 当删除对象时,python解释器也会默认调⽤
__del__()
方法
class TestClass():
def __init__(self,num):
self.attribute1 = num
def __del__(self):
print(f'{self}对象已被删除')
testclass= TestClass(100)
del testclass
# <__main__.TestClass object at 0x000001C1820D1CA0>对象已被删除
4. 类属性和实例属性
(1)类属性
1、设置和访问类属性
- 类属性:类对象所拥有的属性,它被该类的所有实例对象所共有,可以使⽤类对象或实例对象访问
- 优点:类属性为全类所共有,仅占⽤⼀份内存,更加节省内存空间
- 使用场景:记录的某项数据始终保持⼀致时,则定义类属性
class A(object):
num= 10
a1= A()
a2= A()
print(A.num) # 10
print(a1.num) # 10
print(a2.num) # 10
2、修改类属性
- 类属性只能通过类对象修改,不能通过实例对象修改
class A(object):
num = 100
a1 = A()
a2 = A()
# 修改类属性
A.num= 200
print(a1.num ) # 200
print(a2.num ) # 200
# 如果通过实例对象修改类属性,表示的是创建了⼀个实例属性
a1.num= 300
print(a1.num) # 300
print(a2.num) # 200
(2)实例属性
class A(object):
def __init__(self):
self.num = 100
def info(self):
print(self.num)
a = A()
print(a.num) # 5
# print(A.num) # 报错:实例属性不能通过类访问
a.info() # 5
5. 类方法和静态方法
(1)类方法
- 特点:第⼀个参数必须是类对象,⼀般以
cls
作为第⼀个参数,能够通过类对象和实例对象访问 - 使⽤场景:当方法中需要使用类对象(如访问私有类属性等)时,⼀般和类属性配合使用
- 修饰方法:装饰器
@classmethod
class A(object):
__num = 100
@classmethod
def get_num(cls):
return cls.__num
a= A()
re = a.get_num()
print(re) # 100
(2)静态方法
- 特点:既不需要传递类对象也不需要传递实例对象(形参没有
self
/cls
),能够通过类对象和实例对象访问 - 使⽤场景:当方法中既不需要使用实例对象,也不需要使用类对象时,取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
- 修饰方法:装饰器
@staticmethod
class A(object):
@staticmethod
def info():
print('100')
a = A()
a.info() # 100
A.info() # 100
二、面向对象的三大特性
1. 封装
- 封装:将属性和方法书写到类⾥⾯的操作,可以为属性和方法添加私有权限
2. 继承
- 继承指的是多个类之间的所属关系,即子类默认继承⽗类的所有属性和方法,且可以重写⽗类属性和方法
- 在Python中,所有类默认继承object类,object类是顶级类或基类,其他子类叫做派⽣类
# ⽗类 A
class A(object):
def __init__(self):
self.num = 100
def info(self):
print(self.num)
# 子类 B
class B(A):
pass
b = B()
b.info() # 100
(1)单继承
- ⼀个类只继承一个⽗类
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 子类 B
class B(A):
pass
# 3. 创建对象
people = B()
# 4. 对象访问实例属性
print(people.name) # Jack
# 5. 对象调⽤实例方法
people.info() # 姓名:Jack
(2)多继承
- ⼀个类同时继承多个⽗类,默认使⽤第⼀个⽗类的同名属性和方法
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 父类 B
class B(object):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# 3. 子类 C
class C(A,B):
pass
# 4. 创建对象
people = C()
# 5. 对象访问实例属性
print(people.name) # Jack
# 6. 对象调⽤实例方法
people.info() # 姓名:Jack
(3)子类重写父类同名方法和属性
- 子类和父类具有同名属性和方法时,默认使用子类的同名属性和方法
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 父类 B
class B(object):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# 3. 子类 C
class C(A,B):
def __init__(self):
self.name= 'Jerry'
def info(self):
print(f'姓名:{self.name}')
# 4. 创建对象
people = C()
# 5. 对象访问实例属性
print(people.name) # Jerry
# 6. 对象调⽤实例方法
people.info() # 姓名:Jerry
(4)子类调用父类的同名方法和属性
- 为了保证调用到的是父类属性,所以必须在调⽤方法前调⽤父类的初始化
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 父类 B
class B(object):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# 3. 子类 C
class C(A,B):
def __init__(self):
self.name= 'Jerry'
def info(self):
# 为了保证调⽤到的是子类属性,所以也要先调⽤子类的初始化
self.__init__()
print(f'姓名:{self.name}')
# 调⽤⽗类方法
def A_info(self):
A.__init__(self)
A.info(self)
def B_info(self):
B.__init__(self)
B.info(self)
# 4. 创建对象
people = C()
# 5. 对象访问实例属性
print(people.name) # Jerry
# 6. 对象调⽤实例方法
people.info() # 姓名:Jerry
people.A_info() # 姓名:Jack
people.B_info() # 姓名:Tom
people.info() # 姓名:Jerry
(5)多层继承
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 父类 B
class B(object):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# 3. 子类 C
class C(A,B):
def __init__(self):
self.name= 'Jerry'
def info(self):
# 为了保证调⽤到的是子类属性,所以必须先调⽤子类的初始化
self.__init__()
print(f'姓名:{self.name}')
# 调⽤⽗类方法,为了保证调⽤到的是⽗类属性,所以必须在调⽤方法前调⽤⽗类的初始化
def A_info(self):
A.__init__(self)
A.info(self)
def B_info(self):
B.__init__(self)
B.info(self)
# 4. 子孙类 D
class D(C):
pass
# 5. 创建对象
people = D()
# 6. 对象访问实例属性
print(people.name) # Jerry
# 7. 对象调⽤实例方法
people.info() # 姓名:Jerry
people.A_info() # 姓名:Jack
people.B_info() # 姓名:Tom
(6)super()调⽤⽗类方法
- 使⽤
super()
可以⾃动查找⽗类,⽐较适合单继承使⽤
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 子类 B
class B(A):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# ⼀次性调⽤⽗类的同名属性和方法
super().__init__()
super().info()
# 3. 子孙类 C
class C(B):
def __init__(self):
self.name= 'Jerry'
def info(self):
self.__init__()
print(f'姓名:{self.name}')
def A_info(self):
A.__init__(self)
A.info(self)
def B_info(self):
B.__init__(self)
B.info(self)
# ⼀次性调⽤⽗类的同名属性和方法
def A_B_info(self):
super().__init__()
super().info()
# 4. 创建对象
people = C()
# 5. 对象访问实例属性
print(people.name)
# Jerry
# 6. 对象调⽤实例方法
people.info()
# 姓名:Jerry
people.A_info()
# 姓名:Jack
people.B_info()
# 姓名:Tom
# 姓名:Jack
people.A_B_info()
# 姓名:Tom
# 姓名:Jack
(7)私有权限
1、定义私有属性和方法
- 可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类(只能在类⾥⾯访问和修改)
- 设置私有权限的方法:定义属性名或方法名时在前面加
__
,也就是__属性名
、__方法名
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 父类 B
class B(object):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# 3. 子类 C
class C(A,B):
def __init__(self):
self.name= 'Jerry'
# 定义私有属性
self.__age = 18
# 定义私有方法
def __info(self):
print(self.name)
print(self.__age)
def info(self):
self.__init__()
print(f'姓名:{self.name}')
def A_info(self):
A.__init__(self)
A.info(self)
def B_info(self):
B.__init__(self)
B.info(self)
# 4. 子孙类 D
class D(C):
pass
# 5. 创建子类对象
people = C()
# 6. 对象访问实例属性&方法
print(people.name) # Jerry
people.info() # 姓名:Jerry
# print(people.__age) # 报错
# people.__info() # 报错
# 7. 创建子孙类对象
people = D()
# 8. 对象访问实例属性&方法
print(people.name) # Jerry
people.info() # 姓名:Jerry
# print(people.__age) # 报错
# people.__info() # 报错
2、获取和修改私有属性值
- ⼀般定义函数名get_xx⽤来获取私有属性,定义set_xx⽤来修改私有属性值
# 1. 父类 A
class A(object):
def __init__(self):
self.name= 'Jack'
def info(self):
print(f'姓名:{self.name}')
# 2. 父类 B
class B(object):
def __init__(self):
self.name= 'Tom'
def info(self):
print(f'姓名:{self.name}')
# 3. 子类 C
class C(A,B):
def __init__(self):
self.name= 'Jerry'
self.__age = 18
# 获取私有属性
def get_age(self):
return self.__age
# 修改私有属性
def set_age(self):
self.__age = 20
def __info(self):
print(self.name)
print(self.__age)
def info(self):
self.__init__()
print(f'姓名:{self.name}')
def A_info(self):
A.__init__(self)
A.info(self)
def B_info(self):
B.__init__(self)
B.info(self)
# 4. 子孙类 D
class D(C):
pass
# 5. 创建子类对象
people = C()
# 6. 对象访问实例属性&方法
print(people.get_age()) # 18
people.set_age()
print(people.get_age()) # 20
3. 多态
- 多态是⼀种使⽤对象的⽅式,依赖于继承:⼀个抽象类有多个子类,子类重写⽗类方法,调⽤不同子类对象的相同⽗类方法,可以产⽣不同的执⾏结果
实现步骤:
- 定义⽗类,并提供公共方法
- 定义子类,并重写⽗类方法
- 传递子类对象给调⽤者,可以看到不同子类执⾏效果不同
# 1. 父类
class Dog(object):
def info(self):
print('我是一只狗')
# 2. 子类 1
class Samll_Dog(Dog):
def info(self):
print('我是一只小狗')
# 3. 子类 2
class Big_Dog(Dog):
def info(self):
print('我是一只大狗')
# 4. 应用类
class Dog_Type(object):
def dog_info(self, dog):
dog.info()
small_dog = Samll_Dog()
big_dog = Big_Dog()
dog_type = Dog_Type()
dog_type.dog_info(small_dog) # 我是一只小狗
dog_type.dog_info(big_dog) # 我是一只大狗
三、异常
1. 了解异常
异常:当检测到⼀个错误时,解释器无法继续执行,出现了⼀些错误的提示
2. 捕获异常的语法
- 一般语法
try:
可能发⽣错误的代码
except:
如果出现异常执⾏的代码
- 捕获指定异常,语法
try:
可能发⽣错误的代码
except 异常类型:
如果捕获到该异常类型执⾏的代码
注意:
- 如果尝试执⾏的代码的异常类型和要捕获的异常类型不⼀致,则⽆法捕获异常
- ⼀般try下⽅只放⼀⾏尝试执⾏的代码
- 捕获多个指定异常,语法
try:
可能发⽣错误的代码
except (异常类型1, 异常类型2):
如果出现这些异常执⾏的代码
- 捕获异常描述信息,语法
try:
可能发⽣错误的代码
except (异常类型1, 异常类型2) as result:
print(result)
- 捕获所有异常描述信息,语法
try:
可能发⽣错误的代码
# Exception是所有程序异常类的父类
except Exception as result:
print(result)
- 异常的else:表示的是如果没有异常要执⾏的代码
try:
可能发⽣错误的代码
except Exception as result:
print(result)
else:
print('未发生异常')
- 异常的finally:表示⽆论是否异常都要执⾏的代码
try:
可能发⽣错误的代码
except Exception as result:
print(result)
else:
print('未发生异常')
finally:
print('发生异常')
3. 自定义异常
- 自定义异常语法:
# 1. ⾃定义异常类
class 异常类类名(Exception):
代码
# 设置抛出异常的描述信息
def __str__(self):
return ...
# 2. 抛出异常
raise 异常类名()
# 例:设置输入密码不能小于3位,否则抛出自定义异常
class ShortInputError(Exception):
def __init__(self, length, min_len):
self.length = length
self.min_len = min_len
# 设置抛出异常的描述信息
def __str__(self):
return f'你输⼊的⻓度是{self.length}, 不能少于{self.min_len}个字符'
def main():
try:
con = input('请输⼊密码:')
if len(con) < 3:
raise ShortInputError(len(con), 3)
except Exception as result:
print(result)
else:
print('密码已经输⼊完成')
main()
四、模块和包
1. 模块
模块(Module):是以 .py 结尾的Python文件,能定义函数、类和变量,也能包含可执行的代码
1、导⼊模块
import 模块名1, 模块名2...
from 模块名 import 功能1, 功能2, 功能3...
from 模块名 import *
import 模块名 as 别名
from 模块名 import 功能名 as 别名
2、制作模块
每个Python文件都可以作为⼀个模块,模块的名字就是⽂件的名字(必须符合标识符命名规则)
-
定义模块:新建⼀个Python⽂件,命名为 my_module1.py ,并定义 testA 函数。
-
测试模块:在实际开发中,为了让模块能够在项目中达到想要的效果,一般会在 .py 文件中添加⼀些测试代码
让测试代码在模块被导入的时候不被执行
if __name__ == '__main__': 测试代码
- 调⽤模块:参考上面的导入模块
3、模块定位顺序
导入模块时,Python解析器对模块位置的搜索顺序是:
- 当前⽬录
- 如果不在当前⽬录,则搜索在shell变量PYTHONPATH下的每个⽬录
- 如果都找不到,会查看默认路径
模块搜索路径存储在system模块的sys.path变量中(变量⾥包含当前目录,PYTHONPATH和由安装过程决定的默认默认)
注意
- ⾃⼰的⽂件名不要和已有模块名重复,否则导致模块功能⽆法使⽤
- 使⽤
from 模块名 import 功能
的时候,如果功能名字重复,调⽤到的是最后定义或导⼊的功
能
4、__all__
如果⼀个模块⽂件中有 __all__
变量,当使⽤from 模块 import *
导⼊时,只能导入 __all__
列表中的元素
2. 包
包(Package):将有联系的模块组织在⼀起,放到同⼀个⽂件夹下,并且创建⼀个__init__.py ⽂件
1、制作包
PyChram新建包:文件 — 新建 — Python 软件包 — 输⼊包名 — 新建功能模块(有联系的模块)
注意:新建包后,包内部会⾃动创建 __init__.py ⽂件,此文件控制着包的导入行为
2、导入包
方法一:
import 包名.模块名
包名.模块名.⽬标
方法⼆:
from 包名 import *
模块名.目标
注意:必须在 __init__.py ⽂件中添加
__all__ = []
,控制允许导入的模块列表