重载运算符

decimal.Macimal设置算术运算上下文的精度

  • 精度变化可能导致x不等于+x
import decimal
ctx = decimal.getcontext()
# 默认是28位精度
ctx.prec = 40
ont_third = decimal.Decimal('1') / decimal.Decimal('3')
one_third
one_third == +one_third
# 设为28位
# 这里如果是在notebook中,同一行算一个上下文,ctx.prec只对同一上下文起作用
ctx.prec = 28
one_third == +one_third # 此时不相等
+one_third
  • +Counter仅保留大于零的计数器
ct = Counter('abracadabra')
ct
ct['r'] = -3
ct['d'] = 0
ct
+ct # 只保留大于零的计数

重载向量加法运算符

···
    def __add__(self, other):
        try:
            pairs = itertools.zip_longest(self, other, fillvalue=0.0)
            return Vector(a + b for a, b in pairs)
        except TypeError:
            return NotImplemented
        
    def __radd__(self, other):
        return self + other
···
# 正常情况下是:v1 + (10, 20, 30)
# 而(10, 20, 30) + v1 调用的是tuple的__add__方法,由于没有Vector,会报TypeError
# 左操作数首先调用__add__方法,如果返回NotImplemented表明它不知道如何处理右操作数,那么就会调用__radd__方法
# NotImplemented是特殊的单例值,不是异常
# __radd__可以实现(10, 20, 30) + v1

重载标量乘法运算符

···
    def __mul__(self, scalar):
        if isinstance(scalar, numbers.Real):
            return Vector(n * scalar for n in self)
        else:
            return NotImplemented
        
    def __rmul__(self, scalar):
        return self * scalar
···
v1 = Vector([1.0, 2.0, 3.0])
14 * v1

改进的Vector.__eq__方法

···
    def __eq__(self, other):
        if isinstance(other, Vector):
            return (len(self) == len(other) and all(a == b for a, b in zip(self, other)))
        else:
            return NotImplemented
···
va = Vector([1.0, 2.0, 3.0])
vb = Vector(range(1, 4))
va == vb
vc = Vector([1, 2])
t3 = (1, 2, 3)
va == t3

增量赋值运算符

  • 增量赋值不会修改不可变目标,而是新建实例,然后重新绑定
    如果类没有实现__iadd__()方法,a += b 与 a = a + b 一样,对不可变类型是预期的行为。
v1 = Vector([1, 2, 3])
v1_alias = v1 # 保留v1副本v1_alias
id(v1)
v1 += Vector([4, 5, 6])
v1 
id(v1) # 此时的v1 id改变了 
v1_alias # 原来的实例没有改变

v1 *= 11
v1
id(v1) # 与增量加法一样
v1_alias

自增运算符

import random
import abc

class Tombola(abc.ABC):
    
    @abc.abstractmethod
    def load(self, iterable):
        """"""
        
    @abc.abstractmethod
    def pick(self):
        """"""
    def loaded(self):
        return bool(self.inspect())
    
    def inspect(self):
        items = []
        while True:
            try:
                items.append(self.pick())
            except LookupError:
                break
        self.load(items)
        return tuple(sorted(items))
    
class BingoCage(Tombola):
    def __init__(self, items):
        self._randomizer = random.SystemRandom()
        self._items = []
        self.load(items)
    
    def load(self, items):
        self._items.extend(items)
        self._randomizer.shuffle(self._items)
        
    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError('pick from empty BingoCage')
            
    def __call__(self):
        self.pick()
        
import itertools

class AddableBingoCage(BingoCage):
    
    def __add__(self, other):
        if isinstance(other, Tombola):
            return AddableBingoCage(self.inspect() + other.inspect())
        else:
            return NotImplemented
        
    def __iadd__(self, other):
        if isinstance(other, Tombola):
            other_iterable = other.inspect()
        else:
            try:
                other_iterable = iter(other)
            except TypeError:
                self_cls = type(self).__name__
                msg = "right operand in += must be {!r} or an iterable"
                raise TypeError(msg.format(self_cls))
        self.load(other_iterable)
        return self
    
# 加运算符
vowels = 'AEIOU'
globe = AddableBingoCage(vowels)
globe.inspect()
globe2 = AddableBingoCage('XYZ')
globe3 = globe + globe2
len(globe3.inspect())
void = globe + [10, 20] # AddableBingoCage实例无法与列表相加
# 自加运算符
globe += globe2
globe.inspect()
globe += ['M', 'N']
globe.inspect()
globe is globe_orig
globe += 1 # AddableBingoCage实例不能与非可迭代对象相加

总结

  • decimal.Decimal设置上下文精度
  • 重加载__add__方法,NotImplemented单例值,以及__radd__方法的作用
  • 使用isinstance判断重载标量乘法运算符的参数检查numbers.Real抽象基类,numbers.Real涵盖类我们所需的全部类型
  • __eq__方法中使用isinstance判断类型
  • 增量赋值运算符对可变或不可变实例的行为
  • 加运算符和自加运算符的差别

流畅的Python

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值