Python中的特殊方法
Python的特殊方法定义在 class中,不需要直接进行显示调用,Python的某些操作符或者函数会自动调用对应的特殊方法。这些方法如:__str__()
、__len__()
、__cmp__()
等。下面这些更全面:
正确实现特殊方法:首先只需要编写用到的特殊方法;其次有关联性的特殊方法必须都实现,如编写了特殊方法 __getattr__()
,那么特殊方法 __setattr__()
和 __delattr__()
也必须实现。
__str__
和 __repr__
方法:
先来看代码示例:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def __str__(self):
return '(Student: %s, %s, %s)' % (self.name, self.gender, self.score)
__repr__ = __str__
s = Student('Bob', 'male', 88)
print s # 输出结果为:(Student: Bob, male, 88)
__str__()
方法用来把一个类变成一个字符串输出,在 class中定义该方法,可以使类按照我们想要的格式进行输出。__str__()
用于显示给用户,而__repr__()
用于显示给开发人员。
__cmp__()
方法:
还是先看示例:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return '(%s: %s)' % (self.name, self.score)
__repr__ = __str__
def __cmp__(self, s): # 定义__cmp__()方法
if self.name < s.name: # 比较规则(和默认比较规则相同)
return -1
elif self.name > s.name:
return 1
else:
return 0
上述 Student 类实现了__cmp__()
方法,__cmp__
用实例自身 self和传入的实例 s 进行比较,如果 self 应该排在前面,就返回 -1,如果 s 应该排在前面,就返回1,如果两者相当,返回 0。
比较结果:
L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 77)]
print sorted(L) # [(Alice: 77), (Bob: 88), (Tim: 99)] 按照姓名排序
升级版本:先判断类型,然后按照分数排序,分数相同按照姓名排序。如下:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return '(%s: %s)' % (self.name, self.score)
__repr__ = __str__
def __cmp__(self, s):
if not isinstance(s, Student):
return -1
else:
return -cmp(self.score, s.score) or cmp(self.name, s.name)
L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
print sorted(L) # 结果为:[(Alice: 99), (Tim: 99), (Bob: 88)]
注意:在 Python3.4.3版本之后,已经没有cmp()
函数了。被 operator
模块中的一系列函数取代,并且使用时需要导入,如下:
import operator
a, b = 'Hello', 'name'
operator.lt(a, b) # 小于比较
operator.le(a, b) # 小于等于比较
operator.eq(a, b) # 等于比较
operator.ne(a, b) # 不等于比较
operator.gt(a, b) # 大于比较
operator.ge(a, b) # 大于等于比较
# 可在类中编写的内置函数如下:
operator.__lt__(a, b) # 小于比较
operator.__le__(a, b) # 小于等于比较
operator.__eq__(a, b) # 等于比较
operator.__ne__(a, b) # 不等于比较
operator.__gt__(a, b) # 大于比较
operator.__ge__(a, b) # 大于等于比较
__len__()
函数:
如果一个类表现得像一个list,要获取有多少个元素,就得用 len()
函数。要让 len()
函数工作正常,类必须提供一个特殊方法__len__()
,它返回元素的个数。代码示例如下:
class Fib(object):
def __init__(self, num):
a, b, l= 0, 1, []
for item in range(int(num)):
l.append(a)
a, b = b, a+b
self.nums = l
def __len__(self):
return len(self.nums)
def __str__(self):
return str(self.nums)
f = Fib(10)
print f # 输出结果为:[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
print len(f) # 输出结果为:10
Python 中的数学运算
Python 提供的基本数据类型 int、float 可以做整数和浮点的四则运算以及乘方等运算。但是,四则运算不局限于int和float,还可以是有理数、矩阵等。
通过定制类,计算有理数(分数形式)的加减乘除四则运算。分别编写__add__()
、__sub__()
、__mul__()
、__div__()
函数。代码示例如下:
def gcd(a, b):
return gcd(b, a%b) if b!=0 else a
class Rational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __add__(self, r):
return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
def __sub__(self, r):
return Rational(self.p * r.q - self.q * r.p, self.q * r.q)
def __mul__(self, r):
return Rational(self.p * r.p, self.q * r.q)
def __div__(self, r):
return Rational(self.p * r.q, self.q * r.p)
def __str__(self):
temp = gcd(self.p, self.q)
return '%s/%s' % (self.p/temp, self.q/temp)
__repr__ = __str__
r1 = Rational(1, 2)
r2 = Rational(1, 4)
print r1 + r2 # 3/4
print r1 - r2 # 1/4
print r1 * r2 # 1/8
print r1 / r2 # 2/1
Python中的类型转换
Rational类实现了有理数运算,还可以实现int()
和float()
类型转换,示例如下:
class Rational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __int__(self):
return self.p // self.q
def __float__(self):
return self.p*1.0 / self.q
print float(Rational(7, 2)) # 3.5
print int(Rational(1, 3)) # 0
Python中@property运用:
Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把设置和获取属性的 get/set
方法“装饰”成属性调用:
class Student(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self): # 实现 get()方法
return self.__score
@score.setter
def score(self, score): # 实现 set()方法
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
@property
def grade(self): # 实现 grade属性的 get()方法
if self.__score < 60: return 'C'
elif self.__score <80: return 'B'
else: return 'A'
s = Student('Bob', 59)
print s.grade # 输出为:C
s.score = 99 # 输出为:A
print s.grade
s = Student('Bob', 59)
s.score = 60
print s.score # 60
s.score = 1000
"""
Traceback (most recent call last):
...
ValueError: invalid score
"""
Python中限制属性函数__slots__()
:
__slots__
是指一个类允许的属性列表,它的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__
也能节省内存。
class Person(object):
__slots__ = ('name', 'gender')
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Student(Person):
__slots__ = ('score') # 实际上允许的属性还有从父类继承来的 'name' 和 'gender'
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score # 99
Python中对类调用函数__call__()
:
在Python中,函数其实是一个对象,所有的函数都是可调用对象。
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()
。
class Fib(object):
def __call__(self, num):
a, b, l= 0, 1, []
for item in range(int(num)):
l.append(a)
a, b = b, a+b
return l
f = Fib() # 获取类对象
print f(10) # 像调用函数一样,调用类