python面向对象
用几大特征表达一类事物称为一个类,类更像是一张图纸,表达的是一个抽象概念
对象是类的具体实现,更像是由这图纸产出的具体物品,类只有一个,但对象可以通过这个类实例化出多个
对象是类的实例,类是对象的模板
*类中的成员只有方法和属性,不要裸露的把判断和循环直接写在类中,而是用方法包起来
(1)类的定义
# 定义一 class Myclass: pass # 定义二 class Myclass(): pass # 定义三 class Myclass(object): pass
(2)类的实例化 产生的是对象
>>> class Car(): ... color = "red" ... >>> obj = Car() >>> print(obj) <__main__.Car object at 0x0000026497119BE0> >>>
(3)类的基本结构
1.成员属性
2.成员方法
>>> class MyCar(): ... # 成员属性 ... color = "red" ... # 成员方法 ... def run(): ... pass ... >>>
(4)类的命名
推荐使用驼峰命令,每个单词首字母大写
myclass --> MyClass
面向对象三大特征: 封装 继承 多态
封装:对类中成员属性和方法的保护,控制外界对内部成员的访问,修改,删除等操作
对象的使用方式:
对象.属性
对象.方法
class MyCar(): # 公有成员属性 attra = "属性" # 私有成员属性 __attrb = "私有属性" # 公有成员方法 def run(self): print("调用属性",self.attra) # 私有成员方法 def __private_info(self): print("私有成员方法") """ 绑定方法: 1.绑定到对象,默认把对象当成参数进行传递,self形参接受 2.绑定到类,默认把类当成参数进行传递,形参接受 """ # 实例化对象 obj = MyCar() # 1.实例化的对象防卫公有成员属性和方法 print(obj.attra) obj.run() # 2.实例化的对象动态添加公有成员属性和方法 """ __dict__ 获取对象或者类的内部成员 """ print(obj.__dict__) # 当前对象没有成员 obj.attra = "改变属性" print(obj.__dict__) # 动态添加成员方法 # 1) 添加无参方法 def methoda(): print("新添加的方法1") # 类外的函数赋值给obj对象一个成员方法 obj.methoda = methoda obj.methoda() print(obj.__dict__) # 2) 添加有参方法 def methodb(self,arge): print(self.attra,arge) # 赋值 obj.methodb = methodb # 需要手动传入对象 obj.methodb(obj,"有参方法") # 3) 添加lambda表达式 obj.methodc = lambda : print("添加方法c") obj.methodc() # ------------------------------- # 运行结果 属性 调用属性 属性 {} {'attra': '改变属性'} 新添加的方法1 {'attra': '改变属性', 'methoda': <function methoda at 0x0000020F70DA2EA0>} 改变属性 有参方法 添加方法c
继承
一个类除了自身所拥有的属性方法之外,还获取了另外一个类的成员属性和方法
一个类继承另外一个类,当前类是子类(衍生类),被继承的类是父类(基类、超类)。所有类的父类都是object
单继承
-1.子类可以使用父类的共有方法
>>> class Father(): ... attra = 'a' ... def func(self): ... print('func') ... >>> class Son(Father): ... pass ... >>> obj = Son() >>> print(obj.attra) a >>> obj.func() func >>>
-2.子类不能调用父类的私有方法
>>> class Father(): ... __attrb = 'b' ... def __func(self): ... print('private func') ... >>> class Son(Father): ... pass ... >>> obj = Son() >>> obj.__attrb Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Son' object has no attribute '__attrb' >>> obj.__func() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Son' object has no attribute '__func' >>>
-3.子类可以改写父类方法
self对象优先调用本类中的方法,如果本类中没有调用父类的
多继承
# 基本语法 class Father(): attra = "属性a" def methoda(self): print("methoda") class Mother(): attrb = "属性b" def methodb(self): print("methodb") class Son(Father,Mother): pass obj = Son() print(obj.attra) obj.methoda() # 执行结果 属性a methoda
类的相关操作
语法:类.属性 类.方法()
1.调用类中成员的时候,要么使用对象,要么使用类
对象可以使用类中的相关公有成员,但是没有归属权
类中的成员都归当前这个类所有,但是不能使用对象中的成员
2.对象中如果有成员,使用自己的,如果没有,使用类中的
class Person(): attra = "公有成员属性" __attrb = "私有成员属性" def method(): print("普通公有方法",Person.__attrb) def __private_method(): print("普通私有方法") obj = Person() # 实例化一个对象 print(Person.attra) # 类访问成员属性 print(Person.method()) # 类访问成员方法 """ 1.对象无法调用无参的普通方法,必须加上self 2.无论是对象还是类,都无法在类外调用类中的私有成员 """ print(Person.__dict__) # 查看类的所有成员 # 定义的类动态添加公有成员属性和方法 Person.attrc = "添加成员属性" print(Person.__dict__) print(obj.__dict__) # 1) 添加无参方法 def methoda(): print("添加无参方法") Person.methoda = methoda Person.method() # 2) 添加有参方法 def methodb(name): print("方法",name) Person.methodb = methodb Person.methodb("有参方法") # 3) lambda表达式 Person.methodc = lambda : print("lambda表达式") Person.methodc() # 执行结果 公有成员属性 普通公有方法 私有成员属性 None {'__module__': '__main__', 'attra': '公有成员属性', '_Person__attrb': '私有成员属性', 'method': <function Person.method at 0x00000280E4203598>, '_Person__private_method': <function Person.__private_method at 0x00000280E4203488>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} {'__module__': '__main__', 'attra': '公有成员属性', '_Person__attrb': '私有成员属性', 'method': <function Person.method at 0x00000280E4203598>, '_Person__private_method': <function Person.__private_method at 0x00000280E4203488>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'attrc': '添加成员属性'} {} 普通公有方法 私有成员属性 方法 有参方法 lambda表达式
多态:不同的子类对象,调用相同的父类方法,产生不同的执行结果
好处:多态是针对对象来说的,在不改变原有代码的前提下,完成不同的功能。不同的对象,调用相同的方法,达到不同的功能
# 定义一个父类 class Father(): # 方法 def methoda(self): pass # 定义子类调用父类方法 class Sona(Father): def methoda(self): print("调用父类,定制化子类a") class Sonb(Father): def methoda(self): print("调用父类,定制化子类b") # 实例化 obja = Sona() objb = Sonb() listvar = [obja,objb] for i in listvar: i.methoda() # 执行结果 调用父类,定制化子类a 调用父类,定制化子类b
python对成员的保护分为两个等级
私有的: private
在本类内部可以访问,类的外部不可以访问.(python中 属性或者方法前面加上两个下划线__)
公有的: public
在本类的内部和外部都可以访问.
(了解)在其他高级语言当中,如java php c++等语言,有三个等级 private public protected
私有成员的改名策略 [_类名__成员名]
对象的相关操作
(1)实例化的对象访问公有成员属性和方法
(2)实例化的对象动态添加公有成员属性和方法
(3)实例化的对象删除公有成员属性和方法
类的相关操作
(1)定义的类访问公有成员属性和方法
(2)定义的类动态添加公有成员属性和方法
(3)定义的类删除公有成员属性和方法
普通方法: 没有任何参数传递,只能类调用
绑定方法: 把默认传参的方法叫做绑定方法,绑定到对象(默认传对象),绑定到类(默认传类)
非绑定方法:静态方法(无需传任何参数,对象和类都能调用)
私有的:只能载类或者对象的结构中访问
公有的:可以载任何位置访问
受保护:可以载当前类或者对象 和子类或者子类对象中访问
类内 子类中 类外部
公有的: √ √ √
私有的: √ X X
受保护: √ √ X (python语言不支持)
编程语言的发行时间
1972 C
1983 C++(即带有类概念的C语言,更名于1983年7月)
1989 Python
1991 Visual Basic
1993 Ruby
1995 JavaScript
1995 PHP
1996 Java
2001 C#
2009 Go
多继承的弊端会造成菱形继承这种情况,找不清调用顺序
super对象按照mro列表的顺序依次调用,解决菱形继承存在的问题
经典类:深度优先 (python2.x)
新式类:广度优先 (python3.x)
写多继承时,尽量避免造成不同类相同方法名的情况,提高代码质量 高内聚,低耦合
高内聚:一个模块只完成一个任务,专一性高
低耦合:模块与模块之间可以彼此独立不冲突,方便移植复用.
super调用父类方法
(1)super本身是一个类 super()是一个对象 用于调用父类的绑定方法
(2)super() 只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self)
(3)super用途: 解决复杂的多继承调用顺序
class Father(): attra = "aaa" def methoda(): print("aaa") class Mother(): attrb = "bbb" def methodb(self): print("bbb") class Son(Father,Mother): attra = "s-aaa" def methodb(self): print("s-bbb") def calla(self): print(Father.attra) Father.methoda() """ self在调用时,本类有,优先调用自己,本类没有,调用父类 """ def callb(self): print(self.attrb) self.methodb() def callc(self): print(super().attra) super().methodb() obj = Son() obj.calla() obj.callb() obj.callc() # 执行结果 aaa aaa bbb s-bbb aaa bbb
魔术方法(特定时机自动触发)
__init__魔术方法(构造方法)
'''
触发时机:实例化对象,初始化的时候触发
功能:为对象添加成员
参数:参数不固定,至少一个self参数
返回值:无
'''
# 基本语法 class MyClass(): def __init__(self): self.name = "Python" obj = MyClass() print(obj.name) # 多个参数的__init__ class MyClass(): def __init__(self,name): self.name = name obj = MyClass("Python") print(obj.name) # 综合 class MyClass(): def __init__(self,name,age): self.name = name self.age = age def score(self): print("-->111") def course(self): print("-->222") obj = MyClass("Python",18) obj.score() obj.course() # 执行结果 Python Python -->111 -->222
__new__ 魔术方法
'''
触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
功能:控制对象的创建过程
参数:至少一个cls接受当前的类,其他根据情况决定
返回值:通常返回对象或None
'''
# 可以通过__new__来控制对象创建的过程 class MyClassa(): attra = 'a' obja = MyClassa() class MyClassb(): def __new__(cls, *args, **kwargs): print(cls) # 通过父类object 中的 __new__ 魔术方法 ,返回该类的对象,参数是类 return obja # 可以返回别人的对象 objb = MyClassb() print(objb) print(obja.attra)
__new__和__init__之间的区别
""" __new__ 创建对象 __init__ 初始化对象 __new__ 在 __init__触发之前 """ class MyClass(): def __new__(cls,name): # __new__和__init__形参和实参要匹配 print(111) return object.__new__(cls) # 需要返回给__init__中参数 def __init__(self,name): print(222) self.name = name obj = MyClass("test") print(obj.name) # 升级 class MyClass(): def __new__(cls, *args, **kwargs): print(111) return object.__new__(cls) def __init__(self,name,age,sex): print(222) self.name = name self.age = age self.sex = sex obj = MyClass("A",22,"M") print(obj.name) # __init__只会初始化自己的对象 class MyClassa(): def __new__(cls, *args, **kwargs): print(111) return obj def __init__(self): print(222) obj = MyClassa() print(obj) # 执行结果 111 222 test 111 222 A 111 <__main__.MyClass object at 0x000002AD34F1E1D0>
__del__ 魔术方法(析构方法)
触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
功能:对象使用完毕后资源回收
参数:一个self接受对象
返回值:无
1.执行完毕触发析构方法
class Del(): def __init__(self,name): self.name = name def splitline(self): print('-----') def __del__(self): print('析构方法触发') obj = Del('析构方法测试') # 1.执行完毕触发析构方法 print('--程序执行完毕--') # 执行结果 --程序执行完毕-- 析构方法触发
2.所有对象被del后触发
class Del(): def __init__(self,name): self.name = name def splitline(self): print('-----') def __del__(self): print('析构方法触发') obj1 = Del('析构方法测试') print('--程序执行完毕start--') obj2 = obj1 del obj1 del obj2 # 此处不执行del则在最后触发析构方法 print('--程序执行完毕end--')
3.例:文件读取操作(应用)
class ReadFile(): def __new__(cls,filename): if os.path.exists(filename): return object.__new__(cls) return print("改文件不存在") def __init__(self,filename): self.fp = open(filename,mode="r",encoding="utf-8") def readcontent(self): res = self.fp.read() return res def __del__(self): self.fp.close() obj = ReadFile("ceshi111.txt") res = obj.readcontent() print(res)
__call__ 魔术方法
'''
触发时机:把对象当作函数调用的时候自动触发
功能: 模拟函数化操作
参数: 参数不固定,至少一个self参数
返回值: 看需求
'''
# 统一调用 class MyClass(): def __call__(self,task): print("统一调用{}".format(task)) self.step1() self.step2() self.step3() def step1(self): print(111) def step2(self): print(222) def step3(self): print(333) obj = MyClass() obj('test') # 执行结果 统一调用test 111 222 333
__str__ 魔术方法
'''
触发时机: 使用print(对象)或者str(对象)的时候触发
功能: 查看对象
参数: 一个self接受当前对象
返回值: 必须返回字符串类型
'''
class MyClass(): attra = 'attra' def __init__(self,name): self.name = name def info(self): return "测试属性{},测试名称{}".format(self.attra,self.name) def __str__(self): return self.info() obj = MyClass("test") # 打印时触发 print(obj) # 没有__str__时 :<__main__.MyClass object at 0x000001F1DEACA208> print(obj) # 有__str__时 :测试属性attra,测试名称test
__repr__ 魔术方法
'''
触发时机: 使用repr(对象)的时候触发
功能: 查看对象,与魔术方法__str__相似
参数: 一个self接受当前对象
返回值: 必须返回字符串类型
'''
class MyClass(): attra = "attra" def __init__(self,name): self.name = name def info(self): return "属性{},名称{}".format(self.attra,self.name) def __repr__(self): return self.info() # 系统底层自动添加下面语句 __str__ = __repr__ obj = MyClass("test") print(obj) print(str(obj))
----普通变量的基本操作,如果应用在对象上,也有相应的魔术方法
__bool__ 魔术方法
'''
触发时机:使用bool(对象)的时候自动触发
功能:强转对象
参数:一个self接受当前对象
返回值:必须是布尔类型
'''
class MyClass(): def __bool__(self): return False # 实例化对象 obj = MyClass() res = bool(obj) print(res)
'''
类似的还有如下等等(了解):
__complex__(self) 被complex强转对象时调用
__int__(self) 被int强转对象时调用
__float__(self) 被float强转对象时调用
...
...
'''
__add__ 魔术方法 (与之相关的__radd__ 反向加法)
'''
触发时机:使用对象进行运算相加的时候自动触发
功能:对象运算
参数:二个对象参数
返回值:运算后的值
'''
class MyClass(): def __init__(self,num): self.num = num # 当对象在+加号的左侧时,自动触发; def __add__(self,other): return self.num * 2 + other # 当对象在+加号的右侧时,自动触发 def __radd__(self,other): return self.num * 3 + other a = MyClass(3) # self 接收到 a ,other 接收到 1 self.num * 2 + 1 = 3 * 2 +1 = 7 res = a+1 print(res) b = MyClass(5) # 第一次参数永远接受的是对象,self接收的 b ,other 接受的是 2 => 5 * 3 + 2 => 17 res = 2 + b print(res)
'''
类似的还有如下等等(了解):
__sub__(self, other) 定义减法的行为:-
__mul__(self, other) 定义乘法的行为:
__truediv__(self, other) 定义真除法的行为:/
...
...
'''
__len__ 魔术方法
'''
触发时机:使用len(对象)的时候自动触发
功能:用于检测对象中或者类中某个内容的个数
参数:一个self接受当前对象
返回值:必须返回整型
'''
# 计算类中的成员个数 class MyClass(): pty1 = 1 __pty2 = 2 pty3 = 3 def func1(self): pass def func2(self): pass def __func3(self): pass def __len__(self): dic = MyClass.__dict__ """ lst = [] for i in dic: if not( i.startswith("__") and i.endswith("__") ): lst.append(i) """ lst = [i for i in dic if not( i.startswith("__") and i.endswith("__") )] return len(lst) obj = MyClass() print(len(obj))
'''
类似的还有如下等等(了解):
__iter__(self) 定义迭代容器中的元素的行为
__reversed__(self) 定义当被 reversed() 调用时的行为
__contains__(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为
...
...
'''
反射
概念:通过字符串去操作类对象 或者 模块中的属性方法
(1)类中的反射
hasattr() 检测对象/类是否有指定的成员
getattr() 获取对象/类成员的值
setattr() 设置对象/类成员的值
delattr() 删除对象/类成员的值
(2)模块的反射
sys.modules 返回一个系统字典,字典的键是加载的所有模块
class Myclass(): attra = '属性a' __attrb = "私有属性b" def methoda(): print("普通方法") def methodb(self): print("绑定方法") def __methodc(self): print("私有方法") obj = Myclass() # 1.hasattr() 检测对象/类是否有指定的成员 print(hasattr(obj,"attra")) print(hasattr(Myclass,'attra')) # 2.getarrt() 获取对象/类成员的值 print(getattr(obj,"attra")) getattr(obj,"methodb")() # 3.setarrt() 设置对象/类成员的值 setattr(obj,"attrc","属性c") print(obj.attrc) # 4.delattr() 删除对象/类成员的值 delattr(obj,"attrc")