How can I make an alias to a non-function member attribute in a Python class?

Brent Writes Code picture Brent Writes Code · Oct 25, 2010 · Viewed 7.1k times · Source

I'm in the midst of writing a Python library API and I often run into the scenario where my users want multiple different names for the same functions and variables.

If I have a Python class with the function foo() and I want to make an alias to it called bar(), that's super easy:

class Dummy:
   
   def __init__(self):
      pass

   def foo(self):
      pass

   bar = foo

Now I can do this with no problem:

d = Dummy()
d.foo()
d.bar()

What I'm wondering is what is the best way to do this with a class attribute that is a regular variable (e.g. a string) rather than a function? If I had this piece of code:

d = Dummy()
print(d.x)
print(d.xValue)

I want d.x and d.xValue to always print the same thing. If d.x changes, it should change d.xValue also (and vice-versa).

I can think of a number of ways to do this, but none of them seem as smooth as I'd like:

  • Write a custom annotation
  • Use the @property annotation and mess with the setter
  • Override the __setattr__ class functions

Which of these ways is best? Or is there another way? I can't help but feel that if it's so easy to make aliases for functions, it should be just as easy for arbitrary variables...

Answer

Ned Batchelder picture Ned Batchelder · Oct 25, 2010

You can provide a __setattr__ and __getattr__ that reference an aliases map:

class Dummy:
    aliases = {
        'xValue': 'x',
        'another': 'x',
    }

    def __init__(self):
        self.x = 17

    def __setattr__(self, name, value):
        name = self.aliases.get(name, name)
        object.__setattr__(self, name, value)

    def __getattr__(self, name):
        if name == "aliases":
            raise AttributeError  # http://nedbatchelder.com/blog/201010/surprising_getattr_recursion.html
        name = self.aliases.get(name, name)
        return object.__getattribute__(self, name)


d = Dummy()
assert d.x == 17
assert d.xValue == 17
d.x = 23
assert d.xValue == 23
d.xValue = 1492
assert d.x == 1492