Python 面向对象
1.成员共分三类
1.1 变量
1.1.1 实例变量与类变量
-
class Foo: # 类变量(静态字段) country="中国"# 每个对象中的值都相同。 # 方法 def __init__(self,name): self.name=name # 实例变量,字段 # 方法 def func(self): print(self.country) print(Foo.country)# 推荐使用 obj1=Foo('章北海') obj2=Foo('泰勒') print(obj1.name,obj1.country,Foo.country)# obj1.country 没有设置,默认取类的值 obj2.country='美国' # 类变量,可以通过类直接访问 print(obj2.name,obj2.country,Foo.country)
-
准则:
- 实例变量(字段)访问时,使用对象访问,即
obj.name
。 - 类变量(静态字段)访问时,使用类方法,即
Foo.country
,实在不方便时,才使用对象。
- 实例变量(字段)访问时,使用对象访问,即
-
类变量的是使用场景:当所有对象中有共同的字段时,且要改都改要删都删,可以将实例变量(字段)提取到类变量(静态字段)。
1.1.2 私有变量
-
私有变量也分为两种,即私有类变量和私有实例变量
-
class Foo: __country="中国" def __init__(self,name): self.__name=name #私有实例变量,字段 self.age=123 def func(self): print(self.__name) print(Foo.__country) obj=Foo('程心') # print(obj.__name) # 报错: AttributeError:'Foo' object has no attribute '__name' # print(Foo.__country) obj.func()
-
私有的成员变量在 Python 中使用较少。特点是外部无法访问。特殊写法亦可获取到。一般不用。
1.2 方法
- 分类
- 实例方法
- 静态方法
- 类方法
- 私有方法
- 私有实例方法
- 私有静态方法
- 私有类方法
1.2.1 实例方法
- 函数中必须包含self,
- 一般通过对象调用
1.2.2静态方法
-
编写时:
- 方法上写上
@staticmethod
- 参数可有可无
- 方法上写上
-
调用时:
- 类.方法名()
- 对象.方法名() # 不推荐使用此种方法
-
使用场景:静态方法无需使用对象中封装的值,那么就可以使用静态方法。
-
class Foo: def __init__(self,name): self.name=name # 实例方法 def func(self): print(self.name) @staticmethod def display(): print(666) obj=Foo("逻辑") Foo.display()# 一般使用类调用
1.2.3 类方法
-
# -*- coding: utf-8 -*- ''' @Time : 2022/1/23 13:18 @Author : ziqingbaojian @File : 03.方法.py ''' class Foo: def __init__(self,name): self.name=name # 实例方法 def func(self): print(self.name) # 静态方法 @staticmethod def display(): print(666) # 类方法 @classmethod def show(cls,x1,x2): print(cls,x1,x2) # obj=Foo("逻辑") # Foo.display()# 一般使用类调用 Foo.show(1,8)
- 补充:
self
代值对象,cls
代指类。
- 补充:
-
定义时:
- 方法上写上:
@classmethod
- 至少包含一个
cls
参数
- 方法上写上:
-
执行时:
- 类名.方法名;默认会讲话当前类传值参数中
-
使用场景:
- 如果在方法中会使用到当前类,那么就可以使用类方法。单利模式可能会使用到对应的类方法。
-
类方法与静态方法特别相似。调用时无需实例化。
1.2.4 私有方法的使用
# -*- coding: utf-8 -*-
'''
@Time : 2022/1/23 13:18
@Author : ziqingbaojian
@File : 03.方法.py
'''
class Foo:
def __init__(self,name):
self.name=name
# 实例方法
def func(self):
print(self.name)
def __f1(self,args):
print("私有方法")
# 静态方法
@staticmethod
def __display():
print("私有静态方法")
@staticmethod
def get_display():
Foo.__display()
# 类方法
@classmethod
def show(cls,x1,x2):
print(cls,x1,x2)
# obj=Foo("逻辑")
# Foo.display()# 一般使用类调用
Foo.get_display()
1.3 属性
class Foo:
@property
def start(self):
return 1
@property
def end(self):
return 2
obj=Foo()
print(obj.start)
print(obj.end)
将方法改造为属性,即调用方法时通常不使用()
进行调用。
- 编写时:
- 方法上方写上
@property
- 方法参数只有一个
self
- 方法上方写上
- 调用时:
- 无序加括号,使用 对象.方法
- 应用场景:
- 对于简单的方法,当无需传参,且有返回值时,可以使用
@property
- 对于简单的方法,当无需传参,且有返回值时,可以使用
- 属性也具有共有和私之分。与变量和方法类似
注意:类中私有的成员,在继承的子类中依旧不能被使用。
2.组合(建模)
2.1 对象的嵌套
# -*- coding: utf-8 -*-
'''
@Time : 2022/1/23 14:02
@Author : ziqingbaojian
@File : 04.组合建模.py
'''
class School:
def __init__(self,name,addres):
self.name=name
self.addres=addres
obj1=School("亚洲舰队",'自然选择号')
obj2=School("亚洲舰队",'蓝色空间号')
class Teacher:
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.__salary=salary
self.school=None
t1=Teacher("章北海",30,10000)
t2=Teacher("褚岩",20,30000)
t1.school=obj1
t2.school=obj2
# 查看舰长所在的飞船,嵌套查看
print(t1.school.name)
print(t1.school.addres)
2.2 主动调用其他类的成员
class Base:
def f1(self):
print("5个功能")
class Foo(object):
def f1(self):
Base.f1(self)
print("3个功能功能")
-
通过
类名.实例方法()
需要进行手动传参,传入self
. -
obj=Base() Base.f1(obj)# 手动传参
2.3 继承调用
class Base:
def f1(self):
print("5个功能")
class Foo:
def f1(self):
super().f1()
print("3个功能")
class Info(Foo,Base):
pass
obj=Info()
obj.f1()
# 正确执行
# obj=Foo()
# obj.f1()报错,因为类中的 super() 表示的是当前继承顺序的下一个。并不是单单的只当前类的父类
- super() 表示的是当前继承顺序的下一个。并不是单单的只当前类的父类
3.特殊成员
3.1 常见的双下滑线方法
# -*- coding: utf-8 -*-
'''
@Time : 2022/1/23 20:41
@Author : ziqingbaojian
@File : 06.特殊成员.py
'''
class Foo:
# 初始化方法 类名()自动执行
def __init__(self,name,age):
print("对象初始化开始")
self.name=name
self.age=age
# 对象() 自动执行
def __call__(self, *args, **kwargs):
print(args,kwargs)
# 对象[xxx]自动执行
def __getitem__(self, item):
print(item)
return 1
# 对象[xxx]=11自动执行
def __setitem__(self, key, value):
print(key,value)
# 本方法没返回值
def __delitem__(self, key):
print(1)
# 实现对象加对象的运算
def __add__(self, other):
return self.age+other.age
def __enter__(self):
print("可以使用 with 上下文管理,返回值被 as 后面的值接收")
return 123
def __exit__(self, exc_type, exc_val, exc_tb):
print(456)
obj1=Foo("啊哈",20)
obj1(1,23,3,k1="12")
res=obj1['123']
print(res)
obj1['k1']="v1"
obj1.__delitem__('123')
list
with obj1 as f:
print(f)
print("执行中")
3.2 构造方法
class Foo:
def __init__(self,name):
self.name=name
print(2)
def __new__(cls, *args, **kwargs):
'''
返回一个空的对象的供 init 进行初始化赋值
:param args:
:param kwargs:
'''
print(1)
return object.__new__(cls)
obj=Foo('0')
说明:
__init__
一般称做初始化方法,__new__
是真正创建对象的方法。是两个方法组成了类似与其他语言中的构造方法。
3.3 常见特殊方法的使用
-
__dict__
方法
-
class Foo: def __init__(self,name,age): self.name=name self.age=age obj=Foo('章北海','230') print(obj.__dict__)#将实例变量以字典的形式返回
-
补充:
-
类.__dict__
,会返回包括函数在内的成员信息,使用较少。
-
-
__str__
方法
-
class Foo: def __init__(self,name,age): self.name=name self.age=age def __str__(self): return "打印对象我就执行" obj=Foo('章北海','230') print(obj)
-
类似与 Java中的
toString()
方法。 -
补充
__repr__
方法-
__str__
内部调用了__repr__
。当类中没有__str__
,但是有__repr__
,打印对象时 就会执行。一般使用__str__
方法较多
-
4.类的约束
4.1 主动抛出异常
class Foo:
def send(self):
# 如果抛出异常,则子类如果要调用则必须重写该方法
raise NotImplemented(".send() must be overrideen")
def func(self):
print("正常执行")
class Bar(Foo):
pass
obj=Bar()
obj.func()
obj.send()
4.2 抽象类和抽象方法
-
补充:
- Python 语言中不包含接口的数据类型,但是包含抽象类,和抽象方法。
- Java 中包含抽象类和抽象方法,且接口中的方法必须是抽象方法。
-
from abc import ABCMeta,abstractmethod class Foo(metaclass=ABCMeta): def func(self): print(123) @abstractmethod def send(self): pass class Bar(Foo): def send(self): print("Hello world") obj= Bar() obj.send()
-
说明:在 Python 语言中一般会使用第一种方式
NotImplemented
异常进行处理,而不定义相关的抽象类,抽象类与抽象方法不常用。
5.多继承的补充
- 默认:先找左边的再找右面的父类。
class A(object):
pass
class B(object):
def f1(self):
print("B.f1")
class C(A,B):
pass
obj=C()
obj.f1()
5.1 经典类和新式类
-
python2.2
- 经典类:
- 新式类:如果自己或自己的前辈只要有人继承 object,那么此类就是新式类。
-
python3 中全部都是新式类。
-
区别:查找流程不同。
- 经典类:一条到走到黑;深度优先
- 新式类:采用 C3 算法。
-
补充:
查看继承关系。
# 语法:类.__mro__ print(E.__mro__)
- 注意事项:
super
是遵循__mro__
执行顺序。 - Python2 中不包含
__mro__
方法。
- 注意事项:
5.2 C3 算法
- 简单新式类(记忆),复杂的时候使用C3算法。