python 面向对象进阶

isinstance() 和 issubclass()
isinstance(obj,cls) 检查obj是否是类cls的对象
issubclass(sub,super) 检查sub类是否是super类的派生类

class Aoo:
    pass

class Bar(Aoo):
    pass

r = Bar()
print(isinstance(r,Aoo))
print(issubclass(Bar,Aoo))

 

__doc__

class C:
    "描述信息"
    pass

class A(C):
    pass

print(A.__doc__) # __doc__属性无法继承给子类

 

__getattribute__ 
当__getattribute__与__geetattr__同时存在,只会执行__getattribute__,除非__getattribute__在执行过程中抛出异常AttributeError

class Aoo:
    def __init__(self,x):
        self.x=x

    def __getattr__(slef,item):
        print("sb")

    def __getattribute__(self,item):
        print("getattribute")
        raise AttributeError("异常")

r = Aoo(20)
print(r.x)
r.xxx

 

__call__
对象后面加括号,触发执行
注:构造方法的执行时由创建对象触发的,即:对象=类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Aoo:
    def __call__(self,*args,**kwargs):
        print("__call__")

r = Aoo()
r() # r 的类Aoo下的__call__

 

__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为python是一门高级语言,程序员在使用时无须关心内存的分配和释放,因为此工作都是交给python解析器来执行,所以,析构函数的调用是由解析器进行垃圾回收时自动触发执行的。

class Aoo:
    def __init__(self,name):
        self.name=name
    
    def __del__(self):
        print("__del__")

r = Aoo("lwj")
print("------------")

输出结果:
    ------------
    __del__

 

__str__ 和 __repr__
str函数或者print()函数 --->obj.__str__()
repr或者交互式解析器 --->__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这两种方法的返回值必须是字符串,否则抛出异常

class Aoo:
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __str__(self):
        return "名字是%s 年龄是%s"%(self.name,self.age)
    
    def __repr__(self):
        return "名字是%s 年龄是%s"%(self.name,self.age)

r = Aoo("lwj",18)
print(r) # str(r) ---> r.__str__() ---> r.__repr__()

 

__getitem__,__setitem__,__delitem__
操作[""]和item有关

class Aoo:
    def __getitem__(self,item):
        print("getitem")
        return self.__dict__[item]
    
    def __setitem__(self,key,value):
        print("setitem")
        self.__dict__[key]=value

    def __delitem__(self,key):
        print("delitem")
        self.__dict__.pop(key)

r = Aoo()
r["name"]="sb"
print(r.__dict__)
print(r["name"])
del r["name"]
print(r.__dict__)

 

迭代器协议实现斐波那契数列

class Aoo:
    def __init__(self):
        self.a = 0
        self.b = 1

    def __item__(self):
        return self

    def __next__(self):
        self.a,self.b = self.a,self.a + self.b
        return self.a

r = Aoo()
print(r.__next__())
print(r.__next__())
print(r.__next__())
print(r.__next__())
print(r.__next__())

# for i in r:
#   print(r)

 

lin下的aa.py

class C:
    def __init__(self):
        self.name="sb"



__module__,__class__
__module__ # 查看属于哪个模块
__class__ # 查看属于哪模块中的哪个类

import lin.aa import C
c = C()
print(c.name)
print(c.__module__)
print(c.__class__)

 

__solts__
1、__solts__是什么:是一个变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2、引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3、为何使用__solts__;字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示,实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元祖或字典很类似,在__slots__中列出的属性名在内部被映射到这个数组1的指定小标上,使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那么属性名。
4、注意事项:__slots__后的类不再支持一些普通特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百个实例对象,关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性,尽管使用__slots__可以达到这样的目的,但是这个并不是它的初哀。更多的是用来作为一个内存优化工具。

class A:
    __slots__=["name","age"]

r = A()
r.name = "lwj"
r.age = 19
f.asd = 3 # 报错
print(r.name)
print(r.age)
print(r.__slots__)  # r 不再有__dict__
print(A.__slots__) # A 不再有__dict__

 

__format__ 自定义格式化方式
format_dic = {
    "ymd":"{0.year}{0.mon}{0.day}",
    "m-d-y":"{0.mon}-{0.day}-{0.year}",
    "y:m:d":"{0.year}:{0.mon}:{0.day}"
}

class Date:
    def __init__(self,year,mon,day):
        self.year = year
        self.mon = mon
        self.day = day

    def __format__(self,format_spec):
        if not format_spec or format_spec not in format_dic:
            format_spec="y:m:d"
        fn = format_dic[format_spec]
        return fn.format(self)

r = Date(2019,7,13)
print(format(r,"ymd"))
print(format(r,"y:m:d"))
print(format(r,"m-d-y"))
print(format(r,""))
print(format(r,"asddsd"))

 

描述符
定义:一般来说,描述符是一种访问对象属性时候的绑定行为,如果这个对象属性定义了__get__(),__set__(),__delte__() 一种或者几种,那么就称为描述符。
描述符在属性查找的时候可以覆盖默认的属性查找行为。如果一个对象定义了__get__()和__set__()方法,那么称之为数据描述符,如果只定义了__get__()称之为非数据描述符。
1、必须把描述符定义成这个类的属性,不能定义到构造函数中。
2、要严格遵守该优先级,优先级由高到底分别是:
1、类属性
2、数据描述符
3、实例属性
4、非数据描述符
5、找不到的属性触发__getattr__()

class Aoo:
    def __get__(self, instance, owner):
        print("get")

    def __set__(self, instance, value):
        print("set")

    def __delete__(self, instance):
        print("dlelte")

class Foo:
    name = Aoo()

r = Foo()
r.name = 1
print(r.__dict__)
r.name
del r.name
相关文章
相关标签/搜索