使用私有成员对类进行子类化

时间:2022-09-02 09:31:26

One of the really nice things about python is the simplicity with which you can name variables that have the same name as the accessor:

关于python的一个非常好的事情是,你可以简单地命名与访问者同名的变量:

self.__value = 1

def value():
    return self.__value

Is there a simple way of providing access to the private members of a class that I wish to subclass? Often I wish to simply work with the raw data objects inside of a class without having to use accessors and mutators all the time.

是否有一种简单的方法来提供对我希望子类的类的私有成员的访问?通常我希望简单地使用类中的原始数据对象,而不必一直使用访问器和更改器。

I know this seems to go against the general idea of private and public, but usually the class I am trying to subclass is one of my own which I am quite happy to expose the members from to a subclass but not to an instance of that class. Is there a clean way of providing this distinction?

我知道这似乎违背了私有和公共的一般概念,但通常我尝试子类的类是我自己的类,我很乐意将成员公开给一个子类但不公开该类的实例。是否有一种干净的方式来提供这种区别?

3 个解决方案

#1


5  

Not conveniently, without further breaking encapsulation. The double-underscore attribute is name-mangled by prepending '_ClassName' for the class it is being accessed in. So, if you have a 'ContainerThing' class that has a '__value' attribute, the attribute is actually being stored as '_ContainerThing__value'. Changing the class name (or refactoring where the attribute is assigned to) would mean breaking all subclasses that try to access that attribute.

不方便,没有进一步破坏封装。双下划线属性通过在其所访问的类前面添加'_ClassName'来进行名称修改。因此,如果您有一个'__value'属性的'ContainerThing'类,该属性实际上存储为'_ContainerThing__value ”。更改类名(或重构属性的位置)将意味着破坏尝试访问该属性的所有子类。

This is exactly why the double-underscore name-mangling (which is not really "private", just "inconvenient") is a bad idea to use. Just use a single leading underscore. Everyone will know not to touch your 'private' attribute and you will still be able to access it in subclasses and other situations where it's darned handy. The name-mangling of double-underscore attributes is useful only to avoid name-*es for attributes that are truly specific to a particular class, which is extremely rare. It provides no extra 'security' since even the name-mangled attributes are trivially accessible.

这正是为什么双下划线名称修改(这不是真正的“私有”,只是“不方便”)是一个坏主意使用。只需使用一个前导下划线。每个人都知道不要触摸你的“私人”属性,你仍然可以在子类和其他方便的情况下访问它。双重下划线属性的名称修改仅用于避免特定于特定类的属性的名称冲突,这种情况极为罕见。它没有提供额外的“安全性”,因为即使是名称错误的属性也可以轻易访问。

For the record, '__value' and 'value' (and '_value') are not the same name. The underscores are part of the name.

对于记录,'__ value'和'value'(和'_value')不是同一个名字。下划线是名称的一部分。

#2


3  

"I know this seems to go against the general idea of private and public" Not really "against", just different from C++ and Java.

“我知道这似乎违背了私有和公共的一般概念”并非真正“反对”,只是与C ++和Java不同。

Private -- as implemented in C++ and Java is not a very useful concept. It helps, sometimes, to isolate implementation details. But it is way overused.

私有 - 用C ++和Java实现并不是一个非常有用的概念。有时,它有助于隔离实现细节。但它过度使用了。

Python names beginning with two __ are special and you should not, as a normal thing, be defining attributes with names like this. Names with __ are special and part of the implementation. And exposed for your use.

以两个__开头的Python名称是特殊的,作为一般情况,您不应该使用这样的名称定义属性。带__的名称是特殊的,是实现的一部分。并暴露供您使用。

Names beginning with one _ are "private". Sometimes they are concealed, a little. Most of the time, the "consenting adults" rule applies -- don't use them foolishly, they're subject to change without notice.

以一个_开头的名称是“私有的”。有时它们被隐藏了一点。大多数情况下,“同意成人”规则适用 - 不要愚蠢地使用它们,它们如有变更,恕不另行通知。

We put "private" in quotes because it's just an agreement between you and your users. You've marked things with _. Your users (and yourself) should honor that.

我们将“私人”放在引号中,因为它只是您和您的用户之间的协议。你用_标记了东西。您的用户(和您自己)应该尊重这一点。

Often, we have method function names with a leading _ to indicate that we consider them to be "private" and subject to change without notice.

通常,我们使用带有_的方法函数名称来表示我们认为它们是“私有的”,如有更改,恕不另行通知。

The endless getters and setters that Java requires aren't as often used in Python. Python introspection is more flexible, you have access to an object's internal dictionary of attribute values, and you have first class functions like getattr() and setattr().

Java所需的无尽的getter和setter并不像Python那样经常使用。 Python内省更灵活,您可以访问对象的属性值内部字典,并且您具有getattr()和setattr()等第一类函数。

Further, you have the property() function which is often used to bind getters and setters to a single name that behaves like a simple attribute, but is actually well-defined method function calls.

此外,您还具有property()函数,该函数通常用于将getter和setter绑定到一个行为类似于简单属性的名称,但实际上是定义良好的方法函数调用。

#3


1  

Not sure of where to cite it from, but the following statement in regard to access protection is Pythonic canon: "We're all consenting adults here".

不确定从哪里引用它,但关于访问保护的以下声明是Pythonic canon:“我们都在这里同意成年人”。

Just as Thomas Wouters has stated, a single leading underscore is the idiomatic way of marking an attribute as being a part of the object's internal state. Two underscores just provides name mangling to prevent easy access to the attribute.

正如Thomas Wouters所说,单一的前导下划线是将属性标记为对象内部状态的一部分的惯用方法。两个下划线仅提供名称修改以防止轻松访问属性。

After that, you should just expect that the client of your library won't go and shoot themselves in the foot by meddling with the "private" attributes.

在那之后,你应该只是期望你的图书馆的客户不会通过干涉“私人”属性去拍摄自己。

#1


5  

Not conveniently, without further breaking encapsulation. The double-underscore attribute is name-mangled by prepending '_ClassName' for the class it is being accessed in. So, if you have a 'ContainerThing' class that has a '__value' attribute, the attribute is actually being stored as '_ContainerThing__value'. Changing the class name (or refactoring where the attribute is assigned to) would mean breaking all subclasses that try to access that attribute.

不方便,没有进一步破坏封装。双下划线属性通过在其所访问的类前面添加'_ClassName'来进行名称修改。因此,如果您有一个'__value'属性的'ContainerThing'类,该属性实际上存储为'_ContainerThing__value ”。更改类名(或重构属性的位置)将意味着破坏尝试访问该属性的所有子类。

This is exactly why the double-underscore name-mangling (which is not really "private", just "inconvenient") is a bad idea to use. Just use a single leading underscore. Everyone will know not to touch your 'private' attribute and you will still be able to access it in subclasses and other situations where it's darned handy. The name-mangling of double-underscore attributes is useful only to avoid name-*es for attributes that are truly specific to a particular class, which is extremely rare. It provides no extra 'security' since even the name-mangled attributes are trivially accessible.

这正是为什么双下划线名称修改(这不是真正的“私有”,只是“不方便”)是一个坏主意使用。只需使用一个前导下划线。每个人都知道不要触摸你的“私人”属性,你仍然可以在子类和其他方便的情况下访问它。双重下划线属性的名称修改仅用于避免特定于特定类的属性的名称冲突,这种情况极为罕见。它没有提供额外的“安全性”,因为即使是名称错误的属性也可以轻易访问。

For the record, '__value' and 'value' (and '_value') are not the same name. The underscores are part of the name.

对于记录,'__ value'和'value'(和'_value')不是同一个名字。下划线是名称的一部分。

#2


3  

"I know this seems to go against the general idea of private and public" Not really "against", just different from C++ and Java.

“我知道这似乎违背了私有和公共的一般概念”并非真正“反对”,只是与C ++和Java不同。

Private -- as implemented in C++ and Java is not a very useful concept. It helps, sometimes, to isolate implementation details. But it is way overused.

私有 - 用C ++和Java实现并不是一个非常有用的概念。有时,它有助于隔离实现细节。但它过度使用了。

Python names beginning with two __ are special and you should not, as a normal thing, be defining attributes with names like this. Names with __ are special and part of the implementation. And exposed for your use.

以两个__开头的Python名称是特殊的,作为一般情况,您不应该使用这样的名称定义属性。带__的名称是特殊的,是实现的一部分。并暴露供您使用。

Names beginning with one _ are "private". Sometimes they are concealed, a little. Most of the time, the "consenting adults" rule applies -- don't use them foolishly, they're subject to change without notice.

以一个_开头的名称是“私有的”。有时它们被隐藏了一点。大多数情况下,“同意成人”规则适用 - 不要愚蠢地使用它们,它们如有变更,恕不另行通知。

We put "private" in quotes because it's just an agreement between you and your users. You've marked things with _. Your users (and yourself) should honor that.

我们将“私人”放在引号中,因为它只是您和您的用户之间的协议。你用_标记了东西。您的用户(和您自己)应该尊重这一点。

Often, we have method function names with a leading _ to indicate that we consider them to be "private" and subject to change without notice.

通常,我们使用带有_的方法函数名称来表示我们认为它们是“私有的”,如有更改,恕不另行通知。

The endless getters and setters that Java requires aren't as often used in Python. Python introspection is more flexible, you have access to an object's internal dictionary of attribute values, and you have first class functions like getattr() and setattr().

Java所需的无尽的getter和setter并不像Python那样经常使用。 Python内省更灵活,您可以访问对象的属性值内部字典,并且您具有getattr()和setattr()等第一类函数。

Further, you have the property() function which is often used to bind getters and setters to a single name that behaves like a simple attribute, but is actually well-defined method function calls.

此外,您还具有property()函数,该函数通常用于将getter和setter绑定到一个行为类似于简单属性的名称,但实际上是定义良好的方法函数调用。

#3


1  

Not sure of where to cite it from, but the following statement in regard to access protection is Pythonic canon: "We're all consenting adults here".

不确定从哪里引用它,但关于访问保护的以下声明是Pythonic canon:“我们都在这里同意成年人”。

Just as Thomas Wouters has stated, a single leading underscore is the idiomatic way of marking an attribute as being a part of the object's internal state. Two underscores just provides name mangling to prevent easy access to the attribute.

正如Thomas Wouters所说,单一的前导下划线是将属性标记为对象内部状态的一部分的惯用方法。两个下划线仅提供名称修改以防止轻松访问属性。

After that, you should just expect that the client of your library won't go and shoot themselves in the foot by meddling with the "private" attributes.

在那之后,你应该只是期望你的图书馆的客户不会通过干涉“私人”属性去拍摄自己。