Subclassing a class with private members

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:

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?

Asked by: Blake855 | Posted: 06-10-2021

Answer 1

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.

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-clashes 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.

Answered by: Ada829 | Posted: 07-11-2021

Answer 2

"I know this seems to go against the general idea of private and public" Not really "against", just different from C++ and 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.

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.

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().

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.

Answered by: Aida758 | Posted: 07-11-2021

Answer 3

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".

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.

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.

Answered by: Ned306 | Posted: 07-11-2021

Similar questions

Python Cmd module, subclassing issue

I'm trying to work out what's not working in this code: #!/usr/bin/python import cmd class My_class (cmd.Cmd): """docstring for Twitter_handler""" def __init__(self): super(My_class, self).__init__() if __name__ == '__main__': my_handler = My_class() Here's the error I get Traceback (most recent call last): File "", line 12, in <module>...

Subclassing in Python

Is it possible to subclass dynamically? I know there's ____bases____ but I don't want to effect all instances of the class. I want the object cf to polymorph into a mixin of the DrvCrystalfontz class. Further into the hierarchy is a subclass of gobject that needs to be available at this level for connecting signals, and the solution below isn't sufficient. class DrvCrystalfontz: def __init__(self, model...

subclass - Subclassing python's dict, override of __setitem__ doesn't retain new value

I'm subclassing dict, but ran into a problem with setitem where one assignment works, but another assignment does not. I've boiled it down to the following basic problem: class CustomDict(dict): def __setitem__(self, key, value): super(CustomDict, self).__setitem__(key, value) Test 1 fails: data = {"message":"foo"} CustomDict(data)["message"] = "bar" pri...

python - Subclassing tuple with multiple __init__ arguments

The following code works: class Foo(tuple): def __init__(self, b): super(Foo, self).__init__(tuple(b)) if __name__ == '__main__': print Foo([3, 4]) $ python Result: DeprecationWarning: object.__init__() takes no parameters super(Foo, self).__init__(tuple(b)) (3, 4) But not the ...

Subclassing Decimal in Python

I want to use Decimal class in my Python program for doing financial calculations. Decimals to not work with floats - they need explicit conversion to strings first. So i decided to subclass Decimal to be able to work with floats without explicit conversions. # -*- coding: utf-8 -*- import decimal Decimal = decimal.Decimal def floatCheck ( obj ) : # usually Decimal does not work with...

python - A class subclass of itself. Why mutual subclassing is forbidden?

Complex question I assume, but studying OWL opened a new perspective to live, the universe and everything. I'm going philosophical here. I am trying to achieve a class C which is subclass of B which in turn is subclass of C. Just for fun, you know... So here it is >>> class A(object): pass ... >>> class B(A): pass ... >>> class C(B): pass ... >>> B.__ba...

What is the purpose of subclassing the class "object" in Python?

All the Python built-ins are subclasses of object and I come across many user-defined classes which are too. Why? What is the purpose of the class object? It's just an empty class, right?

set - Python, subclassing immutable types

I've the following class: class MySet(set): def __init__(self, arg=None): if isinstance(arg, basestring): arg = arg.split() set.__init__(self, arg) This works as expected (initialising the set with the words of the string rather than the letters). However when I want to do the same with the immutable version of set, the __init__ method seems t...

python - What to consider before subclassing list?

I was recently going over a coding problem I was having and someone looking at the code said that subclassing list was bad (my problem was unrelated to that class). He said that you shouldn't do it and that it came with a bunch of bad side effects. Is this true? I'm asking if list is generally bad to subclass and if so, what are the reasons. Alternately, what should I consider before subclassing list in Python?...

subclassing float to force fixed point printing precision in python

[Python 3.1] I'm following up on this answer: class prettyfloat(float): def __repr__(self): return "%0.2f" % self I know I need to keep track of my float literals (i.e., replace 3.0 with prettyfloat(3.0), etc.), and tha...

Still can't find your answer? Check out these communities...

PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python