2

So here is my situation. I have a class ABCAdapter. Here I have declared a bunch of methods and between them I have:

@staticmethod 
def __prepare_param_names(attributes_list, prefix = None):
 ....some processing....

Now from another class, namely FlowService I do:

from tvb.core.adapters.abcadapter import ABCAdapter
...other imports and code...
def prepare_adapter(self, project_id, adapter_module, adapter_name):
 ...some more code here...
 interface = adapter_instance.get_attribute_list()
 interface = ABCAdapter.__prepare_param_names(interface)
 ...some more code here...

Now this fails at the call to the static method with:

 AttributeError: type object 'ABCAdapter' has no attribute '_FlowService__prepare_param_names'

Now I've not used static methods so far so what is the trick here?

Regards, Bogdan

asked Aug 10, 2011 at 9:50
3
  • 10
    Are you aware that __-prefixed method names get name-mangled, and thus are not accessible from outside the object? Commented Aug 10, 2011 at 9:52
  • 1
    Actually I always tought that was just a naming convention for an equivalent 'private' method. Thank for the input. Commented Aug 10, 2011 at 10:10
  • 1
    Just to clarify, the __-prefixed attributes are accessible outside, but their names are mangled, such that, for example, an attribute defined as __my_attribute in MyClass would be accessible as _MyClass__attribute_name. There is a naming convention of using a single underscore to prefix an attribute that shouldn't be accessed outside the class. Commented Aug 10, 2011 at 14:31

3 Answers 3

4

As you probably know, Python doesn't enforce protected/private attributes: all class attributes are globally accessible. However, there is a convention that attributes whose names start with at least one _ are an implementation detail and not part of the public API.

Double-underscored names are a slight hack used for the following use case. Suppose you have

class Mapping:
 def __init__(self, iterable):
 self.update(iterable)
 def update(self, iterable):
 <stuff>
class MappingSubclass(Mapping):
 def update(self, keys, values):
 <stuff>

Notice that Mapping defines a method update, which is called in __init__. The subclass then redefines update with a different signature. Since the initialiser of the subclass is inherited from Mapping while the update method is overridden, this will cause an error when run.

To avoid this, you want Mapping's copy of update to be specific to that class, and not changed by subclasses. To do this, Python lets you 'magically' include the name of the class in the attribute, which is done by prefixing it with a double underscore. That is, if we used __update instead of update, Python would automatically rename the attribute to (something like) _Mapping__update. Then, when a subclass overwrote update, the double-underscore version would remain class-local and hence not break. So we would do

class Mapping:
 def __init__(self, iterable):
 self.__update(iterable)
 def update(self, iterable):
 <stuff>
 __update = update # private copy for initialiser
class MappingSubclass(Mapping):
 def update(self, keys, values):
 <stuff>

Now, even though update is overwritten in MappingSubClass, the private copy of update saved as __update is mangled to _Mapping__update and hence the code works as it should.


Unfortunately, this does have the problem that attribute names prefixed with double-attributes look like one thing but are actually another. The usual advice, then, is not to use them unless you find yourself in this type of situation; a single underscore will suffice elsewhere.

answered Aug 10, 2011 at 10:34

Comments

1

Attributes starting with __ but not ending with __ are Python's "private" attributes.
They become renamed internally to _CLASSNAME__ATTRNAME, so you actually can still access them through this naming outside the class, but shouldn't be done. When the author wants them to be private, they are surely not private because he'd like to kick ass the user.

answered Aug 10, 2011 at 10:43

Comments

-3

It looks like the __ (double _) prefix is reserved; changing it to a single _ should do the trick.

answered Aug 10, 2011 at 9:56

1 Comment

It is not 'reserved', it just has a specific, but well defined, behaviour and it is intended to be used in a specific class not from a 'foreign' code.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.