Python


433 浏览 5 years, 2 months

6.3.1 scope control

版权声明: 转载请注明出处 http://www.codingsoho.com/
scope control

No real scope control of attributes

  • Public
    • Every field by default
  • Protected
    • Convention: begins with an underscore
    • Still accessible everywhere
    • Must limit scope with getters/setters
  • Private
    • Convention: begins with double underscore
    • Not accessible outside the class
    • Still can be accessed using _ClassName__attribute_name
    • Frowned upon, usually used to denote part of code that will change

Single Underscore

Names, in a class, with a leading underscore are simply to indicate to other programmers that the attribute or method is intended to be private. However, nothing special is done with the name itself.

To quote PEP-8:

_single_leading_underscore: weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an underscore.

Double Underscore (Name Mangling)

From the Python docs:

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, variables stored in globals, and even variables stored in instances. private to this class on instances of other classes.

And a warning from the same page:

Name mangling is intended to give classes an easy way to define “private” instance variables and methods, without having to worry about instance variables defined by derived classes, or mucking with instance variables by code outside the class. Note that the mangling rules are designed mostly to avoid accidents; it still is possible for a determined soul to access or modify a variable that is considered private.

Example

>>> class SomeClass(object):
...     def __init__(self):
...             self.public = 0
...             self._protected = 1
...             self.__private = 2
...
>>> foo = SomeClass()

>>> class SomeChild(SomeClass):
...     def print_attr(self):
...             print(self.public)
...             print(self._protected)
...             print(self.__private)
...

>>> bar = SomeChild()
>>> bar.print_attr()
0
1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in print_attr
AttributeError: SomeChild' object has no attribute '_SomeChild__private'
>>> print(foo.public)
0
>>> print(foo._protected)
1
>>> print(foo.__private)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass' object has no attribute '__private'
>>> print(bar._SomeClass__private)
2
>>> print(bar.__dict__)
{'_SomeClass__private': 2, 'public': 0, '_protected': 1}

参考文档