类型转换魔法
类型转换魔法其实就是实现了str、int等工厂函数的结果,通常这些函数还有类型转换的功能,下面是一些相关的魔法方法:
-
__int__(self)
-
转换成整型,对应int函数。
-
__long__(self)
-
转换成长整型,对应long函数。
-
__float__(self)
-
转换成浮点型,对应float函数。
-
__complex__(self)
-
转换成 复数型,对应complex函数。
-
__oct__(self)
-
转换成八进制,对应oct函数。
-
__hex__(self)
-
转换成十六进制,对应hex函数。
-
__index__(self)
-
首先,这个方法应该返回一个整数,可以是int或者long。这个方法在两个地方有效,首先是 operator 模块中的index函数得到的值就是这个方法的返回值,其次是用于切片操作,下面会专门进行代码演示。
-
__trunc__(self)
-
当 math.trunc(self) 使用时被调用.__trunc__返回自身类型的整型截取 (通常是一个长整型).
-
__coerce__(self, other)
-
实现了类型的强制转换,这个方法对应于 coerce 内建函数的结果(python3.0开始去掉了此函数,也就是该魔法方法也没意义了,至于后续的版本是否重新加入支持,要视官方而定。)
- 这个函数的作用是强制性地将两个不同的数字类型转换成为同一个类型,例如:
#coerce(x, y) -> (x1, y1)
方法返回一个元祖,分别对应转换后的两个数字。其优先级为:复数>浮点数>长整型>整型。在转换的时候,会转换为两个参数中优先级高的类型。当转换无法完成的时候,会触发 TypeError。
而当我们定义这个魔法方法时,如果转换无法完成,应该返回None。
这里有个重要的机制,当python进行运算的时候,如 1 + 1.0 时,会先调用 coerce 函数将其转换为同一个类型,然后再进行运行,这也就是为什么 1 + 1.0 = 2.0,因为转换之后实际进行的运算为 1.0 +1.0。得到这样的结果也就不奇怪了。
代码示例:
class Foo(object):
def __init__(self, x):
self.x = x
def __int__(self):
return int(self.x) + 1
def __long__(self):
return long(self.x) + 1
a = Foo(123)
print int(a)
print long(a)
print type(int(a))
print type(long(a))
这里要注意一点,魔法方法的返回值必须符合预期,例如 __int__ 就应该返回一个 int 类型,如果我们任性地返回其他类型,例如字符串(str)、列表(list)等,会报错。
def __int__(self):
return str(self.x)
def __int__(self):
return list(self.x)
但是 int 可以返回 long,而 long 返回 int 时会自动被处理成 long:
class Foo(object):
def __init__(self, x):
self.x = x
def __int__(self):
return long(self.x) + 1
def __long__(self):
return int(self.x) + 1
a = Foo(123)
print int(a)
print long(a)
print type(int(a))
print type(long(a))
以上发生在python2.7.11上,这是一个很奇怪的行为,以至于我认为其可能是一个 BUG,总之我们在使用的时候要注意要返回对应的类型就是了,以免出错。
__index__(self):
首先是对应于operator.index(),operator.index(a)就相当于a.__index__():
import operator
class Foo(object):
def __init__(self, x):
self.x = x
def __index__(self):
return self.x + 1
a = Foo(10)
print operator.index(a)
另一个是很神奇的特效,当其用于序列中时:
class Foo(object):
def __init__(self, x):
self.x = x
def __index__(self):
return 3
a = Foo('scolia')
b = [1, 2, 3, 4, 5]
print b[a]
print b[3]
可以作为索引一样使用,可进行切片操作:
class Foo(object):
def __init__(self, x):
self.x = x
def __index__(self):
return int(self.x)
a = Foo('1')
b = Foo('3')
c = [1, 2, 3, 4, 5]
print c[a:b]
其实切片内部使用的函数 slice 对其进行了处理,有兴趣的同学可以去了解这个函数:
a = Foo('1')
b = Foo('3')
c = slice(a, b)
print c
d = [1, 2, 3, 4, 5]
print d[c]
__coerce__(self, other):
代码示例:
class Foo(object):
def __init__(self, x):
self.x = x
def __coerce__(self, other):
return self.x, str(other.x)
class Boo(object):
def __init__(self, x):
self.x = x
def __coerce__(self, other):
return self.x, int(other.x)
a = Foo('123')
b = Boo(123)
print coerce(a, b)
print coerce(b, a)
总结:是调用了第一个参数的魔法方法。
类的表示 :
类的表示其实就是对外的特征,例如使用print语句时,打印出来的是什么,其实本质上也是对应函数的输出: