I know that the attributes of class which are declared by double underscore __
prefix may or may not visible outside the class definition. As we can still acces
Nope, since it's part of the name, you can't do that.
Well, actually you can through hacking with the getters/setters, but you generally shouldn't.
Yes, it is possible to hide private data in a closure -- at least, if there is a way to access private
from outside make_A
, I haven't found it:
def make_A():
private = {
'a' : 1,
'b' : 2,
'z' : 26,
}
class A:
def __init__(self):
self.catch = 100
private['a'] = 2 # you can modify the private data
def foo(self):
print(private['a']) # you can access the private data
return A
A = make_A()
a=A()
a.foo()
# 2
Notice that private
is not in dir(a)
print('private' in dir(a))
# False
Although this is possible, I do not think this is recommendable way to program in Python.
Above, private
is shared by all instances of A
. To use private data on a per-instance basis, add self
to the dict key:
def make_A():
private = {}
class A:
def __init__(self):
self.catch = 100
private[self,'a'] = 1 # you can modify the private data
private[self,'b'] = 2
private[self,'z'] = 26
def foo(self):
print(private[self,'a']) # you can access the private data
return A
Why might you want to protect attributes?
If you want to protect attributes from inadvertent overwriting, use double underscores and, probably, ready-only properties to make access easier. But most of the time, you aint't gonna need it. Just do yourself a favor and leave the attributes open, this makes debugging far easier.
If you want to protect your object from tampering by third parties, you can play with __getattr__
and __setattr__
, but probably you should not pass to an untrusted client objects with protected data at all, use the facade pattern instead and hide your valuables more opaquely. You might want to rethink your architecture, too.
While the accepted answer by unutbu
looks like a good idea to hide data, the private
dictionary still accessible using __closure__
(this attribute cannot be removed):
def make_A():
private = {}
class A:
def __init__(self):
self.catch = 100
private[self,'a'] = 1 # you can modify the private data
private[self,'b'] = 2
private[self,'z'] = 26
def foo(self):
print(private[self,'a']) # you can access the private data
return A
A = make_A()
a = A()
a.foo() # 1
a.foo.__closure__[0].cell_contents[(a, 'a')] = 42
a.foo() # 42
Or following the link provided by Sumukh Barve
in the comments:
def createBankAccount():
private = {'balance': 0.0}
def incr(delta):
private['balance'] += delta;
account = {
'deposit': lambda amount: incr(amount),
'withdraw': lambda amount: incr(-amount),
'transferTo': lambda otherAccount, amount: (
account['withdraw'](amount),
otherAccount['deposit'](amount)
),
'transferFrom': lambda otherAccount, amount: (
otherAccount['transferTo'](account, amount)
),
'getBalance': lambda : private['balance']
}
return account;
account = createBankAccount()
print(account['getBalance']())
account['getBalance'].__closure__[0].cell_contents['balance'] = 1000**1000
print(account['getBalance']()) # I can buy a couple of nations
I bevile the only way to create private
attributes is to write some kind of CPython
extension.