If you're in one of those predicaments where
cls.__private attributes just aren't enough since they can easily be accessed through
inst._cls__private, and you need something a little more secure, here's a method I've been playing with for a while that fills that gap.
Note that this uses
__slots__, more info on this below the code.
def private(): # no outside access class A(object): __slots__ = ['__private__'] def __init__( inst, val=None ): setprivate( inst, val ) def __repr__( inst ): return '<A %s >' % getprivate( inst ) globals()['A'] = A # add our class to the public namespace dsc = A.__private__ del A.__private__ # this makes your attribute realistically private as it removes all normal access from both the class and it's instances. # this is how access to the "attribute" is maintained: getprivate = dsc.__get__ setprivate = dsc.__set__ private() del private
How this works is
__slots__ creates member_descriptor objects (which can't be created normally) used by the class instances, which we want because they're valid spaces in memory for applying values per instance.
del class.attr or alternatively
delattr(class,'attr') we're simply removing the link to the member_descriptor, not the member_descriptor itself which is still registered with the class even though it's link is gone.
So in the above code in the private namespace
setprivate can't be accessed anywhere but the class and anything else inside the private namespace.
Now that we have access to the getter and setter methods of the member_descriptor, we can use
__closure__ in A's methods to add a layer of security through a form of obscurity that may change as the code is modified, leaving hackers in a sandbox where their code needs updating to match the program's changes.
(if you know what you're doing, you can still figure out how to access these attributes, but it's much harder to do than, and not as solid as the typical
A.__init__ above calls
setprivate supplying the instance and the value it's given, where it can be seen with
print(repr(inst)) like so:
>>> i = A(15) >>> repr(i) '<A 15 >'
Hope you enjoy this little hack :)
Might I note it's also performative ;D
dir(i) so you can see the
__private__ attribute really doesn't exist in the instance (the same goes for the class).
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__']