12

Is there a function in the Python standard library to reproduce Python's name mangling scheme with a "private" attribute name? It seems like there would be, but I can't find it for the life of me.

I wrote this, but if there's a better way I'm all ears.

def mangle_name (cls, attrname) :
    prefix = '_' + cls.__name__.lstrip('_')

    if not attrname.startswith('__') :
        attrname = '__' + attrname

    if not attrname.endswith('__') :
        return prefix + attrname
    else :
        return attrname

class Foo :
    __some_such = 3

name = mangle_name(Foo, '__some_such')
print name
print hasattr(Foo(), name)
martineau
  • 119,623
  • 25
  • 170
  • 301
rectangletangle
  • 50,393
  • 94
  • 205
  • 275
  • 3
    I'm pretty sure there is no such function in the standard library. What do you need it for? – Sven Marnach Jun 13 '12 at 22:40
  • 8
    I can imagine this is almost always going to be used to do something bad. – Gareth Latty Jun 13 '12 at 22:47
  • Basically, I need to dynamically access an arbitrary class's private attributes. The function above works; however, there may problems with it that I'm unaware of (some unforeseen issue). So using someone else's seems like the best option. – rectangletangle Jun 13 '12 at 22:47
  • 2
    Lattyware's prediction confirmed. – msw Jun 13 '12 at 23:07
  • 6
    This is why using mangled names for "private" names is a *bad* idea, IMHO. Just use a single underscore if you want to flag a name as private to scare people away from using it externally. Name mangling is **not** designed for making private names, it's designed for disambiguating names when multiple classes in an inheritance hierarchy might want to use the same name (because Python's object model means all classes in an inheritance hierarchy share the same attribute-namespace within the instance). – Ben Jun 14 '12 at 02:17
  • 1
    I wrote a decorator that "Asserts" an attribute value before running a function. In this case, it is nice to be able to let the user assert even a private attribute. I'm not doing the above, but it is a valid reason to have an external function access a private attribute. This is what brought me here: http://stackoverflow.com/questions/12537904/python-private-name-mangling-and-instance-vs-class-attributes – Rafe Sep 21 '12 at 20:42
  • 1
    Is there an easy way to tell if an attribute has been inherited rather than defined on the class itself? I'd like to add an attribute to an object that is specifically about that object, or rather, its docstring. Docstrings are not inherited, and so I'd like for this to not be either. Ideally, I would put the attribute on the docstring itself, but Python doesn't allow setting attributes on strings. – asmeurer Apr 06 '13 at 01:21

1 Answers1

18

It looks like the compiler module has a Python implementation for this, the signature is mangle(name, klass) where klass is the class name, not the object itself.

Here is how you can access and use it:

>>> from compiler.misc import mangle
>>> mangle('__some_such', 'Foo')
'_Foo__some_such'

Note that the compiler module is deprecated since Python 2.6 and does not exist in Python 3.0.

Here is the function itself (from Python 2.7 source code) in case you just want to copy it into your source or verify that your version is equivalent:

MANGLE_LEN = 256 # magic constant from compile.c

def mangle(name, klass):
    if not name.startswith('__'):
        return name
    if len(name) + 2 >= MANGLE_LEN:
        return name
    if name.endswith('__'):
        return name
    try:
        i = 0
        while klass[i] == '_':
            i = i + 1
    except IndexError:
        return name
    klass = klass[i:]

    tlen = len(klass) + len(name)
    if tlen > MANGLE_LEN:
        klass = klass[:MANGLE_LEN-tlen]

    return "_%s%s" % (klass, name)
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • 4
    Is there no stdlib replacement in Python 3? It seems to me that it would be better to us a library function, in case someone uses a different value than 256. For example, what do PyPy, Jython, and IronPython use? – asmeurer Apr 06 '13 at 01:18