2

I wanted to access the class on which method is to be defined. This can be used, for example, to create alias for methods with decorator. This particular case could be implemented without using decorator (alias = original_name), but I would like to use decorator, primarily so because the aliasing will be visible along side the method definition at the top, useful when the method definition is long.

def method_alias(*aliases):
    def aliased(m):
        class_of_m = ??? # GET class of this method
        for alias in aliases:
            setattr(class_of_m, alias, m)
        return m
    return aliased

class Test():
    @method_alias('check', 'examine')
    def test():
        print('I am implemented with name "test"')

Later, I found here that the above could be implemented by using two decorators (first store the aliases as method attributes, later when the class is already created, add the attributes to class). Can it be done without decorating the class, i.e. only decorating the method? This requires getting access to the class name in the decorator.

DurgaDatta
  • 3,952
  • 4
  • 27
  • 34

1 Answers1

0

The short answer is no. The contents of the class body are evaluated before the class object is created, i.e. the function test is created and passed to the decorator without class Test already existing. The decorator is therefore unable to obtain a reference to it.

To solve the problem of method aliasing, I reckon three approaches:

  • Using a class decorator as described by your link.
  • Using a metaclass, which lets you modifies the class' __dict__ before the class object is created. (Implementing a metaclass class is acutally overriding the default constructor for class objects, see here. Also the metaclass usage syntax has changed in Python 3.)
  • Creating the aliases in the __init__ method for each instance of Test.

The first approach is probably the most straightforward. I wrote another example. It basically does the same as your link, but is more stripped down to make it a bit clearer.

def alias(*aliases):
    def decorator(f):
        f.aliases = set(aliases)
        return f
    return decorator

def apply_aliases(cls):
    for name, elem in list(cls.__dict__.items()):
        if not hasattr(elem, 'aliases'):
            continue
        for alias in elem.aliases:
            setattr(cls, alias, elem)
    return cls

@apply_aliases
class Test(object):
    @alias('check', 'examine')
    def test(self):
        print('I am implemented with name "test"')

Test().test()
Test().check()
Test().examine()
Community
  • 1
  • 1
code_onkel
  • 2,759
  • 1
  • 16
  • 31