Rename Methods on the Fly

2019-02-19 13:26发布

问题:

We can rename class methods at class definition time with a metaclass. This question is not about that.

This is more of a thought experiment, so humour me a little please.

Say I wanted to write two decorators that are used like this:

class SomeClass(object):

    @append_A
    def some_method( self ):
        pass

    @append_B
    def some_method( self ):
        pass

Which would result in SomeClass having two methods: some_method_A and some_method_B

Is this possible and if so, can you point me in the right direction?

I've tried changing the frame's f_locals a few different ways, but the method name still persists.

回答1:

No, it's not possible to change method names using decorator, as explained in the documentation:

The decorator syntax is merely syntactic sugar, the following two function definitions are semantically equivalent:

def f(...):
    ...
f = staticmethod(f)

@staticmethod
def f(...):
    ...

More syntax discussion goes here.

Update

I guess we could do something like leave the method alone in the decorator but also add a new method with an edited name in the scope it was defined (this case the class). The main thing is defining two methods with the same name then ending up with two differently named methods which are passed to the metaclass.

For this purpose you can use the class decorator:

def append_B(func):
  func.suffix='_B'
  return func

def appendable(class_obj):
  for name in dir(class_obj):
    if not name.startswith('_'):
      attr = class_obj.__dict__[name] #getattr(class_obj, name)
      suffix = getattr(attr, 'suffix', None)
      if isinstance(suffix,str):
        attr.suffix = None
        setattr(class_obj,name+suffix, getattr(class_obj, name))
        #delattr(class_obj,name)
  return class_obj

The following usage allows you to define two names for the same method:

@appendable
class B(object):
  @append_B
  def some_method(s):
    print 'B.some_method'

b=B()
b.some_method()
b.some_method_B()