Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do encapsulation in Python?

What's wrong with this? From objective, and functional standpoints?

import sys

class EncapsulationClass(object):

  def __init__(self):
    self.privates = ["__dict__", "privates", "protected", "a"]
    self.protected = ["b"]

    print self.privates

    self.a = 1
    self.b = 2
    self.c = 3
    pass

  def __getattribute__(self, name):
    if sys._getframe(1).f_code.co_argcount == 0:
      if name in self.privates:
        raise Exception("Access to private attribute \"%s\" is not allowed" % name)
      else:
        return object.__getattribute__(self, name)
    else:
      return object.__getattribute__(self, name)

  def __setattr__(self, name, value):
    if sys._getframe(1).f_code.co_argcount == 0:
      if name in self.privates:
        raise Exception("Setting private attribute \"%s\" is not allowed" % name)
      elif name in self.protected:
        raise Exception("Setting protected attribute \"%s\" is not allowed" % name)
      else:
        return object.__setattr__(self, name, value)
    else:
      return object.__setattr__(self, name, value)


example = EncapsulationClass()

example.a = 10 # Exception: Setting private attribute "a" is not allowed
example.b = 10 # Exception: Setting protected attribute "b" is not allowed
example.c = 10 # example.c == 10

example.__dict__["privates"] # Exception: Setting protected attribute "b" is not allowed

What would actually be wrong with doing something like this?

Is there any better way to achieve encapsulation in Python?

like image 938
will Avatar asked Oct 06 '14 12:10

will


1 Answers

Python has encapsulation - you are using it in your class.

What it doesn't have is access control such as private and protected attributes. However, in Python, there is an attribute naming convention to denote private attributes by prefixing the attribute with one or two underscores, e.g:

self._a
self.__a 

A single underscore indicates to the user of a class that an attribute should be considered private to the class, and should not be accessed directly.

A double underscore indicates the same, however, Python will mangle the attribute name somewhat to attempt to hide it.

class C(object):
    def __init__(self):
        self.a = 123    # OK to access directly
        self._a = 123   # should be considered private
        self.__a = 123  # considered private, name mangled

>>> c = C()
>>> c.a
123
>>> c._a
123
>>> c.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__a'
>>> c._C__a
123

You can see in the last example that the name was changed from __a to _C__a, although it is still accessible within the class as self.__a.

like image 75
mhawke Avatar answered Sep 24 '22 09:09

mhawke