Reputation: 23
Can't call child attribute in parent method, here's the test:
#!/usr/bin/env python3
class A():
def getPath(self):
return self.__path
class B(A):
def __init__( self, name, path):
self.__name = name
self.__path = path
instance = B('test', '/home/test/Projects')
print(instance.getPath())
Running python test file $ ./test.py
returns
./test.py
Traceback (most recent call last):
File "./test.py", line 17, in <module>
print(instance.getPath())
File "./test.py", line 6, in getPath
return self.__path
AttributeError: 'B' object has no attribute '_A__path'
Upvotes: 2
Views: 4235
Reputation: 1380
You are getting this because you are using a private attribute. If you do it using a non-private attributes, it will succeed.
Private attributes in Python are designed to allow each class to have its own private copy of a variable without that variable being overridden by subclasses. So in B, __path means _B__path, and in A, __path means __A_path. This is exactly how Python is intended to work. https://docs.python.org/3/tutorial/classes.html#tut-private
Since want A to be able to access __path, you should not use double-underscores. Instead, you can use a single underscore, which is a convention to indicate that a variable is private, without actually enforcing it.
#!/usr/bin/env python3
class A():
def getPath(self):
return self._path
class B(A):
def __init__( self, name, path):
self.__name = name
self._path = path
instance = B('test', '/home/test/Projects')
print(instance.getPath())
$ ./test.py
/home/test/Projects
Upvotes: 5
Reputation: 530922
Don't use __path
unless you know why you need it. _path
is sufficient to mark it as "private". However, A.getPath
should not be trying to return anything that that isn't defined in A
itself. Instead, call A.__init__
from B.__init__
to ensure any A
-specific initialization is done correctly:
class A:
def __init__(self, path):
self._path = path
def get_path(self):
return self._path
class B(A):
def __init__(self, name, path):
super().__init__(path)
self._name = name
instance = B('test', '/home/test/Projects')
print(instance.get_path())
Now that _path
is properly isolated to A
, you could switch back to __path
if, for example, you were concerned about a child class adding its own _path
attribute.
class A:
def __init__(self, path):
self.__path = path
def get_path(self):
return self.__path
class B(A):
def __init__(self, name, path):
super().__init__(path)
self._name = name
self._path = "foo"
instance = B('test', '/home/test/Projects')
print("{}, not {}".format(instance.get_path(), instance._path))
Upvotes: 2