• 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())

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

  • 相关阅读:
    Hopcroft-Carp 算法模板 自用
    (转)二分图匹配匈牙利算法与KM算法
    LightOJ
    最短路类型 (至今做过的)
    POJ
    POJ
    差分约束
    传递闭包(例题POJ3660)
    arrow,
    分辨率,
  • 原文地址:https://www.cnblogs.com/z-joshua/p/6392911.html
Copyright © 2020-2023  润新知