Thread overview
Need Help with Encapsulation in Python!
Jun 17, 2022
Soham Mukherjee
Jun 17, 2022
Soham Mukherjee
June 17, 2022
   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? Please rectify my code if possible.

June 17, 2022

On Friday, 17 June 2022 at 13:58:15 UTC, Soham Mukherjee wrote:

>

Is there any better way to achieve encapsulation in Python? Please rectify my code if possible.

One convention is to use "self._fieldname" for protected and "self.__fieldname" for private class attributes.

June 17, 2022

Here, they mentioned a way of simulating encapsulation of class level like this:

def private(*values):
    def decorator(cls):
        class Proxy:
            def __init__(self, *args, **kwargs):
                self.inst = cls(*args, **kwargs)
            def __call__(self, cls, *args, **kwargs):
                return self.inst
            def __getattr__(self, attr):
                if attr in values:
                    raise AttributeError("Private valueiables are not accessible!")
                else: return getattr(self.inst, attr)
            def __setattr__(self, attr, val):
                # Allow access inside the class
                if attr == 'inst': self.__dict__[attr] = val
                elif attr in values:
                    raise AttributeError("Private valueiables are not accessible!")
                else: setattr(self.inst, attr, val)
            def __str__(self):
                return self.inst.__str__()
        return Proxy
    return decorator

this can be used for class-level encapsulation (e.g.limiting the access of a variable or method in a class).

For module-level encapsulation, however, the only way that I can think of is that you create a file and write the init.py. However if those who writes the client program knows the structure of your file / package, this can still not stop them from importing stuff.

June 17, 2022

On Friday, 17 June 2022 at 14:14:57 UTC, Ola Fosheim Grøstad wrote:

>

On Friday, 17 June 2022 at 13:58:15 UTC, Soham Mukherjee wrote:

>

Is there any better way to achieve encapsulation in Python? Please rectify my code if possible.

One convention is to use "self._fieldname" for protected and "self.__fieldname" for private class attributes.

Example:

class A:
     def __init__(self):
         self._x = 3
         self.__x = 4

a = A()
print(a.__dict__)

will produce the output: {'_x': 3, '_A__x': 4} .

As you can see the "self.__x" field has the name "_A__x" which makes it "hidden", but not inaccessible.

But you can use external tools to check for misuse.