Python类私有方法的陷阱

引言

Python不像C++、Java、C#等有明确的公共、私有或受保护的关键字来定义成员函数或属性,它使用约定的单下划线“_”和”__”双下划线作为函数或属性的前缀来标识。使用单下划线还是双下划线,是有很大的区别的。

1. 单下划线的函数或属性,在类定义中可以调用和访问,类的实例可以直接访问,子类中可以访问;

2. 双下划线的函数或属性,在类定义中可以调用和访问,类的实例不可以直接访问,子类不可访问。

注意:对于双下划线的函数或属性,Python解释器使用了名字混淆的方法, 将私有的方法”__method”变成了”_classname__method”了,具体看下文示例。



双下划线的私有函数和属性,在子类中不可见,不存在”覆盖“


  
  
  1. class Base(object):
  2. def __private(self):
  3. print( "private value in Base")
  4. def _protected(self):
  5. print( "protected value in Base")
  6. def public(self):
  7. print( "public value in Base")
  8. self.__private()
  9. self._protected()
  10. class Derived(Base):
  11. def __private(self):
  12. print( "override private")
  13. def _protected(self):
  14. print( "override protected")
  15. print dir(Base)
  16. print( "="* 80)
  17. d = Derived()
  18. d.public()
  19. d._protected()
  20. d._Derived__private()
  21. print( "="* 80)
  22. d.__private()
输出结果如下:


  
  
  1. >>>
  2. [ '_Base__private', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_protected', 'public']
  3. ================================================================================
  4. <span style= "color:#FF0000;"> public value in Base
  5. private value in Base
  6. override protected</span>
  7. override protected
  8. <span style= "color:#FF0000;"> override private</span>
  9. ================================================================================
  10. Traceback (most recent call last):
  11. File "D:\temp\test.py", line 91, in <module>
  12. d.__private()
  13. AttributeError: 'Derived' object has no attribute '__private'
  14. >>>

注意上面输出的红色字体部分,与我们想象中的输出可能不太一样啊。调用子类的public方法时,子类的双下划线方法 __private 并没有”覆盖“父类的方法,但子类的单下划线方法_protected方法却”覆盖“了父类的方法。

这其中的原因,就在于子类要”覆盖“父类的方法,得让子类能够具有访问父类相应方法的权限才行。



不要定义Python的混淆类方法名称

Python解释器对于类(ClassName)双下划线的私有方法(__method),会进行名称混淆(Name Mangle),规则为 _ClassName__method。所以不要在类方法中同时存在__method和 _ClassName__method。

示例


  
  
  1. class Base(object):
  2. def _secret(self):
  3. print( "Base secret")
  4. def __hide(self):
  5. print( "Normal __hide")
  6. def _Base__hide(self):
  7. print( "Special _Base__hide")
  8. def public(self):
  9. print( "From public method")
  10. self.__hide()
  11. print dir(Base())
  12. print( "="* 80)
  13. Base().public()
输出如下


  
  
  1. [ <span style="color:#FF0000;">'_Base__hide'</span>, 'class', 'delattr', 'dict', 'doc', 'format', 'getattribute', 'hash', 'init', 'module', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', '_secret', 'public']
  2. ================================================================================
  3. From public method
  4. <span style= "color:#FF0000;">Special _Base__hide< /span>
可以看出 __hide 已经被 _Base__hide方法替换掉了。外部也可以直接通过 Base()._Base__hide()方式调用(但千万别用这种方式实现,比较混乱!)。

猜你喜欢

转载自blog.csdn.net/NichChen/article/details/82721839