Python Access Restrictions private public details

  • 2020-12-16 06:01:40
  • OfStack

1. Knowledge

In a module, we may define many functions and variables. But there are functions and variables that we want to be able to use for others, and there are functions and variables that we want to use only within the module.
We can do this by defining whether the function, the variable, is public or private.
In Python, this is done with the underscore "_" prefix.

public: Public. Normal function and variable names are of this type and can be referenced directly. For example, variables abc, PI, etc. Special variable: Format of ___ 12EN__, starting with and ending with __. Can be referenced directly, but for special purposes. ___, ___, 14EN__. Do not use such variable names for self-defined variables. private: Private, non-public, in a format similar to _xxx_ and ___, with, for example, ES18en.

It should not be directly referenced, only accessible internally, not externally.

The state inside the object cannot be changed at will, so the code is more robust, protected by access restrictions.

2. Give examples

Inside the Class class, you can have properties and methods. The external code can manipulate the data by calling the method of the instance variable directly, hiding the internal complex logic. However, the external code is still free to modify the properties of an instance. Such as:


>>>b.score
99
>>>b.score = 59
>>>b.score
59

If you want to keep the internal property from being accessed externally, you can make the property's name private by putting the underscore "__" in front of it, as follows:


class Student(object):   
  def __init__(self, name, score):     
    self.__name = name     
    self.__score = score   
    
  def print_score(self):     
    print('%s: %s' % (self.__name, self.__score))

An attempt to access the property externally will report an error because the private variable cannot be accessed externally.


>>> bart = Student('Bart Simpson', 98) 
>>> bart.__name #  Private variable: cannot be accessed externally 
Traceback (most recent call last):  
File "<stdin>", line 1, in <module> 
AttributeError: 'Student' object has no attribute '__name'

But what if the external code wants to get name and score?

Add methods to the Student class to get attributes: get_name() and get_score(), as follows:


class Student(object):
  ...
  def get_name(self):     
    return self.__name   
  def get_score(self):     
    return self.__score 

What if the external code modifies score? You can add Settings to the Student class: set_score() :


...
def set_score(self, score): 
  #  Avoid passing in invalid parameters  
  if 0 <= score <= 100: 
    self.__score = score 
  else:       
    raise ValueError('bad score') 

Is a private instance variable that starts with a double underscore 1 must not be accessed externally? Not really.

___, 62EN cannot be accessed directly because the Python interpreter changes the ___ 64en variable to _Student___ name, so the ___ variable can still be accessed with _StudentES68en.


>>> bart = Student('Bart Simpson', 98)
>>> bart.get_name() 
'Bart Simpson' 
>>> bart.__name = 'New Name' #  to bart The addition of __name variable  
>>> bart.__name        #  ! with class The inside of the __name Variables are not 1 A variable! 
'New Name' 
>>> bart.get_name()      # get_name() Internal return self.__name (_Student__name)
'Bart Simpson'  

On the surface, the external code "succeeds" sets the ___ 73en variable, but in fact the ___ 74en variable and the ___ 76en variable within class are not a single variable! The internal ___ variable has been automatically changed by the Python interpreter to _StudentES80en, and the external code adds one more ___ to bart.

Therefore, python does not have a method to completely restrict access to private functions or variables, so it is not "cannot be referenced directly", and it is customary to not refer to private functions or variables. What about their use?

Such as:


def _private_1 (name):
  return 'hello,%s ' % name
def _private_2 (name):
  return 'hi , %s ' % name
def greeting(name):
  if len(name) > 3:
    return _private_1 (name)
  else:
    return _private_2 (name)

Expose the greeting() function in the module and hide the internal logic with the private function. This way, calling the greeting() function does not have to worry about the details of the internal private function.

This is a very useful approach to code encapsulation and abstraction: all functions that need not be referenced externally are defined as private, and only those that need to be referenced externally are defined as public.

3. Complete code


class Student(object):   
  def __init__(self, name, score):     
    self.__name = name     
    self.__score = score   
    
  def print_score(self):     
    print('%s: %s' % (self.__name, self.__score))
  
  def get_name(self):     
    return self.__name   
  
  def get_score(self):     
    return self.__score
    
  def set_score(self, score): 
    #  Avoid passing in invalid parameters  
    if 0 <= score <= 100: 
      self.__score = score 
    else:       
      raise ValueError('bad score')  
      
  def _private_1 (name):
    return 'hello,%s ' % name
  def _private_2 (name):
    return 'hi , %s ' % name
  def greeting(name):
    if len(name) > 3:
      return _private_1 (name)
    else:
      return _private_2 (name)

Related articles: