Should we use private or protected methods for implementation details?

Hello,

I read in many places that we should avoid using private methods, e.g. __fun but we should go for protected ones _fun for stuff that is not going to be accessed outside the class. However, when using pyright, I am not alerted about _fun not been used, I am only alerted when the method is private.

Not knowing that a method is no longer used and can be removed safely is problematic, I am finding a lot of dead code. If I were to subclass my class, I would just switch whatever method I need in the subclass to protected anyway. Are the people telling us not to use protected methods wrong or am I missing anything?

Cheers.

That seems like an improvement suggestion for pyright; at the very least this should be configurable.

To answer why it it is bad practice to use private naming:

Basically in Python the saying is that we are all reasonable adults and therefore, if you use a variable starting with _, you are using internal features and it is your responsibility if something goes wrong.

Therefore private methods further force the user to not use a variable is seen as bad practice, because the user might really have a need to access it. The issue is, you can still access it via f"_{obj_class_name}{obj_name}", so for example _Student__password for a Student object with a private field __password. This process is called Name Mangling.

It just makes it harder for the user to do so, because linters and type checkers hide those variables usually.

I still rarely use private fields, but you should have good reasons to do so.

Edit: Add final quotation mark in f-string

HI @MegaIng

I opened an issue here. However, if this is fixed or not in pyright is not in my control. I see that I can use vulture and deadcode for this, but:

  • Vulture does not seem to be well maintained, well written or well documented.
  • Deadcode seems to be pretty much a one person project.

So there does not seem to be much out there to check for dead code that is as good as pyright.

Cheers.

Hi @JoniKauf

Unfortunately, given the lack of tools to flag protected methods when they are unused (see my reply above), I do not see any other way than to make all my protected methods private. At the end, having dead code out there is worse than the ocassional call to _MyClass__method, which I never ever had to do.

The only place where I might need that is if I need to unit test the methods. And if you think of it, if the method was meant to be accessed by the user, we would make it public, if not, then it’s better to make it hard to access.

Cheers.

You could install something to show the reference count of functions/methods above the function itself. Pylance already has a feature called “CodeLens” for that, but because you are in Neovim I think it won’t work.
Here is a reddit thread I found talking about something like that in Neovim.

Hi @JoniKauf

But this does not make sense to me.

  • If we have methods and attributes that I am not planning to share with any derived class, I should make them private, not protected, as it is often recommended. This makes intuitive sense, from the language design.
  • Besides that, there is a principle, that anything that is not meant to be shown, should be hidden. i.e. expose as much as needed and no more.
  • It does feel like we are not using the language properly and to get around our improper use, we are bringing this codelens tool that we should not need to begin with because standard type analyzers like pyright should do the job.
  • It is true that if we need to inherit from the class, we would not be able to re-use those methods. But do we have to inherit? We are trying to solve a problem that does not exist. Maybe at some point we will need inheritance, but not at this moment, not for this class. Then why bother implementing something that we do not actually need?

This all makes me think that we really should not be using protected methods or attributes, unless we plan to inherit them somewhere. I keep seeing dead code all over the place in my codebases.

Cheers.