python学习第十七天 --定制类
何为定制类?
Python的class允许定义许多特殊方法,可以让我们非常方便地生成特定的类。在类中应用或者重写python的特殊方法,得到的类,就是定制类。
大家都知道print的用法。见下面例子
>>> lst = [2,3,4] >>> print lst [2, 3, 4] >>> class Animal(object): pass >>> a = Animal() >>> print a <__main__.Animal object at 0x01E6E990>
为什么print都能识别出lst和p的数据类型呢?
当我们执行如下代码的时候,就知道为什么了?
>>> print lst.__str__ <method-wrapper '__str__' of list object at 0x01E641E8> >>> print a.__str__ <method-wrapper '__str__' of Animal object at 0x01E6E990>
__str__特殊方法,能识别出每一个数据类型。如果希望类的实例print a 打印出 ‘object of Animal class’.怎么办?重新定义__str__方法。
>>> class Animal(object): def __str__(self): return 'object of Animal class' >>> a = Animal() >>> print a object of Animal class
但是有时候发现直接敲
>>> a <__main__.Animal object at 0x01E6E990>
__str__不会被调用。因为当直接敲a这行代码的时候,直接调用的并不是__str__.而是__repr__.
>>> class Animal(object): def __str__(self): return 'object of Animal class' __repr__ = __str__ //偷懒一下 >>> a = Animal() >>> a object of Animal class
python的特殊方法很多,这里就不做一一介绍。下面主要介绍 __slots__,__call__,@property用法。
__slots__
python是一个动态语言,任何实例可以再运行期间都能动态添加实例的属性。但是有时候,想限制实例的添加属性,就使用__slot__方法。见下面例子:
>>> class Person(object): __slots__ = ('name','age')//限制只有name和age的属性 def __init__(self,name,age): self.name = name self.age = age >>> p = Person('zhangsan',25) >>> p.age 25 >>> p.name 'zhangsan' >>> p.gender ='man'//直接动态赋属性gender,会出现错误 Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> p.gender ='man' AttributeError: 'Person' object has no attribute 'gender'
__slot__目的是限制当前类所能拥有的属性。所以在继承的环境下,子类不受影响。
>>> class Student(Person): pass >>> s = Student('zhangsan',26) >>> s.age 26 >>> s.name 'zhangsan' >>> s.gender = 'man'//可以动态添加属性 >>> s.gender 'man'
所以子类Student如果想自己限制添加属性的话,也要通过__slots__来控制。
__call__
一个类的实例可以变成一个可调用的对象,只需要实现一个特殊的方法__call__就可以了。
接下来我们把Student类变成一个可调用的对象:
>>> class Student(Person): def __init__(self,name,score): self.name = name self.score = score >>> class Student(Person): def __init__(self,name,score): self.name = name self.score = score def __call__(self,age): print 'my name is %s'% self.name print 'my age is %d'% age >>> s = Student('lixi',89) >>> s(25) my name is lixi my age is 25
有时候你会发现s(25)乍一眼感觉不出来是一个函数还是对象的实例。python语言函数和对象的实例不是区分的很明显。
@property
上述的class Student中,当修改s实例的score值时,
>>> s.score = 89 >>> s.score = 9999
但是这样无法检查s实例的分数有效性。目前只能这样做:
>>> class Student(object): def __init__(self,name,score): self.name = name self.__score = score def set_score(self,score): if score <0 or score >100: raise ValueError('invalid score') self.__score = score def get_score(self): return self.__score >>> s = Student('wangwu',89) >>> s.set_score(89) >>> s.set_score(9999) //非法值,ValueError Traceback (most recent call last): File "<pyshell#75>", line 1, in <module> s.set_score(9999) File "<pyshell#71>", line 7, in set_score raise ValueError('invalid score') ValueError: invalid score
有时候觉得写s.set_score和s.get_score没有直接写s.score那么直接。有没有其他办法?既能直接的s.score又能检查score的有效性?python提供@property高阶函数这样功能需求的装饰器。
>>> class Student(object): def __init__(self,name,score): self.name = name self.__score = score @property def score(self): return self.__score @score.setter def score(self,score): if score <0 or score >100: raise ValueError('invalid score') self.__score = score >>> s = Student('liunx',98) >>> s.score = 89 >>> s.score = 9999 Traceback (most recent call last): File "<pyshell#82>", line 1, in <module> s.score = 9999 File "<pyshell#79>", line 12, in score raise ValueError('invalid score') ValueError: invalid score
小结:
特殊方法:
1.任何数据实例都有特殊方法
2.特殊方法定义在class中
3.不需要直接调用
4.python的某些方法或者函数会直接调用数据实例的特殊方法
实现特殊方法:
1.重新编写用到的特殊方法
2.如果重新一些特殊方法,有些关联的特殊方法也要一并实现。例如:__setattr__,__getattr__,__delattr__