Reputation: 300
I have spent the day trying to find an answer to this question but have come up with nothing.
Suppose I have several classes, each containing a methods that are identical to those in the others.
class A:
def __init__(self, attr1, attr2, color):
self.__attr1 = attr1
self.__attr2 = attr2
self.__color = color
def set_color(self, color):
self.__color = color
class B:
def __init__(name, attr3, attr4, color):
self.__attr3 = attr3
self.__attr4 = attr4
self.__color = color
def set_color(self, color):
self.__color = color
In this example, the identical methods are reduced to just one identical method, set_color, to illustrate what I am trying to do.
Is there a way to eliminate repeating code, perhaps with an abstract class as follows?
class Parent:
def set_color(self, color):
self.__color = color
class A(Parent):
def __init__(self, attr1, attr2, color):
self.__attr1 = attr1
self.__attr2 = attr2
self.__color = color
class B(Parent):
def __init__(name, attr3, attr4, color):
self.__attr3 = attr3
self.__attr4 = attr4
self.__color = color
exampleA = A(attr1, attr2, "blue)
I want to be able change from blue to red in a way like this
so that I don't have to define the same methods within each class A
and B
exampleA.set_color("red")
but this doesn't work as I expected it to, it doesn't change the value of exampleA.__color
Upvotes: 2
Views: 1808
Reputation: 365925
You can't. The whole point of __private
-style attributes is that they're private. Base classes, subclasses, outsiders, nobody else can see the or modify them. If a base class or subclass tries, they will end up creating their own private attribute on the instance, completely independent of yours.
If you don't want that, just don't use __private
-style attributes.
So, what should you do?
Well, the most Pythonic thing is to just use public attributes, and scrap your getters and setters entirely: exampleA.color = 'red'
.
If you have a really good reason you need to hide the attributes, maybe you wanted to make them _private
instead of __private
, which means they're private only by convention, so your code will just work as-is. But again, I doubt you really need to hide them.
If you really, really need __private
members, but still really need to defeat the entire purpose of __private
members… well, in that case, I lied; you actually can access them, by manually mangling the names. For example, the attribute that's named __color
from inside class A
is named _A__color
from outside of class A
.
If you're wondering why Python lets you violate the __private
protection... well, unlike the similar feature in Java, this isn't meant to protect you against someone else's malicious code. What it protects you from is a scenario like this: You write a class A
with a an attribute __x
. I write a class B
with an attribute __x
. Someone else composes our classes by inheriting from both, without telling either you or me. My code still works, so does yours.
For further information, see the tutorial section on private variables, and the reference documentation on identifiers.
Upvotes: 5
Reputation: 599788
The only reason this wouldn't work exactly as you have it is because you're using attributes prefixed with __
, which makes them "private" and so not accessible to the parent class. Don't do that: just use normal attribute names.
Upvotes: 3