欢迎来到Introzo百科
Introzo百科
当前位置:网站首页 > 技术 > Python大师之路[11]Python基础知识面向对象

Python大师之路[11]Python基础知识面向对象

日期:2023-10-04 07:39

-->

创建类和对象

面向对象编程是一种编程方法。这种编程方法的实现需要使用“类”和“对象”。因此,面向对象编程实际上就是“类”和“对象”的使用。

类是一个模板。模板可以包含多个函数,函数实现部分功能

对象是基于模板创建的实例。类中的函数可以通过实例对象来执行

class是一个关键字,表示创建对象的类。只需在类名后面添加括号即可

注意:类中函数的第一个参数必须是self(具体参见:类三大特性封装)  

  类中定义的函数称为“方法”

#创建班级
Foo 类:
def Bar(自己):
print("酒吧")
def 你好(自己,名字):
print("我爱%s" %name)
#根据Foo类创建obj对象
obj = Foo()
www.introzo.com() #执行Bar方法
obj.Hello('python') #执行Hello方法

self参数相当于PHP面向对象中的$this,谁调用就指向

面向对象的三大特点

面向对象的三大特性是:封装、继承和多态。

1。包装

封装,顾名思义,就是将内容封装在某个地方,然后在某个地方调用封装的内容。

所以,在使用面向对象的封装特性时,你需要:

  • 将内容封装在某处
  • 从某处调用封装的内容

第一步:将内容封装在某处

Foo 类:
def __init__(self,name,age):##__init__ 被称为构造函数,在基于类创建对象时自动执行
www.introzo.com = 姓名
self.age = 年龄
obj1 = Foo('poe',21)##poe和21分别封装到obj1 self的name和age属性中
print(www.introzo.com,obj1.age)
obj2 = Foo('jet',22)##jet和22分别封装到obj2 self的name和age属性中
print(obj2.名称,obj2.年龄)

self 是一个形式参数。执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1

执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2

所以,内容实际上被封装到了对象obj1和obj2中。每个对象都有name和age属性,这些属性保存在内存中类似下图。

第2步:从某处调用封装的内容

调用封装内容时,有两种情况:

  • 直接通过对象调用
  • 通过自身间接调用

1。通过对象直接调用封装的内容

上图展示了对象obj1和obj2是如何在内存中保存的。封装的内容可以根据保存格式调用:对象.属性名称

Foo 类:
def __init__(self,name,age):##__init__ 被称为构造函数,在基于类创建对象时自动执行
www.introzo.com = 姓名
self.age = 年龄
obj1 = Foo('poe',21)##poe和21分别封装到obj1 self的name和age属性中
print(www.introzo.com,obj1.age)#直接调用obj1对象的name和age属性
obj2 = Foo('jet',22)##jet和22分别封装到obj2 self的name和age属性中
print(www.introzo.com,obj2.age)#直接调用obj2对象的name和age属性

2。通过self间接调用封装的内容

执行类中的方法时,需要通过self间接调用封装的内容

Foo 类:
def __init__(self,name,age):##__init__ 被称为构造函数,在基于类创建对象时自动执行
www.introzo.com = 姓名
self.age = 年龄
详细信息(自己):
print(自己的名字)
打印(自我年龄) obj1 = Foo("poe",21)
obj1.detail()# Python默认会将obj1传递给self参数,即:obj1.detail(obj1),所以此时方法内部self = obj1,即:www.introzo.com is poe;本人年龄21
obj2 = Foo("jet",22)
obj2.detail()# Python默认会将obj1传递给self参数,即:obj1.detail(obj1),所以此时方法内部self = obj1,即:www.introzo.com is jet;本人年龄22岁

综上所述,面向对象的封装,其实就是利用构造方法将内容封装成一个对象,然后直接通过对象或者通过self间接获取封装的内容。

2。传承

继承,面向对象中的继承和现实生活中的继承是一样的,即:子类可以继承父类的内容。

动物类:
def 吃(自己):
print("%s 吃" %www.introzo.com)
def喝酒(自己):
print("%s 饮料" %www.introzo.com) 猫类(动物):
def __init__(self,name):
www.introzo.com = 姓名
self.breed = '猫'
def哭(自己):
打印(“哭”)
狗类(动物):
def __init__(self,name):
www.introzo.com = 姓名
self.breed = '狗'
def哭(自己):
打印(“哭”) c1 = Cat('小猫')
www.introzo.com()
c2 = Cat('大猫')
c2.吃() d1 = Dog('小黑')
d1.吃()

所以,对于面向对象的继承来说,其实就是将多个类共有的方法抽取到父类中。子类只需继承父类即可,无需一一实现各个方法。

注意:除了子类和父类的名称之外,你可能还见过派生类和基类。它们只是与子类和父类的称呼不同。

那么问题又来了,多重继承呢?

  • 是否可以继承多个类
  • 如果多个继承类在每个类中定义了相同的函数,那么会使用哪一个?

1。 Python类可以继承多个类,而Java和C#只能继承一个类

2。如果一个Python类继承了多个类,查找方法的方式如下:

假设G类继承时,C类在前,F类在后,如:G(C,F)

黑色箭头表示继承关系:B类继承A类,C类继承B类,D类继承A类,F类继承D类,G类继承C类,F类

橙色箭头表示搜索顺序。上图中的搜索顺序为:G->C->B->F->D->A

如果A类没有继承关系,那么查找顺序如下:

动物类:
def 吃(自己):
print("%s 吃" %www.introzo.com)
def喝酒(自己):
print("%s饮料" %www.introzo.com)
def piao(自己):
print("动物piao") 班叔:
def piao(自己):
print('飘叔叔')
def du(自己):
打印('杜') class Cat(Uncle,Animal):#继承Uncle类和Animal类
def __init__(self,name):
www.introzo.com = 姓名
self.breed = '猫'
def哭(自己):
打印(“哭”) c1 = Cat('小猫')
c1.piao()
c2 = Cat('大猫')
c2.piao()

上面的Cat类继承了Uncle类和Animal类,两个类都有piao()方法。那么当这个方法被调用时,是按照什么顺序执行的呢?哪个类应该执行 piao() 方法?

1:如果Cat类本身有piao()方法,那么调用piao()方法时,先执行自己类中的piao()方法

2:如果Cat类本身没有piao()方法,像上面的代码,会按照继承的顺序执行,class Cat(Uncle,Animal),两个类先写哪个就执行将首先被执行。类中的piao()方法

3。多态性

Pyhon不支持Java、C#等强类型语言的多态性,但它具有原生多态性,Python提倡“鸭子类型”。

F1级:
通过
S1(F1)级:
def show(自我):
print('www.introzo.com')
S2(F1)级:
def show(自我):
打印(“www.introzo.com”) def Func(obj):
打印(www.introzo.com())
s1_obj = S1()
函数(s1_obj) s2_obj = S2()
函数(s2_​​obj)

扩展名:

  重载:函数名相同但参数个数不同(python不支持)

  重写:在派生类中重新实现基类中的方法

  接口:Python中没有接口这样的东西

类和对象如何存储在内存中?

一个类以及该类中的方法在内存中只有一份,基于该类创建的每个对象都需要存储在内存中,如下图:

如上图所示,基于类创建对象时,对象除了封装name和age的值外,还会存储一个类对象指针,该指针指向到当前对象的类。

通过obj1执行【方法一】时,流程如下:

  1. 根据当前对象中的类对象指针查找类中的方法
  2. 将对象 obj1 作为参数传递给方法的第一个参数 self


执行基类构造方法:

A级:
def __init__(self):
print('一个结构')
B(A)级:
def __init__(self):
print('B结构')
super(B,self).__init__()#推荐使用该方法
#A.__init__(self)#这个方法也可以执行基类的构造方法
对象 = B()

使用反射操作对象成员

Foo 类:
def __init__(self,name):
www.introzo.com = 姓名
def show(自我):
打印('显示') obj = Foo('poe')
#Reflection:班级,只能找到班级成员
#Reflection:对象,既可以找到对象,也可以找到类的成员
print(hasattr(Foo,'show'))
打印(hasattr(obj,'名称'))
##www.introzo.com文件
Foo 类:
def __init__(self,name):
www.introzo.com = 姓名
性别 = '男'
def show(自我):
打印('显示') ##www.introzo.com 文件 #导入模块
m = __import__('commons',fromlist = True)
#查找模块中的类
类名 = getattr(m,'Foo')
#根据类创建对象
obj = 类名("bruce")
#利用对象求name的值
val = getattr(obj,'名称')
打印(值)

类中有普通字段、静态字段、普通方法、静态方法、类方法。在访问这些成员时,您应该首先选择自己的成员来自行访问:

通过类访问的包括:静态字段、静态方法、类方法

通过对象访问的包括:普通字段和普通方法

但请注意:这仅用于代码规范,这四个成员利用对象都是可访问的

班级省份:
#静态字段,保存在类中,内存中只有一个
国家=“中国”
def __init__(self,name):
#公共字段,保存在对象中!有多个对象,有多个字段
www.introzo.com = 姓名
#常用方法,保存在类中
def show(自我):
print('显示')
#静态方法,静态方法中不需要self参数
@静态方法
def xo(arg1,arg2):
返回arg1+arg2
#类方法,类方法不需要self参数,但是必须有cls参数(class)
@classmethod
def xxoo(cls):
打印(“xxoo”,cls) 湖南 = 省份('湖南')
湖南.show()
打印(hunan.xo(3,4))
打印(省.国家)
打印(省.xo(1,2))
Province.xxoo()#调用类方法,cls参数会自动获取当前类的类名。

类别的特点:

班级省份:
def开始(自己):
temp = "%s 是英雄" %www.introzo.com
返回温度
#特征,将方法伪造成字段
@属性
def end(自己):
temp = "%s 是英雄" %www.introzo.com
返回温度 obj = 省份('poe')
print(obj.start())
print(obj.end)#访问属性时,后面不需要加括号,所以不能传递参数。

默认情况下,类的特征不能像普通字段一样在类外部重新赋值。如果需要重新分配特征,则需要使用装饰器:

班级省份:
#静态字段,保存在类中,内存中只有一个
国家=“中国”
def __init__(self,name):
#公共字段,保存在对象中!有多个对象,有多个字段
www.introzo.com = 姓名
#常用方法,保存在类中
def show(自我):
print('显示')
#静态方法,静态方法中不需要self参数
@静态方法
def xo(arg1,arg2):
返回arg1+arg2
#类方法,类方法不需要self参数,但是必须有cls参数(class)
@classmethod
def xxoo(cls):
打印(“xxoo”,cls) def开始(自己):
temp = "%s 是英雄" %www.introzo.com
返回温度
#特征,将方法伪造成字段
@属性
def end(自己):
temp = "%s 是英雄" %www.introzo.com
返回温度
@end.setter
def end(自身,值):
打印(值)
www.introzo.com = 值 obj = 省份('poe')
p = obj.end
打印(页)
#设置属性
obj.end = "布鲁斯"
打印(obj.end)
################################################
Poe是英雄
布鲁斯
布鲁斯是英雄

快速判断成员是由类执行还是由对象执行:

带 self 的对象调用,不带 self 的类调用

成员修饰语

每个班级成员有两种形式:

  • 公共会员,可从任何地方访问
  • 私有成员只能在班级内部访问

私有成员和公共成员定义不同命名私有成员时,前两个字符为下划线。 (特殊成员除外,如:__init__、__call__、__dict__等)

A级:
def __init__(self):
www.introzo.com = '公开'
self.__nick = '私人' obj = A()
print(www.introzo.com)
打印(obj.__nick)
##################################################
公共
追溯(最近一次调用最后一次):
文件“www.introzo.com”,第 11 行,位于
打印(obj.__nick)
AttributeError:“A”对象没有属性“__nick”

如何访问类中的静态成员:两种方法

方法1:在类中添加方法

A级:
def __init__(self):
www.introzo.com = '公开'
self.__nick = '私人' def fetch(自身):
打印(自己.__昵称) obj = A()
obj.fetch()

方法二:使用python特定语法(不推荐此方法)

A级:
def __init__(self):
www.introzo.com = '公开'
self.__nick = '私人' obj = A()
print(obj._A__nick)#A 前面有下划线

班的特别成员

1:__init__:构造方法

构造函数方法在通过类创建对象时自动触发执行。

类Foo: def __init__(self, 名字):
www.introzo.com = 姓名
自我年龄 = 18 obj = Foo('poe') # 自动执行类中的__init__方法

2:__del__:破坏方法

析构函数方法会在内存中释放对象时自动触发执行。

注:这个方法一般不需要定义,因为Python是高级语言,程序员在使用的时候不需要关心内存的分配和释放,因为这个工作是Python来完成的解释器,因此析构函数的调用是在垃圾回收期间由解释器自动触发的。

类Foo: def __del__(自身):
通过

3:__call__方法用于调用实例本身

注意:构造函数方法的执行是由对象的创建触发的,即:object = 类名();而__call__方法的执行是由对象后面的括号触发的,即:object()或class()()

Foo 类:
def __init__(self):
print('init')
# __call__方法用于调用实例本身
def __call__(self,*args,**kwargs):
print('调用')
返回1
# obj = Foo()
# obj()
r = Foo()()
打印(r)
##################################################
初始化
打电话
1

4:__getitem__ , __setitem__ , __delitem__

用于字典等索引操作。以上分别代表获取、设置、删除数据

类Foo: def __getitem__(self,item):
打印(项目)
def __setitem__(自身,键,值):
打印(键,值)
def __delitem__(self,key):
打印(键) obj = Foo()
obj['kk']
obj['aa'] = 123
del obj['kk']
obj['kk']

5:__dict__查询类中的成员和对象中的成员

Foo 类:
def __init__(self):
www.introzo.com = 'poe'
def __call__(自身):
print('调用')
def __getitem__(self,item):
打印(项目)
def __setitem__(自身,键,值):
打印(键,值)
def __delitem__(self,key):
打印(键) obj = Foo() #__init__
打印(obj.__dict__)
打印(Foo.__dict__)

6:__iter__

用于迭代器。列表、字典和元组之所以可以用于 for 循环,是因为 __iter__

是在类型内部定义的。
Foo 类:
def __iter__(self):
产量 1
产量 2
产量 3
obj = Foo()
对于 obj 中的 i:
打印(一)

7:__new__ 和 __metaclass__

阅读以下代码:

类 Foo(对象): def __init__(self):
经过 obj = Foo() # obj 是通过 Foo 类实例化的对象

上面的代码中,obj是通过Foo类实例化的对象。事实上,不仅 obj 是一个对象,Foo 类本身也是一个对象,因为Python 中的一切都是对象

如果按照万物皆对象的理论:obj对象是通过执行Foo类的构造方法创建的,那么Foo类对象也应该是通过执行某个类的构造方法创建的。

print type(obj) # 输出: 表示 obj 对象是由 Foo 类创建的
print type(Foo) # 输出: 表示 Foo 类对象是由 type class 创建的

所以,obj对象是Foo类的实例,而Foo类对象是类型类的实例,即:创建了Foo类对象通过类型类的构造方法。

所以,创建类有两种方法:

a)。正常方式

类 Foo(对象): def func(自身):
print('你好Python')

b).特殊方法(类型类的构造函数)

def func(自身):
打印('你好Python') Foo = type('Foo',(object,),{'func':func})
打印(Foo,类型(Foo))
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类成员

那么问题来了。默认情况下,类是通过类型类的实例化生成的。如何在类型类中创建类?类如何创建对象?

答:类中有一个属性__metaclass__,用于指示谁实例化和创建了该类。因此,我们可以为__metaclass__设置该类型类的派生类来查看类创建的过程。

8:__doc__

  表示类

的描述信息
Foo 类:
"""描述信息,这就是看电影的魔力""" def func(自身):
经过 打印 Foo.__doc__
#输出:类的描述信息

9:__str__

如果类中定义了__str__方法,那么打印对象时,会默认输出该方法的返回值。

类Foo: def __str__(自身):
返回('POE') obj = Foo()
打印(对象)
# 输出:poe

10:__module__ 和 __class__

  __module__表示当前操作对象在哪个模块

  __class__表示当前操作对象的类

# lib/www.introzo.com
C级:
def __init__(self):
www.introzo.com = 'poe'
#www.introzo.com
从 lib.commons 导入 C obj = C()
print(obj.__module__)# 输出lib.commons,即:输出模块
print(obj.__class__)# 输出lib.commons.C,即:输出class

异常处理

1。异常基础

为了增加编程过程中的友好性,当程序出现Bug时,一般不会向用户显示错误信息,而是显示提示页面。通俗地说,就是不允许用户看大黄页! ! !

尝试一下:
通过
除了例外,例如:
经过

需求:将用户输入的两个数字相加

而正确时:
num1 = raw_input('num1:')
num2 = raw_input('num2:')
尝试一下:
num1 = int(num1)
num2 = int(num2)
结果 = num1 + num2
除了例外,e:
print '出现异常,提示信息如下:'
打印 e

2。异常型

Python中有很多种异常类型,每种异常都是专门用来处理某种异常的! ! !

AttributeError 尝试访问对象没有的属性,例如 foo.x,但 foo 没有属性 x
IOError 输入/输出异常;基本上文件打不开
ImportError 无法导入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(子类);代码未正确对齐
IndexError 下标索引超出序列边界。例如,当 x 只有三个元素,但尝试访问 x[5]
KeyError 尝试访问字典中不存在的键
键盘中断 Ctrl+C 被按下
NameError 使用尚未分配对象的变量
SyntaxError Python代码非法,代码无法编译(我个人认为这是语法错误,写错了)
TypeError 传入的对象类型不符合要求
UnboundLocalError 尝试访问尚未设置的局部变量,基本上是因为还有另一个同名的全局变量,
让您认为您正在访问它
ValueError 传入调用者不期望的值,即使值类型正确

常见例外

算术错误
断言错误
属性错误
基本异常
缓冲区错误
字节警告
弃用警告
环境错误
EOF错误
例外
浮点错误
未来警告
发电机退出
导入错误
导入警告
缩进错误
索引错误
IO错误
键盘中断
按键错误
查找错误
内存错误
名称错误
未实现错误
操作系统错误
溢出错误
待定弃用警告
参考错误
运行时错误
运行时警告
标准误差
停止迭代
语法错误
语法警告
系统错误
系统退出
制表符错误
类型错误
UnboundLocalError
Unicode解码错误
UnicodeEncodeError
Unicode错误
Unicode翻译错误
Unicode警告
用户警告
值错误
警告
零除法错误 更多异常

更多异常

dic = ["Jet", 'Jacky']
尝试一下:
迪克[10]
除了 IndexError,e:
打印e

实例:IndexError

s1 = '你好'
尝试一下:
int(s1)
除了 ValueError,e:
打印e

值错误

对于上面的例子来说,异常类只能用来处理指定的异常。无法处理未指定的异常。

# 如果没有捕获异常,程序会直接报错。 s1 = '你好'
尝试一下:
int(s1)
除了 IndexError,e:
打印 e

因此,在编写程序时,需要考虑try代码块中可能出现的异常。你可以这样写:

s1 = '你好'
尝试一下:
int(s1)
除了 IndexError,e:
打印 e
除了 KeyError,e:
打印 e
除了 ValueError,e:
打印 e

通用异常Python中的异常中,有一个通用异常:Exception,它可以捕获任何异常,即:

s1 = '你好'
尝试一下:
int(s1)
除了例外,e:
打印 e

接下来你可能想问,既然有了这个普遍的例外,其他的例外就可以忽略了吗?

回答:当然不是。需要先定义特殊处理或提醒的异常,最后定义Exception以保证程序的正常运行。

s1 = '你好'
尝试一下:
int(s1)
除了 KeyError,e:
打印“按键错误”
除了 IndexError,e:
打印“索引错误”
除了例外,e:
打印“错误”

3。其他结构异常

尝试一下:
# 主代码块
通过
除了 KeyError,e:
# 当异常发生时,执行该块
通过
其他:
# 主代码块执行完毕后,执行块
通过
最后:
# 无论是否异常,该块最终都会被执行
经过

4。主动触发异常

尝试一下:
引发异常('错误...')
除了例外,e:
打印 e

5。自定义例外

类 MyException(异常): def __init__(self, msg):
self.message = 消息 def __str__(自身):
返回自我信息 尝试一下:
raise MyException('我的异常')
除了 MyException,e:
打印 e

6。断言

# 断言条件 断言 1 == 1 断言 1 == 2

 

-->