《零基础入门学习Python》第042讲(魔法方法:算术运算)

目录
0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!
测试题
0. 自 Python2.2 以后,对类和类型进行了统一,做法就是将 int()、float()、str()、list()、tuple() 这些 BIF 转换为工厂函数。请问所谓的工厂函数,其实是什么原理?
1. 当实例对象进行加法操作时,会自动调用什么魔法方法?
2. 下边代码有问题吗?(运行起来似乎没出错的说^_^)
3. 写出下列算术运算符对应的魔法方法:
4. 以下代码说明 Python 支持什么风格?
动动手
0. 我们都知道在 Python 中,两个字符串相加会自动拼接字符串,但遗憾的是两个字符串相减却抛出异常。因此,现在我们要求定义一个 Nstr 类,支持字符串的相减操作:A – B,从 A 中去除所有 B 的子字符串。
1. 移位操作符是应用于二进制操作数的,现在需要你定义一个新的类 Nstr,也支持移位操作符的运算:
2. 定义一个类 Nstr,当该类的实例对象间发生的加、减、乘、除运算时,将该对象的所有字符串的 ASCII 码之和进行计算:
0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式! 在Python2.2之前,类和类型是分开的,在Python2.2之后,作者试图对这两个东西进行统一,做法就是将 int()、float()、str()、list()、tuple() 这些 BIF 转换为工厂函数,那什么是工厂函数呢?
我们试图演示一下:

>>> type(len)

len()是一个普通的内置函数,返回类似也告诉了我们这一点,但是
>>> type(int) >>> type(list)

然后我们发现:
>>> class C: pass>>> type(C)

所以,工厂函数就是类对象。
Python的魔法方法还提供了让你自定义对象的数值处理,通过对我们这些魔法方法进行重写,你可以自定义任何对象间的算术运算。
__add__(self, other)
定义加法的行为:+
__sub__(self, other)
定义减法的行为:-
__mul__(self, other)
定义乘法的行为:*
__truediv__(self, other)
定义真除法的行为:/
【《零基础入门学习Python》第042讲(魔法方法:算术运算)】__floordiv__(self, other)
定义整数除法的行为://
__mod__(self, other)
定义取模算法的行为:%
__divmod__(self, other)
定义当被 divmod() 调用时的行为,divmod(a, b)返回一个元组:(a//b, a%b)
__pow__(self, other[, modulo])
定义当被 power() 调用或 ** 运算时的行为
__lshift__(self, other)
定义按位左移位的行为:<<
__rshift__(self, other)
定义按位右移位的行为:>>
__and__(self, other)
定义按位与操作的行为:&
__xor__(self, other)
定义按位异或操作的行为:^
__or__(self, other)
定义按位或操作的行为:|
例如:
>>> class New_int(int): def __add__(self, other): return int.__sub__(self, other) def __sub__(self, other): return int.__add__(self, other) >>> a = New_int(3) >>> b = New_int(5) >>> a + b -2 >>> a - b 8

发现了没,我在这里对原有 int 的加法和减法进行了改写,把加法变为减法,减法变为加法。
测试题 0. 自 Python2.2 以后,对类和类型进行了统一,做法就是将 int()、float()、str()、list()、tuple() 这些 BIF 转换为工厂函数。请问所谓的工厂函数,其实是什么原理? 答:工厂函数,其实就是一个类对象。当你调用他们的时候,事实上就是创建一个相应的实例对象。
# a 和 b 是工厂函数(类对象) int 的实例对象 >>> a = int('123') >>> b = int('345') >>> a + b 468

1. 当实例对象进行加法操作时,会自动调用什么魔法方法? 答:对象 a 和 b 相加时(a + b),Python 会自动根据对象 a 的 __add__ 魔法方法进行加法操作。
2. 下边代码有问题吗?(运行起来似乎没出错的说^_^)
class Foo: def foo(self): self.foo = "I love FishC.com!" return self.foo>>> foo = Foo() >>> foo.foo() 'I love FishC.com!'

答:这绝对是一个温柔的陷阱,这种BUG比较难以排查,所以一定要注意:类的属性名和方法名绝对不能相同!如果代码这么写,就会有一个难以排查的BUG出现了:
class Foo: def __init__(self): self.foo = "I love FishC.com!" def foo(self): return self.foo>>> foo = Foo() >>> foo.foo() Traceback (most recent call last): File "", line 1, in foo.foo() TypeError: 'str' object is not callable

3. 写出下列算术运算符对应的魔法方法:
运算符
对应的魔法方法
+
__add__(self, other)
-
__sub__(self, other)
*
__mul__(self, other)
/
__truediv__(self, other)
//
__floordiv__(self, other)
%
__mod__(self, other)
divmod(a, b)
__divmod__(a, b)
**
__pow__(self, other[, modulo])
<<
__lshift__(self, other)
>>
__rshift__(self, other)
&
__and__(self, other)
^
__xor__(self, other)
|
__or__(self, other)
4. 以下代码说明 Python 支持什么风格?
def calc(a, b, c): return (a + b) * c>>> a = calc(1, 2, 3) >>> b = calc([1, 2, 3], [4, 5, 6], 2) >>> c = calc('love', 'FishC', 3) >>> print(a) 9 >>> print(b) [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6] >>> print(c) loveFishCloveFishCloveFishC

答:说明 Python 支持鸭子类型(duck typing)风格。
详见:Python扩展阅读:鸭子类型(duck typing)
动动手 0. 我们都知道在 Python 中,两个字符串相加会自动拼接字符串,但遗憾的是两个字符串相减却抛出异常。因此,现在我们要求定义一个 Nstr 类,支持字符串的相减操作:A – B,从 A 中去除所有 B 的子字符串。 示例:
>>> a = Nstr('I love FishC.com!iiiiiiii') >>> b = Nstr('i') >>> a - b 'I love FshC.com!'

答:只需要重载 __sub__ 魔法方法即可。
class Nstr(str): def __sub__(self, other): return self.replace(other, '')

1. 移位操作符是应用于二进制操作数的,现在需要你定义一个新的类 Nstr,也支持移位操作符的运算:
>>> a = Nstr('I love FishC.com!') >>> a << 3 'ove FishC.com!I l' >>> a >> 3 'om!I love FishC.c'

答:只需要重载 __lshift__ 和 __rshift__ 魔法方法即可。
class Nstr(str): def __lshift__(self, other): return self[other:] + self[:other]def __rshift__(self, other): return self[-other:] + self[:-other]

2. 定义一个类 Nstr,当该类的实例对象间发生的加、减、乘、除运算时,将该对象的所有字符串的 ASCII 码之和进行计算:
>>> a = Nstr('FishC') >>> b = Nstr('love') >>> a + b 899 >>> a - b 23 >>> a * b 201918 >>> a / b 1.052511415525114 >>> a // b 1

代码清单:
class Nstr: def __init__(self, arg=''): if isinstance(arg, str): self.total = 0 for each in arg: self.total += ord(each) else: print("参数错误!")def __add__(self, other): return self.total + other.totaldef __sub__(self, other): return self.total - other.totaldef __mul__(self, other): return self.total * other.totaldef __truediv__(self, other): return self.total / other.totaldef __floordiv__(self, other): return self.total // other.total

当然,你还可以这样做:
class Nstr(int): def __new__(cls, arg=0): if isinstance(arg, str): total = 0 for each in arg: total += ord(each) arg = total return int.__new__(cls, arg)

另有不明白的,可参阅->Python魔法方法详解

    推荐阅读