@yanglt7
2018-12-03T06:45:42.000000Z
字数 3484
阅读 579
Python
类是抽象的模板,比如 Student 类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
仍以 Student 类为例,在 Python 中,定义类是通过 class 关键字,class 后面紧接着是类名,即 Student,类名通常是大写开头的单词,紧接着是 (object),表示该类是从哪个类继承下来的,通常,如果没有合适的继承类,就使用 object 类,这是所有类最终都会继承的类。
>>> class Student(object):
... pass
...
定义好了 Student 类,就可以根据 Student 类创建出 Student 的实例,创建实例是通过类名+()实现的:
>>> bart = Student()
>>> bart
<__main__.Student object at 0x0000016298062898>
>>> Student
<class '__main__.Student'>
可以自由地给一个实例变量绑定属性,比如,给实例 bart 绑定一个 name 属性:
>>> bart.name='Bart Simpson'
>>> bart.name
'Bart Simpson'
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的 __init__ 方法,在创建实例的时候,就把 name,score 等属性绑上去:
>>> class Student(object):
... def __init__(self,name,score):
... self.name=name
... self.score=score
...
__init__ 方法的第一个参数永远是 self,表示创建的实例本身,因此,在 __init__ 方法内部,就可以把各种属性绑定到 self,因为 self 就指向创建的实例本身。
有了__init__ 方法,在创建实例的时候,就不能传入空的参数了,必须传入与 __init__ 方法匹配的参数,但 self 不需要传,Python 解释器自己会把实例变量传进去:
>>> bart=Student('Bart Simpson',59)
>>> bart.name
'Bart Simpson'
>>> bart.score
59
仍然可以用默认参数、可变参数、关键字参数和命名关键字参数*。
直接在 Student 类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。这些封装数据的函数是和 Student 类本身是关联起来的,我们称之为类的方法:
>>> 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))
...
要调用一个方法,只需要在实例变量上直接调用,除了 self 不用传递,其他参数正常传入:
>>> bart=Student('Bart Simpson',59)
>>> bart.print_score()
Bart Simpson:59
封装的另一个好处是可以给 Student 类增加新的方法,比如 get_grade:
>>> class Student(object):
... def __init__(self,name,score):
... self.name=name
... self.score=score
... def get_grade(self):
... if self.score>=90:
... return 'A'
... elif self.score>=60:
... return 'B'
... else:
... return 'C'
...
>>> bart=Student('Bart Simpson',59)
>>> bart.get_grade()
'C'
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线 __ ,在Python中,实例的变量名如果以 __ 开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量 .__name 和实例变量 .__score 了:
>>> 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))
...
>>> bart=Student('Bart Simpson',98)
>>> bart.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
但是如果外部代码要获取 name 和 score 怎么办?可以给 Student 类增加 get_name 和 get_score 这样的方法:
>>> 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))
... def get_name(self):
... return self.__name
... def get_score(self):
... return self.__score
...
>>> bart=Student('Bart Simpson',98)
>>> bart.get_name()
'Bart Simpson'
如果又要允许外部代码修改 score 怎么办?可以再给 Student 类增加 set_score 方法:
>>> 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))
... def get_name(self):
... return self.__name
... def get_score(self):
... return self.__score
... def set_score(self,score):
... self.__score=score
...
>>> bart=Student('Bart Simpson',98)
>>> bart.set_score(88)
>>> bart.get_score()
88
原先那种直接通过 bart.score = 59也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数:
>>> bart.score=77
>>> bart.score
77
>>> class Student(object):
...
... def set_score(self,score):
... if 0<=score<=100:
... self.__score=score
... else:
... raise ValueError('bad score')
...
>>> bart=Student('Bart Simpson',108)
>>> bart.get_score()
108
>>> bart.set_score(909)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 15, in set_score
ValueError: bad score
需要注意的是,在Python中,变量名类似 __xxx__ 的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是 private 变量,所以,不能用name、score 这样的变量名。