Python类中的数据隐藏

11 投票
4 回答
15193 浏览
提问于 2025-04-17 11:10

我知道,在类里面用双下划线 __ 开头的属性,可能在类的外面看不到,也可能能看到。不过,我们还是可以通过 object._className__attrName 来访问这些属性。

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        ----
        ----
        self.z = 26
        self.catch = 100

现在,为了保护所有属性,除了 catch 这个属性,我得把它们都用双下划线声明,这样做有点麻烦。有没有办法可以在我的类定义里说明,只有 self.catch 这个属性可以在类外被访问呢?

如果这个问题在别的地方已经回答过或者讨论过,我表示歉意。

4 个回答

1

不行,因为这是名字的一部分,你不能这样做。

其实你可以通过一些技巧,比如使用获取器和设置器来实现,但一般来说不建议这么做。

5

虽然unutbu给出的答案看起来是个不错的隐藏数据的方法,但实际上,private字典还是可以通过__closure__这个属性访问到(这个属性是无法删除的):

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

或者可以查看Sumukh Barve在评论中提供的链接:

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

我认为创建private属性的唯一方法是写一些类型的CPython扩展。

20

是的,可以在一个闭包中隐藏私有数据——至少,如果有办法从外部访问private,我还没找到:

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

注意,private不在dir(a)的列表中。

print('private' in dir(a))
# False

虽然这样做是可能的,但我认为这不是在Python中推荐的编程方式。


上面提到的private是所有A的实例共享的。如果想要让每个实例都有自己的私有数据,可以在字典的键中加上self

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

撰写回答