面向对象编程相关

每日一记

_类名+私有成员                     # 直接访问私有成员
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("没有这个方法")

  

 

posted @ 2020-08-03 21:12  bajie_new  阅读(134)  评论(0编辑  收藏  举报