python 新式类的学习随笔-定制类的特殊方法(2)

来源:互联网 发布:付费wlan和手机网络 编辑:程序博客网 时间:2024/05/22 10:47

这部分大部分都是转载自python学习(7)定制类的特殊方法,加了一些自己的理解。

形如__xxx__的函数是类的特殊方法。

常需要修改的特殊方法有下面这些:

PS:下划线的几种用法
说一下几种常用的:
1.名称前的单下划线(_strri):程序员使用名称前的单下划线,用于指定该名称属性为“私有”。如果你写了代码“from <模块/包名> import *”,那么以“_”开头的名称都不会被导入,除非模块或包中的“__all__”列表显式地包含了它们。

2.名称前的双下划线(__strri):名称(具体为一个方法名)前双下划线(__)的用法并不是一种惯例,对解释器来说它有特定的意义。Python中的这种用法是为了避免与子类定义的名称冲突。Python文档指出,“__spam”这种形式(至少两个前导下划线,最多一个后续下划线)的任何标识符将会被“_classname__spam”这种形式原文取代,在这里“classname”是去掉前导下划线的当前类名。例如下面的例子:
>>> class A(object): ... def _internal_use(self): ... pass ... def __method_name(self): ... pass ... >>> dir(A()) ['_A__method_name', ..., '_internal_use']
正如所预料的,“_internal_use”并未改变,而“__method_name”却被变成了“_ClassName__method_name”。此时,如果你创建A的一个子类B,那么你将不能轻易地覆写A中的方法“__method_name”。
>>> class B(A): ... def __method_name(self): ... pass ... >>> dir(B()) ['_A__method_name', '_B__method_name', ..., '_internal_use']
3.名称前后的双下划线(__init__):

这种用法表示Python中特殊的方法名。其实,这只是一种惯例,对Python系统来说,这将确保不会与用户自定义的名称冲突。通常,你将会覆写这些方法,并在里面实现你所需要的功能,以便Python调用它们。例如,当定义一个类时,你经常会覆写“__init__”方法。

虽然你也可以编写自己的特殊方法名,但不要这样做。

>>> class C(object): ... def __mine__(self): ... pass ... >>> dir(C) ... [..., '__mine__', ...]



下面转入正题

__str__()

print语句输出的结果。

__repr__()

命令行直接输入类名的输出结果。

class Person(object):

    def __init__(self, name, gender):

        self.name = name

        self.gender = gender

    def __str__(self):

        return '(Person: %s, %s)' % (self.name, self.gender)

    __repr__ = __str__

p = Person('Bob', 'male')

print p

>>> p

输出:

(Person: Bob, male)

(Person: Bob, male)

__cmp__()

类的比较规则。

class Student(object):

    def __init__(self, name, score):

        self.name = name

        self.score = score

    def __cmp__(self, s):

        if self.score < s.score :

            return -1

        elif self.score > s.score :

            return 1

        else:

            return 0

__len__()

类似list的类返回的元素数量。

class Students(object):

    def __init__(self, *args):

        self.names = args

    def __len__(self):

        return len(self.names)

ss = Students('Bob', 'Alice', 'Tim')

print len(ss)

输出:3

数学运算符

__add__()、__sub__()、__mul__()、__div__()

有理数的加减乘除:

def gcs(a,b,c=1):

    if 0==a%2 and 0==b%2:

        return gcs(a/2,b/2,c*2);

        

    s = abs(a-b)

    m = min(a,b)

    if s == m:

        return m*c

    return gcs(s,m,c)

 

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)

类型转换

__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

@property装饰器与@score.setter装饰器

一起使用,用于把gettersetter方法变成属性。

class Student(object):

    @property

    def score(self):

        return self._score

    @score.setter

    def score(self, value):

        if not isinstance(value, int):

            raise ValueError('score must be an integer!')

        if value < 0 or value > 100:

            raise ValueError('score must between 0 ~ 100!')

        self._score = value

 

s = Student()

s.score = 60 # OK,实际转化为s.set_score(60)

s.score # OK,实际转化为s.get_score()

s.score = 9999

输出:

60

Traceback (most recent call last):

  ...

ValueError: score must between 0 ~ 100!

__slots__()

指定一个类允许的属性列表。

class Person(object):

    __slots__ = ('name', 'gender')

__call__()

把一个类变成一个可调用的对象。

class ImFunc(object):

    def __call__(self,words):

        print 'i say %s' % words

imfunc = ImFunc()    

imfunc('what the func?') #把类当函数使用

class Addnum(object):def __init__(self):self.num = 0def __call__(self,num = 1):self.num += numdef __str__(self):return 'num:{}'.format(self.num)__repr__ = __str__

>>> a = Addnum()>>> print anum:0>>> a()
把类当做一个函数来使用。

每次调用a()一次,就相当于调用一次 __call__()。
print a()返回的是__str__()的内容,并不会运行。
print a()None>>> a.num2>>> a.num2>>> a.num2>>> a()>>> a.num3>>> a(5)>>> a.num8






原创粉丝点击