python 读书笔记 (六) 异常描述符

异常

可用 sys.exc_info() 获取调用堆栈上的最后异常信息

def test():
    try:
        raise KeyError('KEY ERROR')
    except:
        print(sys.exc_info())
        exc_type, exc_value, traceback = sys.exc_info()
        sys.excepthook(exc_type, exc_value, traceback)

test()

断言

def test(n):
    assert n > 0, 'n > 0 '
    print(n)
test(-1)
AssertionError: n > 0 

很简单,当条件不符时,抛出 AssertionError 异常。assert 受只读参数 __debug__ 控制,可以在启动时添加 "-O" 参数使其失效

python -O main.py

描述符

描述符协议:

def __get__(self, instance, owner)  --> value
def __get__(self, instance, owner) --> None
def __delete__(self, instance)  --> None

描述符对象以类型(owner class) 成员的方式出现,且最少要实现一个协议方法。最常见的描述符有 property, staticmethod, classmethod。访问描述符类型成员时,解释器自动调用与行相对应的协议方法。

  • 实现__get__ 和 __set__ 方法,称为 资料描述器 data descriptor
  • 仅有 __get__方法的,称为 非资料描述器 non-data descriptor
  • __get__ 对 owner_class、owner_instance 访问有效
  • __set__、__delete__ 仅对 owner_instance 访问有效
  • 资料描述器总是比实例字典优先。
  • 非资料描述器可能被实例字典重写。(非资料描述器不如实例字典优先)
class RevealAccess(object):
    """A data descriptor that sets and returns values
       normally and prints a message logging their access.
    """

    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print('get: Retrieving', self.name)
        return self.val

    def __set__(self, obj, val):
        print('set: Updating', self.name)
        self.val = val

class Data(object):
    d = RevealAccess(10, 'var x')
    y = 5

m = Data()


>>> m.d
get: Retrieving var x
10
>>> m.d = 20
set: Updating var x
>>> m.d
get: Retrieving var x
20
>>> m.y
5

obj.d 会在 obj 的字典中找 d ,如果 d 定义了 __get__ 方法,那么 d.__get__(obj) 会依据下面的优先规则被调用

对于对象来讲,方法 object.__getattribute__() 把 b.x 变成 type(b).__dict__['x'].__get__(b, type(b)) 。具体实现是依据这样的优先顺序:资料描述器优先于实例变量,实例变量优先于非资料描述器,__getattr__()方法(如果对象中包含的话)具有最低的优先级

对于类来讲,方法 type.__getattribute__() 把 B.x 变成 B.__dict__['x'].__get__(None, B)

方法和函数

 

>>> class Data(object):
...     def test(self): print('test')
... 
>>> d = Data()
>>> d.test                                 # 只有 bound method 才会隐式传递 self。
<bound method Data.test of <__main__.Data object at 0x7f23c01b8160>>

>>> Data.test.__get__(d, Data)             # 向 __get__ 传递 instance 参数。
<bound method Data.test of <__main__.Data object at 0x7f23c01b8160>>

>>> Data.test                              # unbound method 需显式传递 self。
<function Data.test at 0x7f23bfaeeb70>

>>> Data.test.__get__(None, Data)           # instance 为 None
<function Data.test at 0x7f23bfaeeb70>

>>> bm = Data.test.__get__(d,Data)

>>> bm.__self__                               # __get__ instance 参数,也就是 self。
<__main__.Data object at 0x7f23c01b8160>

>>> bm.__call__()                             # __call__ 内部替我们传递 self !
test

 

转载于:https://my.oschina.net/acutesun/blog/978880

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值