hasattr telling lies? (AttributeError: 'method' object has no attribute '__annotations__')
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
The following code
class Foo:
def bar(self) -> None:
pass
foo = Foo()
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__ = 'hi'
crashes with
AttributeError: 'method' object has no attribute '__annotations__'
How can this happen?
python-3.x
add a comment |
The following code
class Foo:
def bar(self) -> None:
pass
foo = Foo()
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__ = 'hi'
crashes with
AttributeError: 'method' object has no attribute '__annotations__'
How can this happen?
python-3.x
hasattr returnTrue
ifgetattr(object, name)
don't raise, and when you dogetattr(foo.bar, "__annotations__")
you get{'return':None}
. This is why hasattr(foo.bar, 'annotations') returnTrue
.
– iElden
Nov 26 '18 at 8:21
Seems Python bug to me.AttributeError: readonly attribute
would be more sensible error message here.
– wim
Nov 26 '18 at 17:49
add a comment |
The following code
class Foo:
def bar(self) -> None:
pass
foo = Foo()
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__ = 'hi'
crashes with
AttributeError: 'method' object has no attribute '__annotations__'
How can this happen?
python-3.x
The following code
class Foo:
def bar(self) -> None:
pass
foo = Foo()
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__ = 'hi'
crashes with
AttributeError: 'method' object has no attribute '__annotations__'
How can this happen?
python-3.x
python-3.x
asked Nov 23 '18 at 17:07
Tobias HermannTobias Hermann
2,98422356
2,98422356
hasattr returnTrue
ifgetattr(object, name)
don't raise, and when you dogetattr(foo.bar, "__annotations__")
you get{'return':None}
. This is why hasattr(foo.bar, 'annotations') returnTrue
.
– iElden
Nov 26 '18 at 8:21
Seems Python bug to me.AttributeError: readonly attribute
would be more sensible error message here.
– wim
Nov 26 '18 at 17:49
add a comment |
hasattr returnTrue
ifgetattr(object, name)
don't raise, and when you dogetattr(foo.bar, "__annotations__")
you get{'return':None}
. This is why hasattr(foo.bar, 'annotations') returnTrue
.
– iElden
Nov 26 '18 at 8:21
Seems Python bug to me.AttributeError: readonly attribute
would be more sensible error message here.
– wim
Nov 26 '18 at 17:49
hasattr return
True
if getattr(object, name)
don't raise, and when you do getattr(foo.bar, "__annotations__")
you get {'return':None}
. This is why hasattr(foo.bar, 'annotations') return True
.– iElden
Nov 26 '18 at 8:21
hasattr return
True
if getattr(object, name)
don't raise, and when you do getattr(foo.bar, "__annotations__")
you get {'return':None}
. This is why hasattr(foo.bar, 'annotations') return True
.– iElden
Nov 26 '18 at 8:21
Seems Python bug to me.
AttributeError: readonly attribute
would be more sensible error message here.– wim
Nov 26 '18 at 17:49
Seems Python bug to me.
AttributeError: readonly attribute
would be more sensible error message here.– wim
Nov 26 '18 at 17:49
add a comment |
2 Answers
2
active
oldest
votes
The attribute error here is raised because you can't set any attribute on a method object:
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
The exception here is perhaps confusing because method
objects wrap a function object and proxy attribute read access to that underlying function object. So when attributes on the function exist, then hasattr()
on the method will return True
:
>>> hasattr(foo.bar, 'baz')
False
>>> foo.bar.__func__.baz = 42
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz
42
However, you still can't set those attributes via the method, regardless:
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
So, just because the attribute can be read doesn't mean you can set it. hasattr()
is speaking the truth, you just interpreted it to mean something different.
Now, if you tried to set the __annotations__
attribute directly on the underlying function object you'd get another error message:
>>> foo.bar.__func__.__annotations__ = 'hi'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __annotations__ must be set to a dict object
You would want to use a dictionary object here:
>>> foo.bar.__func__.__annotations__ = {'return': 'hi'}
>>> foo.bar.__annotations__
{'return': 'hi'}
However, because __annotations__
is a mutable dictionary, it is just easier to directly manipulate the keys and values to that object, which is perfectly feasible to do via the method wrapper:
>>> foo.bar.__annotations__['return'] = 'int'
>>> foo.bar.__annotations__
{'return': 'int'}
Now, if you were hoping to set per instance annotations, you can't get away with setting attributes on method objects, because method objects are ephemeral, they are created just for the call, then usually discarded right after.
You would have to use custom method descriptor objects via a metaclass and re-create the __annotations__
attribute for those each time, or you could instead pre-bind methods with a new function object that would be given their own attributes. You then have to pay a larger memory price:
import functools
foo.bar = lambda *args, **kwargs: Foo.bar(foo, *args, **kwargs)
functools.update_wrapper(foo.bar, Foo.bar) # copy everything over to the new wrapper
foo.bar.__annotations__['return'] = 'hi'
Either way you completely kill important speed optimisations made in Python 3.7 this way.
And tools that operate on the most important use case for __annatotions__
, type hints, do not actually execute code, they read code statically and would completely miss these runtime alterations.
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead ofhas no attribute
. ;)
– Tobias Hermann
Nov 27 '18 at 6:24
1
@TobiasHermann: The problem there is that thenmethod
would have to implement a__setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of theAttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.
– Martijn Pieters♦
Nov 27 '18 at 11:29
1
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of thehasattr()
call.
– Martijn Pieters♦
Nov 27 '18 at 11:30
add a comment |
You're getting an error. because __annotations__
is a dictionary. If you want to change values you'll have to do it like this:
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__['return'] = 'hi'
This will make the return value of your foo.bar
be hi
instead of None
. The only thing I'm not sure about is how the __annotations__
are protected, not allowing you to change them from a dict to string, but I suppose it's some internal check in the source.
UPDATE
For more control over the signature you can use the inspect
module and get the Signature object of your class(or method) and edit it from there. For example
import inspect
sig = inspect.signature(foo.bar)
sig.return_annotation # prints None (before modifying)
sig.replace(return_annotation="anything you want")
More on that here
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%2f53450624%2fhasattr-telling-lies-attributeerror-method-object-has-no-attribute-annot%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The attribute error here is raised because you can't set any attribute on a method object:
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
The exception here is perhaps confusing because method
objects wrap a function object and proxy attribute read access to that underlying function object. So when attributes on the function exist, then hasattr()
on the method will return True
:
>>> hasattr(foo.bar, 'baz')
False
>>> foo.bar.__func__.baz = 42
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz
42
However, you still can't set those attributes via the method, regardless:
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
So, just because the attribute can be read doesn't mean you can set it. hasattr()
is speaking the truth, you just interpreted it to mean something different.
Now, if you tried to set the __annotations__
attribute directly on the underlying function object you'd get another error message:
>>> foo.bar.__func__.__annotations__ = 'hi'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __annotations__ must be set to a dict object
You would want to use a dictionary object here:
>>> foo.bar.__func__.__annotations__ = {'return': 'hi'}
>>> foo.bar.__annotations__
{'return': 'hi'}
However, because __annotations__
is a mutable dictionary, it is just easier to directly manipulate the keys and values to that object, which is perfectly feasible to do via the method wrapper:
>>> foo.bar.__annotations__['return'] = 'int'
>>> foo.bar.__annotations__
{'return': 'int'}
Now, if you were hoping to set per instance annotations, you can't get away with setting attributes on method objects, because method objects are ephemeral, they are created just for the call, then usually discarded right after.
You would have to use custom method descriptor objects via a metaclass and re-create the __annotations__
attribute for those each time, or you could instead pre-bind methods with a new function object that would be given their own attributes. You then have to pay a larger memory price:
import functools
foo.bar = lambda *args, **kwargs: Foo.bar(foo, *args, **kwargs)
functools.update_wrapper(foo.bar, Foo.bar) # copy everything over to the new wrapper
foo.bar.__annotations__['return'] = 'hi'
Either way you completely kill important speed optimisations made in Python 3.7 this way.
And tools that operate on the most important use case for __annatotions__
, type hints, do not actually execute code, they read code statically and would completely miss these runtime alterations.
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead ofhas no attribute
. ;)
– Tobias Hermann
Nov 27 '18 at 6:24
1
@TobiasHermann: The problem there is that thenmethod
would have to implement a__setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of theAttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.
– Martijn Pieters♦
Nov 27 '18 at 11:29
1
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of thehasattr()
call.
– Martijn Pieters♦
Nov 27 '18 at 11:30
add a comment |
The attribute error here is raised because you can't set any attribute on a method object:
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
The exception here is perhaps confusing because method
objects wrap a function object and proxy attribute read access to that underlying function object. So when attributes on the function exist, then hasattr()
on the method will return True
:
>>> hasattr(foo.bar, 'baz')
False
>>> foo.bar.__func__.baz = 42
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz
42
However, you still can't set those attributes via the method, regardless:
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
So, just because the attribute can be read doesn't mean you can set it. hasattr()
is speaking the truth, you just interpreted it to mean something different.
Now, if you tried to set the __annotations__
attribute directly on the underlying function object you'd get another error message:
>>> foo.bar.__func__.__annotations__ = 'hi'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __annotations__ must be set to a dict object
You would want to use a dictionary object here:
>>> foo.bar.__func__.__annotations__ = {'return': 'hi'}
>>> foo.bar.__annotations__
{'return': 'hi'}
However, because __annotations__
is a mutable dictionary, it is just easier to directly manipulate the keys and values to that object, which is perfectly feasible to do via the method wrapper:
>>> foo.bar.__annotations__['return'] = 'int'
>>> foo.bar.__annotations__
{'return': 'int'}
Now, if you were hoping to set per instance annotations, you can't get away with setting attributes on method objects, because method objects are ephemeral, they are created just for the call, then usually discarded right after.
You would have to use custom method descriptor objects via a metaclass and re-create the __annotations__
attribute for those each time, or you could instead pre-bind methods with a new function object that would be given their own attributes. You then have to pay a larger memory price:
import functools
foo.bar = lambda *args, **kwargs: Foo.bar(foo, *args, **kwargs)
functools.update_wrapper(foo.bar, Foo.bar) # copy everything over to the new wrapper
foo.bar.__annotations__['return'] = 'hi'
Either way you completely kill important speed optimisations made in Python 3.7 this way.
And tools that operate on the most important use case for __annatotions__
, type hints, do not actually execute code, they read code statically and would completely miss these runtime alterations.
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead ofhas no attribute
. ;)
– Tobias Hermann
Nov 27 '18 at 6:24
1
@TobiasHermann: The problem there is that thenmethod
would have to implement a__setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of theAttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.
– Martijn Pieters♦
Nov 27 '18 at 11:29
1
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of thehasattr()
call.
– Martijn Pieters♦
Nov 27 '18 at 11:30
add a comment |
The attribute error here is raised because you can't set any attribute on a method object:
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
The exception here is perhaps confusing because method
objects wrap a function object and proxy attribute read access to that underlying function object. So when attributes on the function exist, then hasattr()
on the method will return True
:
>>> hasattr(foo.bar, 'baz')
False
>>> foo.bar.__func__.baz = 42
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz
42
However, you still can't set those attributes via the method, regardless:
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
So, just because the attribute can be read doesn't mean you can set it. hasattr()
is speaking the truth, you just interpreted it to mean something different.
Now, if you tried to set the __annotations__
attribute directly on the underlying function object you'd get another error message:
>>> foo.bar.__func__.__annotations__ = 'hi'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __annotations__ must be set to a dict object
You would want to use a dictionary object here:
>>> foo.bar.__func__.__annotations__ = {'return': 'hi'}
>>> foo.bar.__annotations__
{'return': 'hi'}
However, because __annotations__
is a mutable dictionary, it is just easier to directly manipulate the keys and values to that object, which is perfectly feasible to do via the method wrapper:
>>> foo.bar.__annotations__['return'] = 'int'
>>> foo.bar.__annotations__
{'return': 'int'}
Now, if you were hoping to set per instance annotations, you can't get away with setting attributes on method objects, because method objects are ephemeral, they are created just for the call, then usually discarded right after.
You would have to use custom method descriptor objects via a metaclass and re-create the __annotations__
attribute for those each time, or you could instead pre-bind methods with a new function object that would be given their own attributes. You then have to pay a larger memory price:
import functools
foo.bar = lambda *args, **kwargs: Foo.bar(foo, *args, **kwargs)
functools.update_wrapper(foo.bar, Foo.bar) # copy everything over to the new wrapper
foo.bar.__annotations__['return'] = 'hi'
Either way you completely kill important speed optimisations made in Python 3.7 this way.
And tools that operate on the most important use case for __annatotions__
, type hints, do not actually execute code, they read code statically and would completely miss these runtime alterations.
The attribute error here is raised because you can't set any attribute on a method object:
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
The exception here is perhaps confusing because method
objects wrap a function object and proxy attribute read access to that underlying function object. So when attributes on the function exist, then hasattr()
on the method will return True
:
>>> hasattr(foo.bar, 'baz')
False
>>> foo.bar.__func__.baz = 42
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz
42
However, you still can't set those attributes via the method, regardless:
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
So, just because the attribute can be read doesn't mean you can set it. hasattr()
is speaking the truth, you just interpreted it to mean something different.
Now, if you tried to set the __annotations__
attribute directly on the underlying function object you'd get another error message:
>>> foo.bar.__func__.__annotations__ = 'hi'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __annotations__ must be set to a dict object
You would want to use a dictionary object here:
>>> foo.bar.__func__.__annotations__ = {'return': 'hi'}
>>> foo.bar.__annotations__
{'return': 'hi'}
However, because __annotations__
is a mutable dictionary, it is just easier to directly manipulate the keys and values to that object, which is perfectly feasible to do via the method wrapper:
>>> foo.bar.__annotations__['return'] = 'int'
>>> foo.bar.__annotations__
{'return': 'int'}
Now, if you were hoping to set per instance annotations, you can't get away with setting attributes on method objects, because method objects are ephemeral, they are created just for the call, then usually discarded right after.
You would have to use custom method descriptor objects via a metaclass and re-create the __annotations__
attribute for those each time, or you could instead pre-bind methods with a new function object that would be given their own attributes. You then have to pay a larger memory price:
import functools
foo.bar = lambda *args, **kwargs: Foo.bar(foo, *args, **kwargs)
functools.update_wrapper(foo.bar, Foo.bar) # copy everything over to the new wrapper
foo.bar.__annotations__['return'] = 'hi'
Either way you completely kill important speed optimisations made in Python 3.7 this way.
And tools that operate on the most important use case for __annatotions__
, type hints, do not actually execute code, they read code statically and would completely miss these runtime alterations.
edited Nov 26 '18 at 19:39
answered Nov 26 '18 at 17:44
Martijn Pieters♦Martijn Pieters
727k14525542356
727k14525542356
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead ofhas no attribute
. ;)
– Tobias Hermann
Nov 27 '18 at 6:24
1
@TobiasHermann: The problem there is that thenmethod
would have to implement a__setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of theAttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.
– Martijn Pieters♦
Nov 27 '18 at 11:29
1
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of thehasattr()
call.
– Martijn Pieters♦
Nov 27 '18 at 11:30
add a comment |
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead ofhas no attribute
. ;)
– Tobias Hermann
Nov 27 '18 at 6:24
1
@TobiasHermann: The problem there is that thenmethod
would have to implement a__setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of theAttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.
– Martijn Pieters♦
Nov 27 '18 at 11:29
1
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of thehasattr()
call.
– Martijn Pieters♦
Nov 27 '18 at 11:30
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change
__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead of has no attribute
. ;)– Tobias Hermann
Nov 27 '18 at 6:24
Great answer, as usual. Thank you. :) Don't worry, I don't plan to actually change
__annotations__
of methods at runtime. I ran into this more by accident, but was confused by the error, so I wanted to find out only for understanding. Your explanation totally makes sense. However I think the error message could be a bit more obvious instead of has no attribute
. ;)– Tobias Hermann
Nov 27 '18 at 6:24
1
1
@TobiasHermann: The problem there is that then
method
would have to implement a __setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of the AttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.– Martijn Pieters♦
Nov 27 '18 at 11:29
@TobiasHermann: The problem there is that then
method
would have to implement a __setattr__
hook that was just there to test if the attribute existed on the wrapped object, then adjust the error message of the AttributeError
exception it throws. That's... going to lead to surprising semantics the moment its a custom object that's being wrapped.– Martijn Pieters♦
Nov 27 '18 at 11:29
1
1
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of the
hasattr()
call.– Martijn Pieters♦
Nov 27 '18 at 11:30
@TobiasHermann: and that's aside from a discussion of the possible side effects and cost of the
hasattr()
call.– Martijn Pieters♦
Nov 27 '18 at 11:30
add a comment |
You're getting an error. because __annotations__
is a dictionary. If you want to change values you'll have to do it like this:
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__['return'] = 'hi'
This will make the return value of your foo.bar
be hi
instead of None
. The only thing I'm not sure about is how the __annotations__
are protected, not allowing you to change them from a dict to string, but I suppose it's some internal check in the source.
UPDATE
For more control over the signature you can use the inspect
module and get the Signature object of your class(or method) and edit it from there. For example
import inspect
sig = inspect.signature(foo.bar)
sig.return_annotation # prints None (before modifying)
sig.replace(return_annotation="anything you want")
More on that here
add a comment |
You're getting an error. because __annotations__
is a dictionary. If you want to change values you'll have to do it like this:
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__['return'] = 'hi'
This will make the return value of your foo.bar
be hi
instead of None
. The only thing I'm not sure about is how the __annotations__
are protected, not allowing you to change them from a dict to string, but I suppose it's some internal check in the source.
UPDATE
For more control over the signature you can use the inspect
module and get the Signature object of your class(or method) and edit it from there. For example
import inspect
sig = inspect.signature(foo.bar)
sig.return_annotation # prints None (before modifying)
sig.replace(return_annotation="anything you want")
More on that here
add a comment |
You're getting an error. because __annotations__
is a dictionary. If you want to change values you'll have to do it like this:
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__['return'] = 'hi'
This will make the return value of your foo.bar
be hi
instead of None
. The only thing I'm not sure about is how the __annotations__
are protected, not allowing you to change them from a dict to string, but I suppose it's some internal check in the source.
UPDATE
For more control over the signature you can use the inspect
module and get the Signature object of your class(or method) and edit it from there. For example
import inspect
sig = inspect.signature(foo.bar)
sig.return_annotation # prints None (before modifying)
sig.replace(return_annotation="anything you want")
More on that here
You're getting an error. because __annotations__
is a dictionary. If you want to change values you'll have to do it like this:
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__['return'] = 'hi'
This will make the return value of your foo.bar
be hi
instead of None
. The only thing I'm not sure about is how the __annotations__
are protected, not allowing you to change them from a dict to string, but I suppose it's some internal check in the source.
UPDATE
For more control over the signature you can use the inspect
module and get the Signature object of your class(or method) and edit it from there. For example
import inspect
sig = inspect.signature(foo.bar)
sig.return_annotation # prints None (before modifying)
sig.replace(return_annotation="anything you want")
More on that here
edited Nov 26 '18 at 9:54
answered Nov 26 '18 at 9:25
BorisuBorisu
549412
549412
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%2f53450624%2fhasattr-telling-lies-attributeerror-method-object-has-no-attribute-annot%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
hasattr return
True
ifgetattr(object, name)
don't raise, and when you dogetattr(foo.bar, "__annotations__")
you get{'return':None}
. This is why hasattr(foo.bar, 'annotations') returnTrue
.– iElden
Nov 26 '18 at 8:21
Seems Python bug to me.
AttributeError: readonly attribute
would be more sensible error message here.– wim
Nov 26 '18 at 17:49