I've googled a bunch and can't seem to figure out how to actually do this:
Given I have a general purpose utility method like so:
def __square(n):
return n*n
Then I have some class where I might like to use this method internally:
def __square(n):
return n*n
class Foo:
def __init__(self):
self.baz = 2
def bar(self):
return self.baz + __square(self.baz)
Well, that doesn't work. I get NameError '_Foo__square' is not defined
Why?
As a workaround I've ended up doing things like this:
class Foo:
def __init__(self):
self.baz = 2
def bar(self):
return baz + self.square(self.baz)
def square(self,n):
return n*n
But that feels silly to me because the square function has nothing to do with a Foo instance, nor would I expect or want it to be a method on Foo instances.
What's the "pythonic" way of dealing with this sort of thing?
EDIT
I figured out at least one part of this: I was getting this behavior because I think of these utility methods as private, and I've been naming them like def __square(n):.
I didn't realize that was special, and when typing the example above I initially didn't type it that way. I've now edited the question to reflect how it was actually typed.
So now my question is: why does putting __ in front of a top level method break it, or seem to? I understood that to be the convention for naming "private things" in Python, since it doesn't work in this case what would you recommend instead?
You should not prefix your function name with two underscores - __ - the Python compiler performs a name mangling operation whenever a name prefixed by two underscores name is found in code inside a class. - Threfore your reference to __square is transformed in a reference to the non-existing _Foo_square at compile (to bytecode) time.
Just use a single _ like in _square and you won't have this error.
Python has no such a thing like "private" names. By convention - and convention only - a function or attribute prefixed with _ should not be called or accessed from code from other scopes.
Some write ups out there on the internet, in an effort to create equivalence for every concept existing in other wide-known OOP languages, actually mention that a double-underscore prefix is equivalent to "private" variables in those languages. That is a common mistake in older documentation - more recent articles avoid this fault.
The behavior a double-underscore prefix has is something different - which sometimes can serve the same purpose as private (as opposed to protected) attributes have: it does transform the variable name in an operation known as "name mangling" throughout Python's documentation. Usually this is used for an attribute name, and it is transformed into a name that is unique to the container class, in a way it will be accessible, by default, only on the class it was defined, not on its subclasses. The transformation is deterministic and well documented: one underscore and the class name is prepended to the attribute's name (two underscores included). Therefore, a Polygon class that would have an __area attribute would actually have a _Polygon__area at run time - and if a derived class Square(Polygon): class would try to access an __area attribute in its code, it would actually access _Square__area at run time. (But it would be possible to read and write the superclass' __area by explicitly writing Square._Polygon__area in the code)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With