Python中的特殊方法

Python的特殊方法定义在 class中,不需要直接进行显示调用,Python的某些操作符或者函数会自动调用对应的特殊方法。这些方法如:__str__()__len__()__cmp__()等。下面这些更全面:

python中把bute转换为str_函数式编程


正确实现特殊方法:首先只需要编写用到的特殊方法;其次有关联性的特殊方法必须都实现,如编写了特殊方法 __getattr__(),那么特殊方法 __setattr__()__delattr__()也必须实现。

__str____repr__方法:

先来看代码示例:

class Person(object):

    def __init__(self, name, gender):
         = 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.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):
         = name
        self.score = score
    def __str__(self):
        return '(%s: %s)' % (, self.score)
    __repr__ = __str__

    def __cmp__(self, s):         # 定义__cmp__()方法
        if  < :    # 比较规则(和默认比较规则相同)
            return -1
        elif  > :
            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):
         = name
        self.score = score
    def __str__(self):
        return '(%s: %s)' % (, self.score)
    __repr__ = __str__
    def __cmp__(self, s):
        if not isinstance(s, Student):
            return -1
        else:
            return -cmp(self.score, s.score) or cmp(, )

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)       # 等于比较
(a, b)       # 不等于比较
(a, b)       # 大于比较
(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):
         = 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):
         = 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)
 = '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)     # 像调用函数一样,调用类