面向对象编程相关
每日一记
_类名+私有成员 # 直接访问私有成员 import types types.MethodType("方法","对象") # 将方法和对象绑定到一起
面向对象
# 类的基本结构 # 定义 class Preson(): # 属性 mode = "心情美美的" # 方法 def eat(self): print(self.mode + "吃了一顿烧烤") bajie = Preson() # 实例化一个对象bajie bajie.eat() # 对象调用了Preson中eat()方法
1、面向对象三大特性
1.1 面向对象三大特性之封装
# 封装等级 (公有与私有) class MySelf: # 公有成员属性 name = "bajie" # 私有成员属性 __age = 18 # 公有成员方法 def sports(self): print("I can swim") # 私有有成员属性 def __love(self): print("I love baozhu") def info(): print(MySelf.__age)
1.1.1 封装之对象的相关操作
# 对象在类外动态添加成员属性 obj.happy = "money" print(obj.happy) # 对象在类外动态添加成员方法 def labour(arg): print("我在{}劳动".format(arg)) obj.eat = labour obj.eat("包头") # 我在包头劳动 # 对象在类外动态添加成员绑定方法,可以调用类属性 import types def func(self): print("{},me go to swim !".format(self.name)) # MethodType(方法,对象) 把哪个方法和哪个对象绑定到一起,形成绑定方法 obj.go = types.MethodType(func,obj) obj.go() # bajie,me go to swim ! # lambda表达式 obj.to = lambda : print("执行to方法") obj.to()
1.1.2 封装之类的相关操作
""" 类调用的方式:1,类.成员属性 2,类.成员方法(类中的无参方法只能是类来调用.) 对象不能调用无参的方法 """ # 类访问公有成员属性 print(MySelf.name) # 类访问公有方法 MySelf.sports() # I can swim # 定义的类动态添加公有成员属性 MySelf.happy = "swim" # 类动态添加公有成员方法 def func(): pass MySelf.haha = func() # 访问私有成员 print(obj._MySelf__age) # 不推荐 # 推荐写法,通过方法内间接调用私有成员 obj1 = MySelf() obj1.info()
1.1.3 del 关键字删除类成员
del obj.to # 删除对象的方法 del MySelf.info # 删除类方法info """ 总结: 类和对象之间的区别 对象可以调用类中的成员属性和方法,返过来,类不能调用对象中的成员. 类中的成员属性和方法归属于类本身,对象可以使用,但是没有修改和删除的权利. 对象在调用相应成员时,先看看自己有没有.如果有,调用自己的,如果没有,调用类中的成员:如果类中成员也没有,直接报错. """
1.2 面向对象三大特性之继承
1.2.1 单继承
class F1(): name = "bajie" __age = 18 def f1(self): print("我是f1") def __f2(self): print("我是私有方法f2") def info(): print(F1.__age) o1 = F1() F1.info() # 18 class F2(F1): def info(): print(F1.__age) obj = F2() print(obj.name) # bajie print(obj.__age) # error obj.f1() # "我是f1" obj.info # error # 总结:继续可以继承基类所有共有成员,而继承不了私有成员,可以通过公有方法间接调用私有成员
1.2.2 多继承
class Father(): property = "Father----属性" # 类方法 def f_hobby(): print("Father----方法") class Mother(): property = "Mother----属性" # 绑定方法 def m_hobby(self): print("Mother----方法") # 继承顺序,深度优先,先左后右 class Son(Father, Mother): property = "Son----属性" def SonTry(self): print(super().property) print(self.property) # super用法 """ (1)super本身是一个类,super()是一个对象 用于调用父类的绑定方法 (2)super()只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self) (3)super用途: 解决复杂的多继承调用顺序 """ # super() 与 self print(Son.property) # "Son----属性" obj = Son() obj.SonTry() # print(super().property)------>Father----属性 # print(self.property) ------> Son----属性 """ self 和 super()的区别 self 在调用成员时,先看看自己的类对象中是否存在该成员,如果有调用自己的,如果没有,调用父类的.如果都没有报错 super() 在调用成员时,只调用父类的公有成员(属性,绑定方法),永远不会调用自己的.如果父类没有,直接报错. """
1.2.3 菱形继承
# mro 返回的是方法调用顺序列表,针对于多继承下的同名方法,按照顺序依次的进行调用 # 用法 print(类.mreo()) # issubclass (应用在类当中,判断衍生类关系) issubclass(sub,surer) # isinstance (应用在对象和类之间,判断类型) isinstance(odj,class)
1.3 面向对象三大特性之多态
# 多态就是同一操作(方法)作用于不同的对象时,可以有不同的解释,产生不同的执行结果。
2、魔术方法
__init__() 初始化方法
''' 触发时机:实例化对象,初始化的时候触发 功 能:为对象添加成员 参 数:参数不固定,至少一个self参数 返 回值:无 ''' def MyClass(): def __init__(self,name,age): self.name = name self.age = age # obj对象传给self,"bajie"传给"name",18传给"age" obj = MyClass("bajie",18)
__new__() 构造方法
''' 触发时机:实例化类生成对象的时候触发(触发时机在__init__之前) 功 能:控制对象的创建过程 参 数:至少一个cls接受当前的类,其他根据情况决定 返回 值:通常返回对象或None ''' # 代码解读一 (参数问题) class MyClass(): def __init__(self,name,age): self.name = name self.age = age def __new__(cls): return object.__new__(cls) # 1,实例化对象时,new方法需要将MyClass传给object为自己创建对象.但此时,MyClass传入值超过了new方法接收参数数量. # obj = MyClass("bajie",18) 报错 # 代码解读二 (触发时机) class MyClass(): def __init__(self,name,age): self.name = name self.age = age def __new__(cls,*args,**kwargs): return object.__new__(cls) # 此时的new方法,能够接收无限参数,那么就要看__init__需要多少参数. # obj对象传给self,"bajie"传给"name",18传给"age" obj = MyClass("bajie",18) # 代码解读三 (返回值) # 示例一 class MyClass(): def __new__(cls,*args,**kwargs): # 基类object为自己本身创建的对象 return object.__new__(cls) # 示例二 class A(): age = 18 obj = A() class MyClass(): age = 20 def __new__(cls,*args,**kwargs): # 返回其A类的对象 return obj obj = MyClass() # MyClass的实例化对象 obj # 看代码,__new__是创建方法,而以上代码并没有为MyClass类创建对象,而是返回了A类的对象 print(obj.age) # 打印结果是 18 # 示例三 class MyClass(): def __new__(cls,*args,**kwargs): # 返回空 return None # 创建对象不成功,为空
单态模式
# 一个类,无论实例化多少个对象,都有且只有1个,不重复开辟空间 """ 优点:节省内存空间,提升执行效率, 针对于不要额外对该对象添加成员的场景(比如:mysql增删改查) """ # 示例代码 class Myclass(): __obj = None def __new__(cls): if cls.__obj is None(): cls.__obj = object.__new__(cls) return cls.__obj # 三对象内存地址与第一个内存地址相同 obj1 = MyClass() obj2 = MyClass() obj3 = MyClass() """ 第一次实例化对象时候, 创建一个对象赋值给cls.__obj,返回 cls.__obj 第二次实例化对象时候, 判定cls.__obj is None: 不成立, 直接返回上一次创建好的那一个对象 第三次实例化对象时候, 判定cls.__obj is None: 不成立, 直接返回上一次创建好的那一个对象 """ # 练习 class SingleTon(): __obj = None def __new__(cls,*args,**kwargs): if cls.__obj is None: cls.__obj = object.__new__(cls) return cls.__obj def __init__(self,name): self.name = name obj1 = SingleTon("bajie") obj2 = SingleTon("meizhu") print(obj1.name) # meizhu print(obj2.name) # meizhu """ 第一次实例化对象,创建的obj1对象,name = bajie 第二次实例化对象,并没有创建对象,相当于>obj1 = SingleTon("meizhu") ,从而覆盖掉了 name变量 """
连贯操作
# 通过.不停的调用下一个对象的操作就是连贯操作 # 示例一 class MyClass1(): pth1 = 10 class MyClass2(): def __init__(self, obj): self.obj = obj obj = MyClass1() obj2 = MyClass2(obj) # 对象.对象.属性 print(obj2.obj.pth1) # 示例二 class MyClass1(): pty1 = 101 def func1(self): print("我是func1函数") class MyClass2(): def __init__(self,obj): self.pty2 = obj def func2(self): print("我是func2函数") class MyClass3(): pty3 = 103 def __init__(self,obj): self.pty3 = obj def func2(self): print("我是func3函数") obj1 = MyClass1() obj2 = MyClass2(obj1) obj3 = MyClass3(obj2) # 通过对象来调用func1 obj3.pty3.pty2.func1() # 通过对象来查看pty1属性 print(obj3.pty3.pty2.pty1)
__del__() 析构方法
''' 触发时机:1,程序结束 2,del 删除对象,对象引用计数为0时自动触发 功 能:回收对象 参 数: self 返回 值:无 ''' # 示例一 class A name = "bajie" def __del__(self): print('析构方法被触发') a = A() b = a del a # 程序结束才触发,因为a对象的计数不为零,b也在引用 # 示例二 class A name = "bajie" def __del__(self): print('析构方法被触发') a = A() del a # 引用计数为零 ----> '析构方法被触发'
__str__()
''' 触发时机:1,print 打印时 2,str() 强转时 功 能:查看对象 参 数: self 返回 值:必须是字符串 ''' class A: name = "bajie" def __str__(self): print("str被触发") return "123" a = A() str(a) # "str被触发" print(a) # 先 "str被触发" 后打印 123
__repr__()
''' 触发时机:1,print 打印查看对象时 2,str() 强转时 3,repr 转换时 功 能:查看对象 参 数: self 返回 值:必须是字符串 ''' class A: name = "bajie" def __repr__(self): print("str被触发") return "123" # 注意点 底层代码 __str__ == __repr__ 所以 print,str 也会触发 a = A() repr(a) # "str被触发"
__call__()
''' 触发时机:对象当作函数执行时触发 功 能:模拟函数化操作 参 数: 至少一个self参数 返回 值:看需求 ''' # 基本用法 class MyClass(): a = 1 def __call__(self): print("call魔术方法被触发了") obj = MyClass() obj() # "call魔术方法被触发了" # 模拟 int 运作 import math class MyInt(): def calc(self,num,sign=1): # 去掉左边多余的0 strvar = num.lstrip("0") # 为了防止都是0 ,如果去掉之后为空,返回0 if strvar == "": return 0 # 正常情况下,执行存数字字符串变成数字 , 在乘上相应的符号,得出最后的结果 return eval(strvar) * sign def __call__(self,num): if isinstance(num , bool): if num == True: return 1 elif num == False: return 0 elif isinstance(num,int): return num elif isinstance(num,float): return math.floor(num) if num >= 0 else math.ceil(num) elif isinstance(num,str): if (num[0] == "+" or num[0]== "-") and num[1:].isdecimal(): if num[0] == "+":sign = 1 else:sign = -1 return self.calc(num[1:],sign) elif num.isdecimal(): return self.calc(num) else: return "老铁,这个真转不了" myint = MyInt()
__bool__()
# 相同用法:__int__() , __float__() , __complex__() ''' 触发时机:bool(对象)的时候自动触发 功 能:强转对象 参 数: self 返回 值:必须是bool值 ''' class MyClass(): def __bool__(self): return False obj = MyClass() res = bool(obj) print(res)
__add__()
# __sub__() , __mul__() , __truediv__() ''' 触发时机: + 时触发 功 能:对象运算 参 数: self + 相加的参数 返回 值:相加后的值 ''' # 示例一 (对象 + 值的情况,对象在加号+的左侧) class MyClass(): def __init__(self,num): self.num = num def __add__(self,other): return self.num + other a = MyClass(6) # + 号左侧的对象传给self ,右侧的4传给other,那么self.num = 6 print(a + 4) # 10 print(4 + a) # error # 示例二 (__radd__()反向加法,对象在 + 号右侧自动触发) class MyClass(): def __init__(self,num): self.num = num def __radd__(self,other): return self.num + other a = MyClass(6) # + 号右侧的对象传给self ,左侧的4传给other,那么self.num = 6 print(a + 4) # error print(4 + a) # 10 # 示例三 (2个对象的参数相加) class Foo: def __init__(self,name,age): self.name = name self.age = age def __add__(self, other): return self.age + other.age def __radd__(self,other): return self.num * 2 + other obj1 = Foo("八戒",18) obj2 = Foo("九戒",19) # 只执行add,不执行radd.因为+号左侧是对象 print(obj2 + obj1) # 37 print(obj1 + obj2) # 37 # 示例四 (2个对象相加) class MyClass(): def __init__(self,num): self.num = num def __add__(self,other): return self.num + other def __radd__(self,other): return self.num * 2 + other a = MyClass(3) b = MyClass(7) print(a + b) # 17 """ 代码解读: a + b 先触发 __add__ self是a,other是b.等价于 3 + b 返回值是 3 + b 触发 __radd__, 此时self是b,other为3.等价于 7*2+3 """
__len__()
# 相同用法:__iter__() , __revaersed__() , __contains__() ''' 触发时机:使用len(对象)的时候自动触发 功 能:用于检测对象中或者类中成员的个数 参 数: self参数 返回 值:整型 ''' # 示例 class MyClass(): pty1 = 1 pty2 = 2 __pty3 = 3 def func1(): pass def __func3(): pass def __len__(self): lst = [] dic = MyClass.__dict__ lst = [i for i in dic if not(i.startswith("__") and i.endswith("__"))] return len(lst) obj = MyClass() # 自动触发__len__,功能看函数代码,此实例是过滤类中的自定义成员 print(len(obj)) # 5
3、魔术属性
__dict__
# 获取对象或类的所有成员 class MyClass(): pty1 = 1 __pty3 = 3 def func1(): pass def __func3(): pass obj = MyClass() print(MyClass.__dict__) # 获取类中所有成员 print(obj.__dict__) # 获取对象中所有成员
__doc__
# 获取函数,或类中的文档部分 def func(n): """ :param n: 字符串 :return: 字符串n中,z出现的次数 """ # 返回值 return n.count("z") print(func.__doc__) """ # 返回值不打印 :param n: 字符串 :return: 字符串n中,z出现的次数 """
__name__
# 获取对象或类名 def func(n): return n.count("z") print(func.__name__) # func
__class__
# 获取对象属于的类 class MyClass: def func(n): pass class MyClass1(MyClass): def func2(n): return n.count("z") obj1 = MyClass() obj2 = MyClass1() print(MyClass1.__class__) # <class 'type'> print(obj1.__class__) # <class '__main__.MyClass'> print(obj2.__class__) # <class '__main__.MyClass1'>
__bases__
# 获取类的直接继承类 (返回值是元组) # 示例一 class A(): pass class B(A): pass class C(A,B): pass # 报错,B类间接继承了A print(C.__base__) print(C.__bases__) # 示例二 class A(): pass class B(): pass class C(): pass class D(A,B,C): pass # 报错,B类间接继承了A print(D.__base__) # A print(D.__bases__) # A,B,C
4、装饰器
# 不改变原函数代码情况下,为原函数扩展新功能 # 示例一 def newfunc(func): def inner(): print("我是装饰器") func() return inner def func(): print("我是原函数") func = newfunc(func) # 1,newfunc(func) == inner 2, func == inner func() # 不改变原函数,新函数重新赋值给原函数,再调用时,扩展了新功能,执行顺序需要看调用位置 # 示例二 (语法糖---> @ ) def newfunc(func): def inner(): print("我是装饰器") func() return inner @newfunc # 相当于 ---> func = newfunc(func) # 1,newfunc(func) == inner 2, func == inner def func(): print("我是原函数") func() # 示例三 (装饰器的嵌套) def kuozhan1(func): def newfunc(): print("1") func() print("2") return newfunc def kuozhan2(func): def newfunc(): print("3") func() print("4") return newfunc # 装饰器由下往上递! @kuozhan2 # 此时func = newfunc ,newfunc中的func是5,然后继续装饰,参数相当于传的是 newfunc @kuozhan1 # 相当于 func = kuozhan1(func) = newfunc 如果此时执行,那么打印结果是 1 - 5 - 2 def func(): print("5") func() # 再次执行func ,是执行kuozhan2的返回值newfunc,所以, 3 - 1 - 5 - 2 - 4 # 示例四 (原函数带参数的装饰器) def kuozhan(func): def newfunc(who, where): print("1") func(who, where) # 原函数有参数,这里也需要传 print("2") return newfunc @kuozhan def func(who, where): print("执行原函数") # 示例五 (原函数带返回值的装饰器) def kuozhan(func): def newfunc(who, where): print("1") res = func(who, where) # 原函数有参数,这里也需要传,接收原函数的返回值 print("2") return res # 返回原函数的返回值 return newfunc @kuozhan def func(who, where): print("执行原函数") return "{}在{}解手".format(who,where) print(func("八戒", "厕所")) # 示例六 (类装饰器) class A: def __call__(self,func): return self.kuozhan1(func) def kuozhan(func): def newfunc(who, where): print("1") func(who, where) print("2") return newfunc def kuozhan1(self,func): def newfunc(who, where): print("3") func(who, where) print("4") return newfunc # 方法一 @A.kuozhan # A类中的方法kuozhan来装饰func函数 def func(who, where): print("执行原函数{}在{}蹲坑".format(who,where)) func("八戒", "厕所") # 方法二 @A() # A()为对象, def func(who, where): print("执行原函数{}在{}蹲坑".format(who,where)) func("八戒", "厕所") # 示例7 (装饰器带参数) def outer(num): def kuozhan(func): def newfunc1(self): print("厕所前,干净整齐") func(self) print("厕所后,一片狼藉") def newfunc2(self): print("厕所前,大腹便便") func(self) print("厕所后,满口雌黄") if num == 1: return newfunc1 elif num == 2: return newfunc2 elif num == 3: # 把func3方法变成属性 return "我是女性" return kuozhan class MyClass(): @outer(1) def func1(self): print("向前一小步,文明一大步") @outer(2) def func2(self): print("来也冲冲,去也冲冲") @outer(3) def func3(self): print("尿道外面,说明你短") # 示例八 (装饰类) class ZSQ(): def __init__(self,num): self.num = num def __call__(self,cls): if self.num == 1: return self.newmethod1(cls) elif self.num == 2 : return self.newmethod2(cls) def newmethod1(self,cls): def inner(): cls.age = 18 return cls() return inner def newmethod2(self,cls): def inner(): cls.method = self.method return cls() return inner def method(self): print("新方法") # 装饰器功能,为MyClass添加新属性,新方法 @ZSQ(2) class MyClass(): name = "bajie" def func(self): return "原代码" obj = MyClass() obj.method()
property
# 普通方法 class MyClass(): # 无参数,只能类来掉 def name(): print("我是普通方法") # 绑定方法(1,绑定到对象) # 自动传对象本身给self class MyClass(): def name(self): print("我是绑定方法") # 绑定方法(2,绑定到类) # 对象和类都可以调用绑定到类的方法 推荐使用类来调用 class MyClass(): @classmethod def name(self): print("我是绑定方法") # 静态方法 # 对象和类都可以掉 class MyClass(): @staticmethod def name(): print("我是静态方法方法") # property """ property 可以把方法变成属性使用 作用: 控制属性的获取,修改,删除等操作 变向的增加成员的安全性,可以通过自定义的逻辑进行控制 自动触发 : 要求名字相同,同一个名字 获取@property 设置@属性名.setter 删除@属性名.deleter """ class MyClass(): def __init__(self,name): self.name = name @property def username(self): return self.name # obj = MyClass("bajie") # error报错,此时已变成属性,属性加括号语法错误. #obj.uesrname() # print(obj.username) # 获取属性 # @username.setter def username(self,var): self.name = var obj = MyClass("bajie") obj.username = "meizhu" # 设置属性 print(obj.username) # "meizhu" @username.deleter def username(self,var): self.name = var # 删除属性 del obj.username print(obj.username) # NameError: name 'var' is not defined
反射
# 通过字符串操作类或对象 class Person: name = "bajie" __age = 18 def dump(self): print("一步登天") obj = Person() data = input("请输入要调用的成员") # 判断是否存在,返回bool值 print(hasattr(obj,data)) # 对象 print(hasattr(Person,data)) # 类 # getattr 获取成员的值 """通过对象反射出来的方法是个绑定方法,对象可执行;通过类反射出来的方法是个类方法""" print(getattr(obj,data)) # 对象 print(getattr(Person,data)) # 类 # 当获取的值不存在时,可添加默认值防止报错 print(getattr(obj,data,"该方法不存在")) # setattr 设置成员 """类设置的对象可以访问,反过来不可以""" print(setattr(obj,"变量",data)) # 对象 print(setattr(Person,"变量",data)) # 类 # delattr 删除成员 delattr(obj,"变量") delattr(Person,"变量")
反射的应用
import sys res = sys.modules["__main__"] def func1(): print("我是func1方法") def func2(): print("我是func2方法") # 综合案例 while True: # 获取当前模块的绝对路径对象 selfmodule = sys.modules["__main__"] strvar = input("请输入你要反射的方法") if hasattr(selfmodule,strvar): func = getattr(selfmodule,strvar) func() else: print("没有这个方法")