目录
0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!
在Python2.2之前,类和类型是分开的,在Python2.2之后,作者试图对这两个东西进行统一,做法就是将 int()、float()、str()、list()、tuple() 这些 BIF 转换为工厂函数,那什么是工厂函数呢? 我们试图演示一下:
>>> type(len)
<class 'builtin_function_or_method'>
len()是一个普通的内置函数,返回类似也告诉了我们这一点,但是
>>> type(int)
<class 'type'>
>>> type(list)
<class 'type'>
然后我们发现:
>>> class C:
pass
>>> type(C)
<class 'type'>
所以,工厂函数就是类对象。
Python的魔法方法还提供了让你自定义对象的数值处理,通过对我们这些魔法方法进行重写,你可以自定义任何对象间的算术运算。
add(self, other) | 定义加法的行为:+ |
---|---|
sub(self, other) | 定义减法的行为:- |
mul(self, other) | 定义乘法的行为:* |
truediv(self, other) | 定义真除法的行为:/ |
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 "<pyshell#21>", line 1, in <module>
foo.foo()
TypeError: 'str' object is not callable
3. 写出下列算术运算符对应的魔法方法:
看上面的表格
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)风格。
鸭子风格
动动手
0. 我们都知道在 Python 中,两个字符串相加会自动拼接字符串,但遗憾的是两个字符串相减却抛出异常。因此,现在我们要求定义一个 Nstr 类,支持字符串的相减操作:A – B,从 A 中去除所有 B 的子字符串。
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'
class Nstr(str):
def __sub__(self,other):
return self.replace(other,'')
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
可以看出这个类的对象应该有一个属性,就是各个Ascll码的和,
理应在init函数里初始化
class Nstr(str):
def __init__(self,arg):
if isinstance(arg,str):
self.ascll=0
for i in arg:
self.ascll+=ord(i)
else:
print("重新输入:")
#int要不要都行,因为ascll这个变量定义的时候就已经是整型了,使用的+也是int默认的__add__
def __add__(self,other):
return int(self.ascll)+int(other.ascll)
def __sub__(self,other):
return int(self.ascll)-int(other.ascll)
def __mul__(self, other):
return self.ascll* other.ascll
def __truediv__(self, other):
return self.ascll / other.ascll
def __floordiv__(self, other):
return self.ascll // other.ascll
技巧:利用new算出Ascii码后在转为Int
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)