@yanglt7
2018-12-03T06:45:42.000000Z
字数 3484
阅读 649
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.score59
仍然可以用默认参数、可变参数、关键字参数和命名关键字参数*。
直接在 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.__nameTraceback (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.score77
>>> 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_scoreValueError: bad score
需要注意的是,在Python中,变量名类似 __xxx__ 的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是 private 变量,所以,不能用name、score 这样的变量名。