Some good answers, but we're missing something obvious: class attributes
class Credential:
role = 'rx'
def __init__ (...
# (... rest of class definition)
class AXL(Credential):
role = 'r'
def __init__ (...
# (... rest of class definition)
If you want the quick answer: just remove the self.role = ...
lines from the __init__
functions, and instead have these role = ...
lines in as class attributes.
If you want the detailed answer: keep reading :)
The problem
The main problem lies in the last two lines of the __init__
function for Credential. First, it sets self.role
to 'rx'
, and then it uses self.role
to compute a value of self.username_file
. From the point of view of the AXL
class, this sets the wrong value for both attributes.
AXL needs to fix the value of self.role
after Credential sets it to 'rx'
, but before Credential uses it to set the value of username_file
. But it can't. Your problem is that these two things are happening right next to each other in Credential's __init__
function. There's no space in-between for AXL to intervene and change the result.
To fix the problem, one of these assignments needs to be moved out of Credential's __init__
function. The previous answers all decided to move username_file
. But in my humble opinion, it's easier and better to move role
. Instead of setting username_file
after the init function, we're going to set role
before the init function.
Class attributes
When the interpreter encounters a line like self.role = 'rx'
, it sets an instance attribute. This means that each particular Credential object gets its own personal value for role
. They're all stored separately, even if they all happen to be copies of the same string.
In your case, it looks like you want every Credential object to have the exact same role
as every other Credential object, and every AXL object to have the same role as every other AXL object. That's a perfect use case for a class attribute.
Class attributes are attributes that you define on the class itself, instead of on the individual instances. Importantly for our purposes, you can set them just once, when the class is defined. You don't have to set them again every time in the __init__
function.
I found a pretty good article on class attributes here.
The fixed Code
PATH = 'home_drive_'
PLATFORM = 'Linux_'
ITEM = '_PC'
class Credential:
role = 'rx'
def __init__(self, path, platform):
self.username_file = path + platform + ('The role should be the same as AXL role: ' + self.role)
class AXL(Credential):
role = 'r'
def __init__(self, path, platform, item):
super().__init__(path, platform)
self.item = item
def final(self):
return self.username_file + self.item
reg1 = AXL(PATH, PLATFORM, ITEM)
print('AXL role:', reg1.role)
print(reg1.username_file)
print(reg1.final())
sandbox
How it works
First, the interpreter executes the class definition for Credential, which creates the class and sets the class attribute Credential.role
to 'rx'
. An __init__
function is defined, but it isn't run.
Then the interpreter executes the the class definition for AXL. As before it creates the class and sets the class attribute. This time the attribut is AXL.role
, and it's set to 'r'
.
At last, an AXL
object is created, called reg1. This is when AXL.__init__
is actualy run, and in turn it runs Credential.__init__
.
Here's where it gets fun. Credential's __init__
function tries to access self.role
. self
is the reg1 object, so the interpreter tries to look up reg1.role
. reg1
doesn't have a role
attribute itself, but it's an instance of the AXL class, and the class does have a role
attribute, so the interpreter substitutes the value of AXL.role
for self.role
, and gets a value of 'r'
.
That last part is the interesting bit. Even though we're inside Credential's __init__
, the self
object is an instance of AXL, so AXL.role
is the value we want. And that's the value we get.