How to detect is decorator has been applied to method or function?












3















The goal is that I wan't to have one decorator that will work with both, function and instance methods, and I would like to retrieve within wrapping function the self object when decorator has been applied on method or the function object itself when applied to function.



Here's what I have found almost working, this is only the func I'm using to detect on what decorator has been applied:



def _is_method(func):
for stack_frame in inspect.stack():
# if the code_context of the stack frame starts with 'class' this
# function is defined within a class and so a method.
if inspect.getframeinfo(stack_frame[0]).code_context[0].strip().startswith('class'):
return True
return False


This does work for me, with one small exception, It throws exceptions when I run tests in parallel in multiple processes.










share|improve this question



























    3















    The goal is that I wan't to have one decorator that will work with both, function and instance methods, and I would like to retrieve within wrapping function the self object when decorator has been applied on method or the function object itself when applied to function.



    Here's what I have found almost working, this is only the func I'm using to detect on what decorator has been applied:



    def _is_method(func):
    for stack_frame in inspect.stack():
    # if the code_context of the stack frame starts with 'class' this
    # function is defined within a class and so a method.
    if inspect.getframeinfo(stack_frame[0]).code_context[0].strip().startswith('class'):
    return True
    return False


    This does work for me, with one small exception, It throws exceptions when I run tests in parallel in multiple processes.










    share|improve this question

























      3












      3








      3


      2






      The goal is that I wan't to have one decorator that will work with both, function and instance methods, and I would like to retrieve within wrapping function the self object when decorator has been applied on method or the function object itself when applied to function.



      Here's what I have found almost working, this is only the func I'm using to detect on what decorator has been applied:



      def _is_method(func):
      for stack_frame in inspect.stack():
      # if the code_context of the stack frame starts with 'class' this
      # function is defined within a class and so a method.
      if inspect.getframeinfo(stack_frame[0]).code_context[0].strip().startswith('class'):
      return True
      return False


      This does work for me, with one small exception, It throws exceptions when I run tests in parallel in multiple processes.










      share|improve this question














      The goal is that I wan't to have one decorator that will work with both, function and instance methods, and I would like to retrieve within wrapping function the self object when decorator has been applied on method or the function object itself when applied to function.



      Here's what I have found almost working, this is only the func I'm using to detect on what decorator has been applied:



      def _is_method(func):
      for stack_frame in inspect.stack():
      # if the code_context of the stack frame starts with 'class' this
      # function is defined within a class and so a method.
      if inspect.getframeinfo(stack_frame[0]).code_context[0].strip().startswith('class'):
      return True
      return False


      This does work for me, with one small exception, It throws exceptions when I run tests in parallel in multiple processes.







      python






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Oct 11 '13 at 9:11









      cannicanni

      2,73662862




      2,73662862
























          4 Answers
          4






          active

          oldest

          votes


















          3














          You can solve this problem using descriptor protocol. By returning non-data descriptor from decorator you get to implement __get__ where you can save the method's instance/class.



          Another (simpler) way would be to detect instance/class late, in decorator-made wrapper which may have self or cls as first of *args. This improves "inspectability" of decorated function, as it's still a plain function and not a custom non-data-desctiptor/function-object.



          Problem we have to solve is that we cannot hook into or before the method binding:




          Note that the transformation from function object to (unbound or bound)
          method object happens each time the attribute is retrieved from the class
          or instance.




          In other words: when our wrapper runs, its descriptor protocol, namely __get__ method-wrapper of function, has already bound function with class/instance and resulting method is already being executed. We're left with args/kwargs and no straightforwardly accessible class-related info in current stack frame.



          Let's start with solving class/staticmethod special cases and implementing wrapper as simple printer:



          def decorated(fun):
          desc = next((desc for desc in (staticmethod, classmethod)
          if isinstance(fun, desc)), None)
          if desc:
          fun = fun.__func__

          @wraps(fun)
          def wrap(*args, **kwargs):
          cls, nonselfargs = _declassify(fun, args)
          clsname = cls.__name__ if cls else None
          print('class: %-10s func: %-15s args: %-10s kwargs: %-10s' %
          (clsname, fun.__name__, nonselfargs, kwargs))

          wrap.original = fun

          if desc:
          wrap = desc(wrap)
          return wrap


          Here comes the tricky part - if this was a method/classmethod call, first of args must be instance/class respectively. If so, we can get the very method we execute from this arg. If so, wrapper which we implemented above will be inside as __func__. If so, original member will be in our wrapper. If it is identical to fun from closure, we're home and can slice instance/class safely from remaining args.



          def _declassify(fun, args):
          if len(args):
          met = getattr(args[0], fun.__name__, None)
          if met:
          wrap = getattr(met, '__func__', None)
          if getattr(wrap, 'original', None) is fun:
          maybe_cls = args[0]
          cls = maybe_cls if isclass(maybe_cls) else maybe_cls.__class__
          return cls, args[1:]
          return None, args


          Let's see if this works with different variants of functions/methods:



          @decorated
          def simplefun():
          pass

          class Class(object):
          @decorated
          def __init__(self):
          pass

          @decorated
          def method(self, a, b):
          pass

          @decorated
          @staticmethod
          def staticmethod(a1, a2=None):
          pass

          @decorated
          @classmethod
          def classmethod(cls):
          pass


          Let's see if this actually runs:



          simplefun()
          instance = Class()
          instance.method(1, 2)
          instance.staticmethod(a1=3)
          instance.classmethod()
          Class.staticmethod(a1=3)
          Class.classmethod()


          output:



          $ python Example5.py 
          class: None func: simplefun args: () kwargs: {}
          class: Class func: __init__ args: () kwargs: {}
          class: Class func: method args: (1, 2) kwargs: {}
          class: None func: staticmethod args: () kwargs: {'a1': 3}
          class: Class func: classmethod args: () kwargs: {}
          class: None func: staticmethod args: () kwargs: {'a1': 3}
          class: Class func: classmethod args: () kwargs: {}





          share|improve this answer


























          • It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

            – bartolo-otrit
            Nov 16 '18 at 7:50






          • 1





            I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

            – aurzenligl
            Nov 25 '18 at 23:17





















          2














          You can use inspect.getargspec:



          import inspect

          def _is_method(func):
          spec = inspect.getargspec(func)
          return spec.args and spec.args[0] == 'self'


          Example usage:



          >>> def dummy_deco(f):
          ... print('{} is method? {}'.format(f.__name__, _is_method(f)))
          ... return f
          ...
          >>> @dummy_deco
          ... def add(a, b):
          ... return a + b
          ...
          add is method? False
          >>> class A:
          ... @dummy_deco
          ... def meth(self, a, b):
          ... return a + b
          ...
          meth is method? True


          NOTE This code depend on the name of the first argument. If the name is not self it will treat it as non-instance-method even though it is.






          share|improve this answer
























          • Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

            – canni
            Oct 11 '13 at 12:26



















          1














          Thanks to this SO answer: Using the same decorator (with arguments) with functions and methods



          I came to this solution witch works for me flawlessly:



          def proofOfConcept():
          def wrapper(func):

          class MethodDecoratorAdapter(object):
          def __init__(self, func):
          self.func = func
          self.is_method = False

          def __get__(self, instance, owner):
          if not self.is_method:
          self.is_method = True
          self.instance = instance

          return self

          def __call__(self, *args, **kwargs):
          # Decorator real logic goes here
          if self.is_method:
          return self.func(self.instance, *args, **kwargs)
          else:
          return self.func(*args, **kwargs)

          return wraps(func)(MethodDecoratorAdapter(func))

          return wrapper


          NOTE This is not thread safe, to have a thread safe method one must return a callable object from __get__ that will have scope tied to instance






          share|improve this answer

































            1














            Solution for python3:



            import inspect

            def _is_method(func):
            spec = inspect.signature(func)
            if len(spec.parameters) > 0:
            if list(spec.parameters.keys())[0] == 'self':
            return True
            return False





            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f19314405%2fhow-to-detect-is-decorator-has-been-applied-to-method-or-function%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              4 Answers
              4






              active

              oldest

              votes








              4 Answers
              4






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              3














              You can solve this problem using descriptor protocol. By returning non-data descriptor from decorator you get to implement __get__ where you can save the method's instance/class.



              Another (simpler) way would be to detect instance/class late, in decorator-made wrapper which may have self or cls as first of *args. This improves "inspectability" of decorated function, as it's still a plain function and not a custom non-data-desctiptor/function-object.



              Problem we have to solve is that we cannot hook into or before the method binding:




              Note that the transformation from function object to (unbound or bound)
              method object happens each time the attribute is retrieved from the class
              or instance.




              In other words: when our wrapper runs, its descriptor protocol, namely __get__ method-wrapper of function, has already bound function with class/instance and resulting method is already being executed. We're left with args/kwargs and no straightforwardly accessible class-related info in current stack frame.



              Let's start with solving class/staticmethod special cases and implementing wrapper as simple printer:



              def decorated(fun):
              desc = next((desc for desc in (staticmethod, classmethod)
              if isinstance(fun, desc)), None)
              if desc:
              fun = fun.__func__

              @wraps(fun)
              def wrap(*args, **kwargs):
              cls, nonselfargs = _declassify(fun, args)
              clsname = cls.__name__ if cls else None
              print('class: %-10s func: %-15s args: %-10s kwargs: %-10s' %
              (clsname, fun.__name__, nonselfargs, kwargs))

              wrap.original = fun

              if desc:
              wrap = desc(wrap)
              return wrap


              Here comes the tricky part - if this was a method/classmethod call, first of args must be instance/class respectively. If so, we can get the very method we execute from this arg. If so, wrapper which we implemented above will be inside as __func__. If so, original member will be in our wrapper. If it is identical to fun from closure, we're home and can slice instance/class safely from remaining args.



              def _declassify(fun, args):
              if len(args):
              met = getattr(args[0], fun.__name__, None)
              if met:
              wrap = getattr(met, '__func__', None)
              if getattr(wrap, 'original', None) is fun:
              maybe_cls = args[0]
              cls = maybe_cls if isclass(maybe_cls) else maybe_cls.__class__
              return cls, args[1:]
              return None, args


              Let's see if this works with different variants of functions/methods:



              @decorated
              def simplefun():
              pass

              class Class(object):
              @decorated
              def __init__(self):
              pass

              @decorated
              def method(self, a, b):
              pass

              @decorated
              @staticmethod
              def staticmethod(a1, a2=None):
              pass

              @decorated
              @classmethod
              def classmethod(cls):
              pass


              Let's see if this actually runs:



              simplefun()
              instance = Class()
              instance.method(1, 2)
              instance.staticmethod(a1=3)
              instance.classmethod()
              Class.staticmethod(a1=3)
              Class.classmethod()


              output:



              $ python Example5.py 
              class: None func: simplefun args: () kwargs: {}
              class: Class func: __init__ args: () kwargs: {}
              class: Class func: method args: (1, 2) kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}





              share|improve this answer


























              • It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

                – bartolo-otrit
                Nov 16 '18 at 7:50






              • 1





                I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

                – aurzenligl
                Nov 25 '18 at 23:17


















              3














              You can solve this problem using descriptor protocol. By returning non-data descriptor from decorator you get to implement __get__ where you can save the method's instance/class.



              Another (simpler) way would be to detect instance/class late, in decorator-made wrapper which may have self or cls as first of *args. This improves "inspectability" of decorated function, as it's still a plain function and not a custom non-data-desctiptor/function-object.



              Problem we have to solve is that we cannot hook into or before the method binding:




              Note that the transformation from function object to (unbound or bound)
              method object happens each time the attribute is retrieved from the class
              or instance.




              In other words: when our wrapper runs, its descriptor protocol, namely __get__ method-wrapper of function, has already bound function with class/instance and resulting method is already being executed. We're left with args/kwargs and no straightforwardly accessible class-related info in current stack frame.



              Let's start with solving class/staticmethod special cases and implementing wrapper as simple printer:



              def decorated(fun):
              desc = next((desc for desc in (staticmethod, classmethod)
              if isinstance(fun, desc)), None)
              if desc:
              fun = fun.__func__

              @wraps(fun)
              def wrap(*args, **kwargs):
              cls, nonselfargs = _declassify(fun, args)
              clsname = cls.__name__ if cls else None
              print('class: %-10s func: %-15s args: %-10s kwargs: %-10s' %
              (clsname, fun.__name__, nonselfargs, kwargs))

              wrap.original = fun

              if desc:
              wrap = desc(wrap)
              return wrap


              Here comes the tricky part - if this was a method/classmethod call, first of args must be instance/class respectively. If so, we can get the very method we execute from this arg. If so, wrapper which we implemented above will be inside as __func__. If so, original member will be in our wrapper. If it is identical to fun from closure, we're home and can slice instance/class safely from remaining args.



              def _declassify(fun, args):
              if len(args):
              met = getattr(args[0], fun.__name__, None)
              if met:
              wrap = getattr(met, '__func__', None)
              if getattr(wrap, 'original', None) is fun:
              maybe_cls = args[0]
              cls = maybe_cls if isclass(maybe_cls) else maybe_cls.__class__
              return cls, args[1:]
              return None, args


              Let's see if this works with different variants of functions/methods:



              @decorated
              def simplefun():
              pass

              class Class(object):
              @decorated
              def __init__(self):
              pass

              @decorated
              def method(self, a, b):
              pass

              @decorated
              @staticmethod
              def staticmethod(a1, a2=None):
              pass

              @decorated
              @classmethod
              def classmethod(cls):
              pass


              Let's see if this actually runs:



              simplefun()
              instance = Class()
              instance.method(1, 2)
              instance.staticmethod(a1=3)
              instance.classmethod()
              Class.staticmethod(a1=3)
              Class.classmethod()


              output:



              $ python Example5.py 
              class: None func: simplefun args: () kwargs: {}
              class: Class func: __init__ args: () kwargs: {}
              class: Class func: method args: (1, 2) kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}





              share|improve this answer


























              • It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

                – bartolo-otrit
                Nov 16 '18 at 7:50






              • 1





                I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

                – aurzenligl
                Nov 25 '18 at 23:17
















              3












              3








              3







              You can solve this problem using descriptor protocol. By returning non-data descriptor from decorator you get to implement __get__ where you can save the method's instance/class.



              Another (simpler) way would be to detect instance/class late, in decorator-made wrapper which may have self or cls as first of *args. This improves "inspectability" of decorated function, as it's still a plain function and not a custom non-data-desctiptor/function-object.



              Problem we have to solve is that we cannot hook into or before the method binding:




              Note that the transformation from function object to (unbound or bound)
              method object happens each time the attribute is retrieved from the class
              or instance.




              In other words: when our wrapper runs, its descriptor protocol, namely __get__ method-wrapper of function, has already bound function with class/instance and resulting method is already being executed. We're left with args/kwargs and no straightforwardly accessible class-related info in current stack frame.



              Let's start with solving class/staticmethod special cases and implementing wrapper as simple printer:



              def decorated(fun):
              desc = next((desc for desc in (staticmethod, classmethod)
              if isinstance(fun, desc)), None)
              if desc:
              fun = fun.__func__

              @wraps(fun)
              def wrap(*args, **kwargs):
              cls, nonselfargs = _declassify(fun, args)
              clsname = cls.__name__ if cls else None
              print('class: %-10s func: %-15s args: %-10s kwargs: %-10s' %
              (clsname, fun.__name__, nonselfargs, kwargs))

              wrap.original = fun

              if desc:
              wrap = desc(wrap)
              return wrap


              Here comes the tricky part - if this was a method/classmethod call, first of args must be instance/class respectively. If so, we can get the very method we execute from this arg. If so, wrapper which we implemented above will be inside as __func__. If so, original member will be in our wrapper. If it is identical to fun from closure, we're home and can slice instance/class safely from remaining args.



              def _declassify(fun, args):
              if len(args):
              met = getattr(args[0], fun.__name__, None)
              if met:
              wrap = getattr(met, '__func__', None)
              if getattr(wrap, 'original', None) is fun:
              maybe_cls = args[0]
              cls = maybe_cls if isclass(maybe_cls) else maybe_cls.__class__
              return cls, args[1:]
              return None, args


              Let's see if this works with different variants of functions/methods:



              @decorated
              def simplefun():
              pass

              class Class(object):
              @decorated
              def __init__(self):
              pass

              @decorated
              def method(self, a, b):
              pass

              @decorated
              @staticmethod
              def staticmethod(a1, a2=None):
              pass

              @decorated
              @classmethod
              def classmethod(cls):
              pass


              Let's see if this actually runs:



              simplefun()
              instance = Class()
              instance.method(1, 2)
              instance.staticmethod(a1=3)
              instance.classmethod()
              Class.staticmethod(a1=3)
              Class.classmethod()


              output:



              $ python Example5.py 
              class: None func: simplefun args: () kwargs: {}
              class: Class func: __init__ args: () kwargs: {}
              class: Class func: method args: (1, 2) kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}





              share|improve this answer















              You can solve this problem using descriptor protocol. By returning non-data descriptor from decorator you get to implement __get__ where you can save the method's instance/class.



              Another (simpler) way would be to detect instance/class late, in decorator-made wrapper which may have self or cls as first of *args. This improves "inspectability" of decorated function, as it's still a plain function and not a custom non-data-desctiptor/function-object.



              Problem we have to solve is that we cannot hook into or before the method binding:




              Note that the transformation from function object to (unbound or bound)
              method object happens each time the attribute is retrieved from the class
              or instance.




              In other words: when our wrapper runs, its descriptor protocol, namely __get__ method-wrapper of function, has already bound function with class/instance and resulting method is already being executed. We're left with args/kwargs and no straightforwardly accessible class-related info in current stack frame.



              Let's start with solving class/staticmethod special cases and implementing wrapper as simple printer:



              def decorated(fun):
              desc = next((desc for desc in (staticmethod, classmethod)
              if isinstance(fun, desc)), None)
              if desc:
              fun = fun.__func__

              @wraps(fun)
              def wrap(*args, **kwargs):
              cls, nonselfargs = _declassify(fun, args)
              clsname = cls.__name__ if cls else None
              print('class: %-10s func: %-15s args: %-10s kwargs: %-10s' %
              (clsname, fun.__name__, nonselfargs, kwargs))

              wrap.original = fun

              if desc:
              wrap = desc(wrap)
              return wrap


              Here comes the tricky part - if this was a method/classmethod call, first of args must be instance/class respectively. If so, we can get the very method we execute from this arg. If so, wrapper which we implemented above will be inside as __func__. If so, original member will be in our wrapper. If it is identical to fun from closure, we're home and can slice instance/class safely from remaining args.



              def _declassify(fun, args):
              if len(args):
              met = getattr(args[0], fun.__name__, None)
              if met:
              wrap = getattr(met, '__func__', None)
              if getattr(wrap, 'original', None) is fun:
              maybe_cls = args[0]
              cls = maybe_cls if isclass(maybe_cls) else maybe_cls.__class__
              return cls, args[1:]
              return None, args


              Let's see if this works with different variants of functions/methods:



              @decorated
              def simplefun():
              pass

              class Class(object):
              @decorated
              def __init__(self):
              pass

              @decorated
              def method(self, a, b):
              pass

              @decorated
              @staticmethod
              def staticmethod(a1, a2=None):
              pass

              @decorated
              @classmethod
              def classmethod(cls):
              pass


              Let's see if this actually runs:



              simplefun()
              instance = Class()
              instance.method(1, 2)
              instance.staticmethod(a1=3)
              instance.classmethod()
              Class.staticmethod(a1=3)
              Class.classmethod()


              output:



              $ python Example5.py 
              class: None func: simplefun args: () kwargs: {}
              class: Class func: __init__ args: () kwargs: {}
              class: Class func: method args: (1, 2) kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}
              class: None func: staticmethod args: () kwargs: {'a1': 3}
              class: Class func: classmethod args: () kwargs: {}






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 25 '18 at 23:19

























              answered Feb 16 '18 at 23:55









              aurzenliglaurzenligl

              716




              716













              • It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

                – bartolo-otrit
                Nov 16 '18 at 7:50






              • 1





                I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

                – aurzenligl
                Nov 25 '18 at 23:17





















              • It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

                – bartolo-otrit
                Nov 16 '18 at 7:50






              • 1





                I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

                – aurzenligl
                Nov 25 '18 at 23:17



















              It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

              – bartolo-otrit
              Nov 16 '18 at 7:50





              It's an interesting solution, but there is a problem. What if the first argument of a static function is a class instance which has a function with the same name? class C: def staticmethod(self): pass Class.staticmethod(C()) # AttributeError: 'function' object has no attribute 'original'

              – bartolo-otrit
              Nov 16 '18 at 7:50




              1




              1





              I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

              – aurzenligl
              Nov 25 '18 at 23:17







              I completely missed this case! I guess identity check wrap.original is fun wrongly assumes that if something is the first arg, has attribute as original fun __name__ and has __func__ attr, it's definitely the local wrap function with original attribute. It doesn't have to be - let's check for presence of original as well: getattr(wrap, 'original', None) is fun.

              – aurzenligl
              Nov 25 '18 at 23:17















              2














              You can use inspect.getargspec:



              import inspect

              def _is_method(func):
              spec = inspect.getargspec(func)
              return spec.args and spec.args[0] == 'self'


              Example usage:



              >>> def dummy_deco(f):
              ... print('{} is method? {}'.format(f.__name__, _is_method(f)))
              ... return f
              ...
              >>> @dummy_deco
              ... def add(a, b):
              ... return a + b
              ...
              add is method? False
              >>> class A:
              ... @dummy_deco
              ... def meth(self, a, b):
              ... return a + b
              ...
              meth is method? True


              NOTE This code depend on the name of the first argument. If the name is not self it will treat it as non-instance-method even though it is.






              share|improve this answer
























              • Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

                – canni
                Oct 11 '13 at 12:26
















              2














              You can use inspect.getargspec:



              import inspect

              def _is_method(func):
              spec = inspect.getargspec(func)
              return spec.args and spec.args[0] == 'self'


              Example usage:



              >>> def dummy_deco(f):
              ... print('{} is method? {}'.format(f.__name__, _is_method(f)))
              ... return f
              ...
              >>> @dummy_deco
              ... def add(a, b):
              ... return a + b
              ...
              add is method? False
              >>> class A:
              ... @dummy_deco
              ... def meth(self, a, b):
              ... return a + b
              ...
              meth is method? True


              NOTE This code depend on the name of the first argument. If the name is not self it will treat it as non-instance-method even though it is.






              share|improve this answer
























              • Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

                – canni
                Oct 11 '13 at 12:26














              2












              2








              2







              You can use inspect.getargspec:



              import inspect

              def _is_method(func):
              spec = inspect.getargspec(func)
              return spec.args and spec.args[0] == 'self'


              Example usage:



              >>> def dummy_deco(f):
              ... print('{} is method? {}'.format(f.__name__, _is_method(f)))
              ... return f
              ...
              >>> @dummy_deco
              ... def add(a, b):
              ... return a + b
              ...
              add is method? False
              >>> class A:
              ... @dummy_deco
              ... def meth(self, a, b):
              ... return a + b
              ...
              meth is method? True


              NOTE This code depend on the name of the first argument. If the name is not self it will treat it as non-instance-method even though it is.






              share|improve this answer













              You can use inspect.getargspec:



              import inspect

              def _is_method(func):
              spec = inspect.getargspec(func)
              return spec.args and spec.args[0] == 'self'


              Example usage:



              >>> def dummy_deco(f):
              ... print('{} is method? {}'.format(f.__name__, _is_method(f)))
              ... return f
              ...
              >>> @dummy_deco
              ... def add(a, b):
              ... return a + b
              ...
              add is method? False
              >>> class A:
              ... @dummy_deco
              ... def meth(self, a, b):
              ... return a + b
              ...
              meth is method? True


              NOTE This code depend on the name of the first argument. If the name is not self it will treat it as non-instance-method even though it is.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Oct 11 '13 at 9:44









              falsetrufalsetru

              246k34430427




              246k34430427













              • Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

                – canni
                Oct 11 '13 at 12:26



















              • Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

                – canni
                Oct 11 '13 at 12:26

















              Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

              – canni
              Oct 11 '13 at 12:26





              Thanks, looks like this could solve my issue, but I'm thinking like using inspect at all is not "elegant" approach, maybe there is some other way of doing this?

              – canni
              Oct 11 '13 at 12:26











              1














              Thanks to this SO answer: Using the same decorator (with arguments) with functions and methods



              I came to this solution witch works for me flawlessly:



              def proofOfConcept():
              def wrapper(func):

              class MethodDecoratorAdapter(object):
              def __init__(self, func):
              self.func = func
              self.is_method = False

              def __get__(self, instance, owner):
              if not self.is_method:
              self.is_method = True
              self.instance = instance

              return self

              def __call__(self, *args, **kwargs):
              # Decorator real logic goes here
              if self.is_method:
              return self.func(self.instance, *args, **kwargs)
              else:
              return self.func(*args, **kwargs)

              return wraps(func)(MethodDecoratorAdapter(func))

              return wrapper


              NOTE This is not thread safe, to have a thread safe method one must return a callable object from __get__ that will have scope tied to instance






              share|improve this answer






























                1














                Thanks to this SO answer: Using the same decorator (with arguments) with functions and methods



                I came to this solution witch works for me flawlessly:



                def proofOfConcept():
                def wrapper(func):

                class MethodDecoratorAdapter(object):
                def __init__(self, func):
                self.func = func
                self.is_method = False

                def __get__(self, instance, owner):
                if not self.is_method:
                self.is_method = True
                self.instance = instance

                return self

                def __call__(self, *args, **kwargs):
                # Decorator real logic goes here
                if self.is_method:
                return self.func(self.instance, *args, **kwargs)
                else:
                return self.func(*args, **kwargs)

                return wraps(func)(MethodDecoratorAdapter(func))

                return wrapper


                NOTE This is not thread safe, to have a thread safe method one must return a callable object from __get__ that will have scope tied to instance






                share|improve this answer




























                  1












                  1








                  1







                  Thanks to this SO answer: Using the same decorator (with arguments) with functions and methods



                  I came to this solution witch works for me flawlessly:



                  def proofOfConcept():
                  def wrapper(func):

                  class MethodDecoratorAdapter(object):
                  def __init__(self, func):
                  self.func = func
                  self.is_method = False

                  def __get__(self, instance, owner):
                  if not self.is_method:
                  self.is_method = True
                  self.instance = instance

                  return self

                  def __call__(self, *args, **kwargs):
                  # Decorator real logic goes here
                  if self.is_method:
                  return self.func(self.instance, *args, **kwargs)
                  else:
                  return self.func(*args, **kwargs)

                  return wraps(func)(MethodDecoratorAdapter(func))

                  return wrapper


                  NOTE This is not thread safe, to have a thread safe method one must return a callable object from __get__ that will have scope tied to instance






                  share|improve this answer















                  Thanks to this SO answer: Using the same decorator (with arguments) with functions and methods



                  I came to this solution witch works for me flawlessly:



                  def proofOfConcept():
                  def wrapper(func):

                  class MethodDecoratorAdapter(object):
                  def __init__(self, func):
                  self.func = func
                  self.is_method = False

                  def __get__(self, instance, owner):
                  if not self.is_method:
                  self.is_method = True
                  self.instance = instance

                  return self

                  def __call__(self, *args, **kwargs):
                  # Decorator real logic goes here
                  if self.is_method:
                  return self.func(self.instance, *args, **kwargs)
                  else:
                  return self.func(*args, **kwargs)

                  return wraps(func)(MethodDecoratorAdapter(func))

                  return wrapper


                  NOTE This is not thread safe, to have a thread safe method one must return a callable object from __get__ that will have scope tied to instance







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited May 23 '17 at 11:53









                  Community

                  11




                  11










                  answered Oct 11 '13 at 13:38









                  cannicanni

                  2,73662862




                  2,73662862























                      1














                      Solution for python3:



                      import inspect

                      def _is_method(func):
                      spec = inspect.signature(func)
                      if len(spec.parameters) > 0:
                      if list(spec.parameters.keys())[0] == 'self':
                      return True
                      return False





                      share|improve this answer




























                        1














                        Solution for python3:



                        import inspect

                        def _is_method(func):
                        spec = inspect.signature(func)
                        if len(spec.parameters) > 0:
                        if list(spec.parameters.keys())[0] == 'self':
                        return True
                        return False





                        share|improve this answer


























                          1












                          1








                          1







                          Solution for python3:



                          import inspect

                          def _is_method(func):
                          spec = inspect.signature(func)
                          if len(spec.parameters) > 0:
                          if list(spec.parameters.keys())[0] == 'self':
                          return True
                          return False





                          share|improve this answer













                          Solution for python3:



                          import inspect

                          def _is_method(func):
                          spec = inspect.signature(func)
                          if len(spec.parameters) > 0:
                          if list(spec.parameters.keys())[0] == 'self':
                          return True
                          return False






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Mar 6 '18 at 12:28









                          Dino HensenDino Hensen

                          264




                          264






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f19314405%2fhow-to-detect-is-decorator-has-been-applied-to-method-or-function%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Contact image not getting when fetch all contact list from iPhone by CNContact

                              count number of partitions of a set with n elements into k subsets

                              A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks