pylint
pylint copied to clipboard
False positive on member classes accessing private attributes of parent
Bug description
In the example below, it's completely normal for the Command class to access a private member of the Service class.
class Service:
class Command:
def __init__(self, service:'Service'):
reply = queue.Queue()
self.service = service
def execute(self):
self.service._execute(self.reply)
def get_reply(self):
return self.reply.get()
def __init__(self):
self.commands = queue.Queue()
self.running = True
self.worker = threading.Thread(target=self.run)
self.worker.start()
def run(self):
while self.running:
try:
command = self.commands.get(timeout=1)
command.execute()
except queue.Empty:
pass
def _execute(self, reply):
reply.put("Done")
def Execute(self):
command = Service.Command()
self.commands.put(command)
return command.get_reply()
Command used
pylint lint.py
Pylint output
************* Module lint
lint.py:11:12: W0212: Access to a protected member _execute of a client class (protected-access)
------------------------------------------------------------------
Your code has been rated at 9.66/10 (previous run: 9.66/10, +0.00)
Expected behavior
It should be okay for a member class to access its parents' private attributes. I can't think of a clearer way to express that the two classes are intimately related.
Pylint version
$ pylint --version
pylint 2.15.6
astroid 2.12.13
Python 3.10.6 (main, Nov 2 2022, 18:53:38) [GCC 11.3.0]
OS / Environment
Ubuntu 22.04
This is a more specific version of #4362 .
Shorter reproducing example:
class Service:
class Command:
def __init__(self, service):
self.reply = []
self.service = service
def execute(self):
# Access to a protected member _execute of a client class (protected-access)
self.service._execute(self.reply)
def __init__(self):
self.commands = []
def _execute(self, reply):
reply.append("Done")
def execute(self):
command = Service.Command(self)
self.commands.append(command)
Shorter still and more abstract:
class Outer:
class Inner:
def protected_access(self, outer):
print(outer._attr)
def __init__(self, val):
self._attr = val
Outer.Inner().protected_access(self)
Personally, I am not convinced that an object of Inner class should automatically have access to private methods of each object of Outer class just because Inner is defined inside Outer. I even tend to avoid accessing private methods of another object of the same class. Ideally, IMO, ._<name> should only follow self.
I have not found any documentation of the "best practices" of accessing private methods of other objects though. I imagine that explicitly allowing exceptions (friend classes) may be useful.