zoukankan      html  css  js  c++  java
  • Python面向对象-访问限制

    在Class内部,可以有字段,方法和属性,而外部代码可以通过直接调用实例变量的方法来操作数据,

    (1)私有普通字段

    比如对于下面的Student类,name字段可以在外面通过对象进行直接访问:

     1 class Student(object):
     2     def __init__(self, name):
     3         self.name = name
     4 
     5     def get_name(self):
     6         return self.name
     7 
     8 rob = Student("Rob")
     9 rob.name = 'Rob1'
    10 print(rob.get_name())

    上面的程序输出是 Rob1 

    如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

     1 class Student(object):
     2     def __init__(self, name):
     3         self.__name = name
     4 
     5     def get_name(self):
     6         return self.__name
     7 
     8 rob = Student("Rob")
     9 rob.__name = 'Rob1'
    10 print(rob.get_name())

    改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name,我们看到程序输出是 Rob ,也就是代码 rob.__name = 'Rob1' 并不生效。

    这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。

    但是如果外部代码要修改name怎么办?可以给Student类增加set_name这样的方法:

    1 class Student(object):
    2     ...
    3 
    4     def set_name(self, name):
    5         self.__name = name

    你也许会问,原先那种直接通过rob.name= "Rob1"也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数,比如我们想对学生类的score操作:

     1 class Student(object):
     2     ...
     3 
     4     def get_score(self):
     5         return self.__score
     6 
     7     def set_score(self, value):
     8         if 0 <= value <= 100:
     9             self.__score = value
    10         else:
    11             raise ValueError("Bad score")

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

    有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

    双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量

    但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__name改成不同的变量名

    总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。

    还有一个问题需要注意,

    假如有子类继承了Student类,那么private字段能否在子类中访问呢?我们来看下面的例子,Freashman类继承Student类,在Freashman类中尝试获取__score属性:

     1 class Student(object):
     2     def __init__(self, name):
     3         self.__name = name
     4         self.__score = 0
     5 
     6     def get_name(self):
     7         return self.__name
     8 
     9     def set_name(self, name):
    10         self.__name = name
    11 
    12     def get_score(self):
    13         return self.__score
    14 
    15     def set_score(self, value):
    16         if 0 <= value <= 100:
    17             self.__score = value
    18         else:
    19             raise ValueError("Bad score")
    20 
    21 
    22 class Freshman(Student):
    23     def get_score(self):
    24         return self.__score
    25 
    26 
    27 mary = Freshman("Mary")
    28 print(mary.get_score())

    运行程序将报错: AttributeError: 'Freshman' object has no attribute '_Freshman__score' 

    因此私有成员除了类本身内部,其他地方都不可访问。

    (2)私有静态字段

    我们知道类除了有普通字段,还有静态字段,对于静态字段我们也可以限制只在类内部访问,只是和普通字段稍有不同:

    (1)静态字段通过类访问

    (2)可以将内部访问的方法设置为静态方法:

     1 class Student(object):
     2     __nationality = 'China'
     3 
     4     ...
     5 
     6     @staticmethod # 静态方法
     7     def get_nationality():
     8         return Student.__nationality # 通过类访问
     9 
    10     @staticmethod  # 静态方法
    11     def set_nationality(nation):
    12         Student.__nationality = nation # 通过类访问
    13 
    14 print(Student.get_nationality())
    15 Student.set_nationality('USA')
    16 print(Student.get_nationality())

    方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用

  • 相关阅读:
    HDU 2899 Strange fuction
    HDU 2899 Strange fuction
    HDU 2199 Can you solve this equation?
    HDU 2199 Can you solve this equation?
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
  • 原文地址:https://www.cnblogs.com/z-joshua/p/6392911.html
Copyright © 2011-2022 走看看