【Python】私有变量机制
2022年 09月 27 日

子弹

class A:
    def __init__(self):
        self.v = 0

o = A()
o.v =1

v 就是正常的对象中的成员变量,C++ 和 java 中的私有变量只有在这个类内部才可以被访问,而在这个类之外这个变量是访问不到的。在 python 中把一个类的变量定义成私有变量的方法是通过他的名字来实现的,可以把这个属性或者变量或者方法的名字前面加至少两个下划线,同时后面至多有一个下划线来把他定义成私有变量。那我们最常见的方式就是把名字前加两个下划线。

class A:
    def __init__(self):
        self.__v = 0

o = A()
print(o.__v)
Traceback (most recent call last):
  File "c:\Users\Moe\Desktop\Note\1.py", line 6, in <module>
    print(o.__v)
AttributeError: 'A' object has no attribute '__v'

A 这个class的初始化里面,我们做 self.__v = 0, 那当我们在这个类外面的代码里想使用 o.__v 的时候,他就会报错。就会告诉你没有 __v 这个属性。

class A:
    def __init__(self):
        self.__v = 0
    
    def print_v(self):
        print(self.__v)

o = A()
o.print_v()

而如果我们给 A 写一个方法 print_v 让他打印 self.__v,然后在这个类之外使用 print_v 他就可以正常打印出这个值了。

class A:
    def __init__(self):
        self.__v = 0
    
    def __print_v(self):
        print(self.__v)

o = A()
o.__print_v()

这个规则对方法同样有效,如果在 print_v 前面加两个下划线,这个 o 就也没有办法使用这个方法了。

私有变量概念的存在当然是有意义的,一个明显的好处就是他让我们的封装变得更佳严格了,我们可以通过对变量和函数的命名告诉这段代码的使用者,这个变量或者这个函数是你不应该用的,同时他还提供了一个机制,防止这些变量和函数被误用。当然除此之外还有其他的好处,尤其是当我们涉及到继承的时候。

class A:
    valid_kwds = ["a"]
    def __init__(self, **kwargs):
        for key, val in kwargs.items():
            if key in self.valid_kwds:
                print(key, val)


class B(A):
    valid_kwds = ["b"]
    def __init__(self, **kwargs):
        left_kwargs = {}
        for key, val in kwargs.items():
            if key in self.valid_kwds:
                print(key, val)
            else:
                left_kwargs[key] = val
        super().__init__(**left_kwargs)

o = B(a=2, b=3)
b 3

我们有两个类 AB , B 继承了 A, 这两个类的共同特点就是都有一个类属性叫做 valid_kwds,这个 valid_kwds 保存了在初始化的时候 kwargs 里面有哪些 keyword 是可以被接受的。当我们尝试初始化的时候,B 先从这些 keyword 里面挑他需要的,然后挑剩下的再传给 A 。为了简单起见,我们就直接把他拿到的这个keyword 和 value 给打印出来了。当你一眼看上去的时候,这段程序是没有什么问题的。类 A 需要 a 这个keyword,类 B 需要 b这个 keyword。但当我们建立对象的时候,我们发现只有 b 3 这对 kwargs 被使用了,而本应该传到基类里的 keyword A 并没有被认为是合法的。这里的问题在第5行,当你去读取 self.valid.kwds 的时候,由于 self 是一个 b 对象,所以他的 valid_kwds 已经被覆盖掉了,第5行和第14行的 self.valid.kwds 是一样的, 所以在 类 A 的函数里面尽管他被调用了,但他不认为那个 a 是一个合法的 keyword argument。

class A:
    __valid_kwds = ["a"]
    def __init__(self, **kwargs):
        for key, val in kwargs.items():
            if key in self.__valid_kwds:
                print(key, val)


class B(A):
    __valid_kwds = ["b"]
    def __init__(self, **kwargs):
        left_kwargs = {}
        for key, val in kwargs.items():
            if key in self.__valid_kwds:
                print(key, val)
            else:
                left_kwargs[key] = val
        super().__init__(**left_kwargs)

o = B(a=2, b=3)
b 3
a 2

我们可以把 valid_kwds 变成私有变量来解决这个问题,由于私有变量是不会被继承和覆盖的,所以第5行的 __valid_kwds 将永远指向类 A 里定义的这个 __valid_kwds 。我们可以看到程序的运行结果,b 和 a 都被打印出来了。

当然类方法同样适用。有时候我不希望我类里面的成员被重载,我就可以把他变成私有的,这样可以保证在我自己的类里面调用这个函数的时候,他永远会调用的是我定义的这个函数,而不是继承我的类重新定义的同名的函数。

【Python】私有变量机制

class A:
    def __init__(self):
        self.v = 0

o = A()
o.v =1

v 就是正常的对象中的成员变量,C++ 和 java 中的私有变量只有在这个类内部才可以被访问,而在这个类之外这个变量是访问不到的。在 python 中把一个类的变量定义成私有变量的方法是通过他的名字来实现的,可以把这个属性或者变量或者方法的名字前面加至少两个下划线,同时后面至多有一个下划线来把他定义成私有变量。那我们最常见的方式就是把名字前加两个下划线。

class A:
    def __init__(self):
        self.__v = 0

o = A()
print(o.__v)
Traceback (most recent call last):
  File "c:\Users\Moe\Desktop\Note\1.py", line 6, in <module>
    print(o.__v)
AttributeError: 'A' object has no attribute '__v'

A 这个class的初始化里面,我们做 self.__v = 0, 那当我们在这个类外面的代码里想使用 o.__v 的时候,他就会报错。就会告诉你没有 __v 这个属性。

class A:
    def __init__(self):
        self.__v = 0
    
    def print_v(self):
        print(self.__v)

o = A()
o.print_v()

而如果我们给 A 写一个方法 print_v 让他打印 self.__v,然后在这个类之外使用 print_v 他就可以正常打印出这个值了。

class A:
    def __init__(self):
        self.__v = 0
    
    def __print_v(self):
        print(self.__v)

o = A()
o.__print_v()

这个规则对方法同样有效,如果在 print_v 前面加两个下划线,这个 o 就也没有办法使用这个方法了。

私有变量概念的存在当然是有意义的,一个明显的好处就是他让我们的封装变得更佳严格了,我们可以通过对变量和函数的命名告诉这段代码的使用者,这个变量或者这个函数是你不应该用的,同时他还提供了一个机制,防止这些变量和函数被误用。当然除此之外还有其他的好处,尤其是当我们涉及到继承的时候。

class A:
    valid_kwds = ["a"]
    def __init__(self, **kwargs):
        for key, val in kwargs.items():
            if key in self.valid_kwds:
                print(key, val)


class B(A):
    valid_kwds = ["b"]
    def __init__(self, **kwargs):
        left_kwargs = {}
        for key, val in kwargs.items():
            if key in self.valid_kwds:
                print(key, val)
            else:
                left_kwargs[key] = val
        super().__init__(**left_kwargs)

o = B(a=2, b=3)
b 3

我们有两个类 AB , B 继承了 A, 这两个类的共同特点就是都有一个类属性叫做 valid_kwds,这个 valid_kwds 保存了在初始化的时候 kwargs 里面有哪些 keyword 是可以被接受的。当我们尝试初始化的时候,B 先从这些 keyword 里面挑他需要的,然后挑剩下的再传给 A 。为了简单起见,我们就直接把他拿到的这个keyword 和 value 给打印出来了。当你一眼看上去的时候,这段程序是没有什么问题的。类 A 需要 a 这个keyword,类 B 需要 b这个 keyword。但当我们建立对象的时候,我们发现只有 b 3 这对 kwargs 被使用了,而本应该传到基类里的 keyword A 并没有被认为是合法的。这里的问题在第5行,当你去读取 self.valid.kwds 的时候,由于 self 是一个 b 对象,所以他的 valid_kwds 已经被覆盖掉了,第5行和第14行的 self.valid.kwds 是一样的, 所以在 类 A 的函数里面尽管他被调用了,但他不认为那个 a 是一个合法的 keyword argument。

class A:
    __valid_kwds = ["a"]
    def __init__(self, **kwargs):
        for key, val in kwargs.items():
            if key in self.__valid_kwds:
                print(key, val)


class B(A):
    __valid_kwds = ["b"]
    def __init__(self, **kwargs):
        left_kwargs = {}
        for key, val in kwargs.items():
            if key in self.__valid_kwds:
                print(key, val)
            else:
                left_kwargs[key] = val
        super().__init__(**left_kwargs)

o = B(a=2, b=3)
b 3
a 2

我们可以把 valid_kwds 变成私有变量来解决这个问题,由于私有变量是不会被继承和覆盖的,所以第5行的 __valid_kwds 将永远指向类 A 里定义的这个 __valid_kwds 。我们可以看到程序的运行结果,b 和 a 都被打印出来了。

当然类方法同样适用。有时候我不希望我类里面的成员被重载,我就可以把他变成私有的,这样可以保证在我自己的类里面调用这个函数的时候,他永远会调用的是我定义的这个函数,而不是继承我的类重新定义的同名的函数。

赞 (0)

评论区(暂无评论)

这里空空如也,快来评论吧~

我要评论