[关闭]
@yanglt7 2018-12-03T06:45:42.000000Z 字数 3484 阅读 579

Python17_类和实例、访问限制

Python


类和实例

类是抽象的模板,比如 Student 类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

仍以 Student 类为例,在 Python 中,定义类是通过 class 关键字,class 后面紧接着是类名,即 Student,类名通常是大写开头的单词,紧接着是 (object),表示该类是从哪个类继承下来的,通常,如果没有合适的继承类,就使用 object 类,这是所有类最终都会继承的类。

  1. >>> class Student(object):
  2. ... pass
  3. ...

定义好了 Student 类,就可以根据 Student 类创建出 Student 的实例,创建实例是通过类名+()实现的:

  1. >>> bart = Student()
  2. >>> bart
  3. <__main__.Student object at 0x0000016298062898>
  4. >>> Student
  5. <class '__main__.Student'>

可以自由地给一个实例变量绑定属性,比如,给实例 bart 绑定一个 name 属性:

  1. >>> bart.name='Bart Simpson'
  2. >>> bart.name
  3. 'Bart Simpson'

由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的 __init__ 方法,在创建实例的时候,就把 name,score 等属性绑上去:

  1. >>> class Student(object):
  2. ... def __init__(self,name,score):
  3. ... self.name=name
  4. ... self.score=score
  5. ...

__init__ 方法的第一个参数永远是 self,表示创建的实例本身,因此,在 __init__ 方法内部,就可以把各种属性绑定到 self,因为 self 就指向创建的实例本身。

有了__init__ 方法,在创建实例的时候,就不能传入空的参数了,必须传入与 __init__ 方法匹配的参数,但 self 不需要传,Python 解释器自己会把实例变量传进去:

  1. >>> bart=Student('Bart Simpson',59)
  2. >>> bart.name
  3. 'Bart Simpson'
  4. >>> bart.score
  5. 59

仍然可以用默认参数、可变参数、关键字参数和命名关键字参数*。

数据封装

直接在 Student 类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。这些封装数据的函数是和 Student 类本身是关联起来的,我们称之为类的方法:

  1. >>> class Student(object):
  2. ... def __init__(self,name,score):
  3. ... self.name=name
  4. ... self.score=score
  5. ... def print_score(self):
  6. ... print('%s:%s' % (self.name,self.score))
  7. ...

要调用一个方法,只需要在实例变量上直接调用,除了 self 不用传递,其他参数正常传入:

  1. >>> bart=Student('Bart Simpson',59)
  2. >>> bart.print_score()
  3. Bart Simpson:59

封装的另一个好处是可以给 Student 类增加新的方法,比如 get_grade:

  1. >>> class Student(object):
  2. ... def __init__(self,name,score):
  3. ... self.name=name
  4. ... self.score=score
  5. ... def get_grade(self):
  6. ... if self.score>=90:
  7. ... return 'A'
  8. ... elif self.score>=60:
  9. ... return 'B'
  10. ... else:
  11. ... return 'C'
  12. ...
  13. >>> bart=Student('Bart Simpson',59)
  14. >>> bart.get_grade()
  15. 'C'

访问限制

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线 __ ,在Python中,实例的变量名如果以 __ 开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量 .__name 和实例变量 .__score 了:

  1. >>> class Student(object):
  2. ... def __init__(self,name,score):
  3. ... self.__name=name
  4. ... self.__score=score
  5. ... def print_score(self):
  6. ... print('%s:%s' % (self.__name,self.__score))
  7. ...
  8. >>> bart=Student('Bart Simpson',98)
  9. >>> bart.__name
  10. Traceback (most recent call last):
  11. File "<stdin>", line 1, in <module>
  12. AttributeError: 'Student' object has no attribute '__name'

但是如果外部代码要获取 name 和 score 怎么办?可以给 Student 类增加 get_name 和 get_score 这样的方法:

  1. >>> class Student(object):
  2. ... def __init__(self,name,score):
  3. ... self.__name=name
  4. ... self.__score=score
  5. ... def print_score(self):
  6. ... print('%s:%s' % (self.__name,self.__score))
  7. ... def get_name(self):
  8. ... return self.__name
  9. ... def get_score(self):
  10. ... return self.__score
  11. ...
  12. >>> bart=Student('Bart Simpson',98)
  13. >>> bart.get_name()
  14. 'Bart Simpson'

如果又要允许外部代码修改 score 怎么办?可以再给 Student 类增加 set_score 方法:

  1. >>> class Student(object):
  2. ... def __init__(self,name,score):
  3. ... self.__name=name
  4. ... self.__score=score
  5. ... def print_score(self):
  6. ... print('%s:%s' % (self.__name,self.__score))
  7. ... def get_name(self):
  8. ... return self.__name
  9. ... def get_score(self):
  10. ... return self.__score
  11. ... def set_score(self,score):
  12. ... self.__score=score
  13. ...
  14. >>> bart=Student('Bart Simpson',98)
  15. >>> bart.set_score(88)
  16. >>> bart.get_score()
  17. 88

原先那种直接通过 bart.score = 59也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数:

  1. >>> bart.score=77
  2. >>> bart.score
  3. 77
  1. >>> class Student(object):
  2. ...
  3. ... def set_score(self,score):
  4. ... if 0<=score<=100:
  5. ... self.__score=score
  6. ... else:
  7. ... raise ValueError('bad score')
  8. ...
  9. >>> bart=Student('Bart Simpson',108)
  10. >>> bart.get_score()
  11. 108
  12. >>> bart.set_score(909)
  13. Traceback (most recent call last):
  14. File "<stdin>", line 1, in <module>
  15. File "<stdin>", line 15, in set_score
  16. ValueError: bad score

需要注意的是,在Python中,变量名类似 __xxx__ 的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是 private 变量,所以,不能用namescore 这样的变量名。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注