Search code examples
pythonpython-3.xpython-decorators

Name mangling in function decorators


I cannot use a decorator within a class declared in the same module as the decorator if the decorator name is a __double_leading_underscore type.

It's easier to explain with an example:

# Just a pass-through
def __decorator(fn):
  return fn

decorator = __decorator

class A(object):
  @decorator
  def test(self):
    return 1

print(A().test())
# Prints 1

If I change @decorator with @__decorator:

class A(object):
  @__decorator
  def test(self):
    return 1

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in A
NameError: name '_A__decorator' is not defined

It tries to find __decorator from within the class.

Is there a way to keep the naming convention but refer to the module instead of the class?


Solution

  • This is due to Python's name mangling. According to the docs

    Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

    Emphasis added.

    When the interpreter sees @__decorator within class A, it ignores the binding to decorator, textually replaces __decorator with _A__decorator and tries to evaluate that identifier, which gives you a NameError.