第十六节:内置函数补充

通过  .  的方式访问、设置、删除对象属性的时候会触发类的内置属性__getattr__、__setattr__、__delattr__

class Dog:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __getattr__(self, item):#在获取不存在的函数属性的时候会触发
        print("执行的是getattr")
    def __setattr__(self, key, value):#在设置对象属性的时候会触发
        self.__dict__[key] = value
    def __delattr__(self, item):#在删除对象属性的时候会触发的内置函数
        self.__dict__.pop(item)
    def run(self):
        print("%s今年%s"%(name,age)

 def __getattribute__(self, item):  #获取存在的函数属性的时候执行该函数
      raise AttributeError('抛出异常')#在获取不存在的函数属性的时候会抛出异常给__getattr__
View Code

通过键值的方式访问、设置、删除对象属性的时候会触发类的内置属性__getitem__、__setitem__、__delitem__

class Foo:
    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)

f1=Foo()
print(f1.__dict__)
f1['name']='sss'
print(f1['name'])
del f1['name']
执行结果如下:
{}
setitem
getitem
sss
delitem
View Code

类的内置属性__str__和__repr__:

print函数在执行的时候实际上就是在调用str()函数
在打印对象的时候实际上是在调用内置函数 str()函数 就等于  f1.__str__()  
class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return '名字是%s 年龄是%s' %(self.name,self.age)
#
# f1=Foo('egon',18)
# print(f1) #str(f1)--->f1.__str__()
#
# x=str(f1)
# print(x)
#
# y=f1.__str__()
# print(y)
这三个结果是一样的,这个很重要,可以定义输出

在解释器中打印的时候触发的是__repr__
class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    # def __str__(self):
    #     return '这是str'
    def __repr__(self):
        return '名字是%s 年龄是%s' %(self.name,self.age)

f1=Foo('egon',19)
#repr(f1)---->f1.__repr__()
print(f1) #str(f1)---》f1.__str__()------>f1.__repr__()

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

类的内置属性__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):
        print('我执行啦')
        print('--->',format_spec)
        if not format_spec or format_spec not in format_dic:
            format_spec='ymd'
        fm=format_dic[format_spec]
        return fm.format(self)#必须有返回值
d1=Date(2016,12,26)
# format(d1) #d1.__format__()  #内置方法可以直接用函数调用
# print(format(d1))
print(format(d1,'ymd'))
print(format(d1,'y:m:d'))
print(format(d1,'m-d-y'))
print(format(d1,'m-d:y'))
print('===========>',format(d1,'asd'))
View Code

类的内置属性__slots__:

应用场景:属性较少实例较多的情况下,可用该方法(慎用)
这样定义实例化的实例就没有属性字典了,
class Foo:
    __slots__=['name','age']  #{'name':None,'age':None}#只能定义slots提供的属性
    # __slots__='name' #{'name':None,'age':None}#实例只能创建仅限一个属性

f1=Foo()
# f1.name='egon'
# print(f1.name)

# f1.age=18  #--->setattr----->f1.__dict__['age']=18

# print(f1.__dict__)
print(Foo.__slots__)
print(f1.__slots__)
f1.name='egon'
f1.age=17
print(f1.name)
print(f1.age)
View Code

 类的内置属性__doc__

class Foo:
    '我是描述信息'
    pass

class Bar(Foo):  #该属性不可继承,如果没有定义,默认是none
    pass

 类的内置属性__module__和__class__

 查看实例属于哪个模块和类

类的内置属性析构函数__del__

垃圾回收机制,在实例被删除的时候会触发,删除实例属性的时候不会触发,当程序执行完毕的时候会自动触发该机制回收内存

类的内置属性__call__

class Foo:
    def __call__(self, *args, **kwargs):
        print('实例执行啦 obj()')

f1=Foo()

f1() #f1的类Foo 下的__call__

Foo() #Foo的类 xxx下的__call__
一个对象之所有可以加上()运行,就是因为他调用了__call__方法

类的内置方法__iter__和__next__

class Foo:
    def __init__(self,n):
        self.n=n
    def __iter__(self):
        return self

    def __next__(self):
        if self.n == 13:
            raise StopIteration('终止了')#跳出异常
        self.n+=1
        return self.n

# l=list('hello')
# for i in l:
#     print(i)
f1=Foo(10)
# print(f1.__next__())
# print(f1.__next__())
# print(f1.__next__())
# print(f1.__next__())

for i in f1:  # obj=iter(f1)------------>f1.__iter__()
     print(i)  #obj.__next_()#for循环会自动捕捉异常终止循环

描述符__get__、__set__、__del__:描述符的作用是用来代理另外一个类的属性的

class Foo:#数据描述符
    def __get__(self, instance, owner):
        print('===>get方法')
    def __set__(self, instance, value):
        print('===>set方法',instance,value#这里的instance就是实例化的对象,value就是传的值
        instance.__dict__['x']=value #b1.__dict__
    def __delete__(self, instance):
        print('===>delete方法')


class Bar:
    x=Foo() #在何地?#只要是在这个给类或者这个类实例化的的对象中对x进行操作,就会触发描述符的相关方法
    def __init__(self,n):
        self.x=n #b1.x=10  #触发数据描述符,因为x被数据据描述符代理了
b1=Bar(10)
 
Bar.x=6    #在定义类的属性的时候,优先级高于数据描述符,不会触发数据描述,会负载之前定义的描述符属性,通过属性字典可以查看
数据描述符定义:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()

1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
3 描述符分两种
一 数据描述符:至少实现了__get__()和__set__()
二 非数据描述符:没有实现__set__()
原文地址:https://www.cnblogs.com/sxdpython/p/12747419.html