Data Hiding in Python Class

后端 未结 4 1344
半阙折子戏
半阙折子戏 2021-01-02 09:07

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

相关标签:
4条回答
  • 2021-01-02 09:31

    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.

    0 讨论(0)
  • 2021-01-02 09:37

    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
    
    0 讨论(0)
  • 2021-01-02 09:44

    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.

    0 讨论(0)
  • 2021-01-02 09:56

    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.

    0 讨论(0)
提交回复
热议问题