类和实例
在Python中,定义类是通过class关键字,注意类名要大写首字母:
class Student(object):
pass
定义好了Student类,就可以根据Student类创建出Student的实例,创建实例是通过类名+()实现的:bart = Student()
可以自由地给一个实例变量绑定属性,比如,给实例bart绑定一个name属性:bart.name = 'Bart Simpson'
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去:
class Studetn(object):
def __init__(self, name, score):
self.name = name
self.score = score
__init__
方法的第一个参数永远是self
,表示创建的实例本身,有了__init__
方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__
方法匹配的参数,bart = Student('Jack', 59)
我们可以在类的内部定义访问类的数据的函数,这些函数叫做方法:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
通过这些方法就可以在外部直接访问类的数据,而不需要知道具体实现的细节。
访问限制
在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问:
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
需要注意的是,在Python中,变量名类似__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
继承和多态
当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类,而被继承的class称为基类、父类或超类。
比如,我们已经编写了一个名为Animal的class:
class Animal(object):
def run(self):
print('Animal is running...')
当我们需要编写Dog类时,就可以直接从Animal类继承:
class Dog(Animal):
pass
继承最大的好处是子类获得了父类的全部功能。由于Animial实现了run()
方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()
方法。
给Dog类也加一个run()
方法,子类的run()
覆盖了父类的run()
,这就是继承的另一个好处,多态:一个类他可以拥有多种状态,实质上就是说它本身就有多个类型。
__slot__的作用
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。如果我们想要限制实例的属性,比如,只允许对Student实例添加name和age属性,为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性:
class Student(object):
__slot__ = ('name', 'age')
然后:
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
socre
属性不在__slot__
中,所以无法绑定
使用__slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的,除非在子类中也定义__slots__
,这样,子类实例允许定义的属性就是自身的__slots__
加上父类的__slots__
。
使用@property
Python内置的@property
装饰器就是负责把一个方法变成属性调用的:
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
这样就把一个set_score
的方法变成了一个属性赋值,就拥有了一个可控的属性操作,可以对score
的赋值进行限制,比起直接定义一个set_score
要方便许多:
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!