面向对象2

目录

面向对象之反射

面向对象之内置方法

 __setattr__ ,__getattr__,__delattr__

 item系列

 为类设置输出 __str__,__repr__,__format__

 析构方法  __del__

描述符(__get__, __set__, __delete__)

描述符

作用

注意事项

 

面向对象之反射

参考 :https://www.cnblogs.com/yuliangkaiyue/p/9516427.html

面向对象之内置方法

 __setattr__ ,__getattr__,__delattr__

class Foo:
    x = 1

    def __init__(self, y):
        self.y = y

    def __setattr__(self, key, value):
        print('----->setattr')
        # self.key =value   #等同于赋值,不断触发setattr,造成递归循环
        self.__dict__[key] = value

    def __getattr__(self, item):
        print('------->getattr')
        print('%s不存在' % item)

    def __delattr__(self, item):
        print('-------delete')
        # del self.item   # 同上理
        self.__dict__.pop(item)


f = Foo(6)
print(f.__dict__)  


f.z        

f.z =2
print(f.__dict__)

f.__dict__['a'] = 10  # 直接调用字典赋值并不会触发setattr方法
del f.a
print(f.__dict__)


执行结果:  
----->setattr    因为初始化触发了__setattr__方法执行
{'y': 6}
------->getattr  属性Z不存在,触发了getattr方法,所以找不到属性才触发
z不存在
----->setattr    
{'y': 6, 'z': 2}
-------delete    
{'y': 6, 'z': 2}

 item系列

__setitem__,__getitem__,__delitem__ 在功能上和上边的有些类似,但是又稍有不同。item系列的特点是把类操作弄得像字典一样。

class Foo:
    def __init__(self, name):
        self.name = name

    def __setitem__(self, key, value):
        print('from setitem')
        self.__dict__[key]=value

    def __getitem__(self, item):
        print('from getitem')
        print(self.__dict__.get(item))

    def __delitem__(self, key):
        print('from delitem del 类[key]')
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print('from delattr  del 类.属性')
        self.__dict__.pop(item)


f1=Foo('李四')
print(f1.__dict__)
f1['age']=18
f1['sex']='男'
print(f1.__dict__)
del f1.age
del f1['sex']
f1['home']='滨州'
print(f1.__dict__)

# {'name': '李四'}
# from setitem
# from setitem
# {'name': '李四', 'age': 18, 'sex': '男'}
# from delattr
# from delitem
# from setitem
# {'name': '李四', 'home': '滨州'}

 为类设置输出 __str__,__repr__,__format__

改变对象的字符串显示__str__,__repr__

自定制格式化字符串__format__

format_dict={
    'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
    'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)

# from repr:  School(oldboy1,北京)
# from str:  (oldboy1,北京)
# (oldboy1,北京)
'''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''
print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'a'))

# oldboy1-北京-私立
# 私立:oldboy1:北京
# 私立/北京/oldboy1
# oldboy1-北京-私立

当然也可以在__str__()中调用format方法,以显示想要的效果 

 析构方法  __del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__。简而言之,操作系统资源要通过代码手动调用管理的,用完就关闭它,用del方式可以防止忘记关闭操作系统资源而出错,也使代码简洁。

class Foo:

    def __del__(self):
        print('回收')

f1=Foo()
del f1
print('------->')

#输出结果
# 回收
# ------->

描述符(__get__, __set__, __delete__)

描述符

本质就是一个新式类,在这个类中至少实现了__get__, __set__, __delete__中的一个,这也被称为描述符协议。

__get__():调用一个属性时触发

 __set__():为一个属性赋值时触发

 __delete__():采用del删除一个属性时触发

作用

描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

class Foo:
    def __get__(self, instance, owner):
        print('触发get')
    def __set__(self, instance, value):
        print('触发set')
    def __delete__(self, instance):
        print('触发delete')


f1=Foo()
f1.name='egon'
f1.name
del f1.name

但是,这样子并没有触发三个方法的执行

那如何才会触发执行呢?

#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str调用')
    def __set__(self, instance, value):
        print('Str设置...')
    def __delete__(self, instance):
        print('Str删除...')

#描述符Int
class Int:
    def __get__(self, instance, owner):
        print('Int调用')
    def __set__(self, instance, value):
        print('Int设置...')
    def __delete__(self, instance):
        print('Int删除...')

class People:
    name=Str()
    age=Int()
    def __init__(self,name,age): #name被Str类代理,age被Int类代理,
        self.name=name
        self.age=age

#何地?:定义成另外一个类的类属性

#何时?:且看下列演示

p1=People('alex',18)

#描述符Str的使用
p1.name
p1.name='egon'
del p1.name

#描述符Int的使用
p1.age
p1.age=18
del p1.age

#我们来瞅瞅到底发生了什么
print(p1.__dict__)
print(People.__dict__)

#补充
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__)


执行结果:

Str设置...
Int设置...
Str调用
Str设置...
Str删除...
Int调用
Int设置...
Int删除...
{}
{'__module__': '__main__', 'name': <__main__.Str object at 0x0000000A51974438>, 'age': <__main__.Int object at 0x0000000A51ACFC18>, '__init__': <function People.__init__ at 0x0000000A51AD3BF8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
True
True

注意事项

一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
           1.类属性
           2.数据描述符
           3.实例属性
           4.非数据描述符
           5.找不到的属性触发__getattr__()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值