How to detect is decorator has been applied to method or function?
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
add a comment |
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
add a comment |
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
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
python
asked Oct 11 '13 at 9:11
cannicanni
2,73662862
2,73662862
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
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: {}
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 checkwrap.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 localwrap
function withoriginal
attribute. It doesn't have to be - let's check for presence oforiginal
as well:getattr(wrap, 'original', None) is fun
.
– aurzenligl
Nov 25 '18 at 23:17
add a comment |
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.
Thanks, looks like this could solve my issue, but I'm thinking like usinginspect
at all is not "elegant" approach, maybe there is some other way of doing this?
– canni
Oct 11 '13 at 12:26
add a comment |
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
add a comment |
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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: {}
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 checkwrap.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 localwrap
function withoriginal
attribute. It doesn't have to be - let's check for presence oforiginal
as well:getattr(wrap, 'original', None) is fun
.
– aurzenligl
Nov 25 '18 at 23:17
add a comment |
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: {}
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 checkwrap.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 localwrap
function withoriginal
attribute. It doesn't have to be - let's check for presence oforiginal
as well:getattr(wrap, 'original', None) is fun
.
– aurzenligl
Nov 25 '18 at 23:17
add a comment |
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: {}
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: {}
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 checkwrap.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 localwrap
function withoriginal
attribute. It doesn't have to be - let's check for presence oforiginal
as well:getattr(wrap, 'original', None) is fun
.
– aurzenligl
Nov 25 '18 at 23:17
add a comment |
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 checkwrap.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 localwrap
function withoriginal
attribute. It doesn't have to be - let's check for presence oforiginal
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
add a comment |
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.
Thanks, looks like this could solve my issue, but I'm thinking like usinginspect
at all is not "elegant" approach, maybe there is some other way of doing this?
– canni
Oct 11 '13 at 12:26
add a comment |
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.
Thanks, looks like this could solve my issue, but I'm thinking like usinginspect
at all is not "elegant" approach, maybe there is some other way of doing this?
– canni
Oct 11 '13 at 12:26
add a comment |
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.
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.
answered Oct 11 '13 at 9:44
falsetrufalsetru
246k34430427
246k34430427
Thanks, looks like this could solve my issue, but I'm thinking like usinginspect
at all is not "elegant" approach, maybe there is some other way of doing this?
– canni
Oct 11 '13 at 12:26
add a comment |
Thanks, looks like this could solve my issue, but I'm thinking like usinginspect
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
add a comment |
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
add a comment |
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
add a comment |
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
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
edited May 23 '17 at 11:53
Community♦
11
11
answered Oct 11 '13 at 13:38
cannicanni
2,73662862
2,73662862
add a comment |
add a comment |
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
add a comment |
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
add a comment |
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
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
answered Mar 6 '18 at 12:28
Dino HensenDino Hensen
264
264
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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