The function attribute do_something.n
is incremented each time you call the function.
It bothered me that I declared the attribute do_something.n=0
outside the function.
I answered the question Using queue.PriorityQueue, not caring about comparisons using a "function-attribute" to provide a unique counter for usage with PriorityQueue's - there is a nicer solution by MartijnPieters)
MCVE:
def do_something():
do_something.n += 1
return do_something.n
# need to declare do_something.n before usign it, else
# AttributeError: 'function' object has no attribute 'n'
# on first call of do_something() occures
do_something.n = 0
for _ in range(10):
print(do_something()) # prints 1 to 10
What other ways are there, to define the attribute of a function "inside" of it so you avoid the AttributeError: 'function' object has no attribute 'n'
if you forget it?
Edited plenty of other ways in from comments:
Functions already have a number of attributes, some of which are writable, e.g. func_doc , a.k.a. func.
A function attribute is specified with the keyword __attribute__ followed by the attribute name and any additional arguments the attribute name requires. A function __attribute__ specification is included in the declaration or definition of a function.
The __attribute__ directive is used to decorate a code declaration in C, C++ and Objective-C programming languages. This gives the declared code additional attributes that would help the compiler incorporate optimizations or elicit useful warnings to the consumer of that code.
Not quite inside, but a decorator makes the function attribute more obvious:
def func_attr(**attrs):
def wrap(f):
f.__dict__.update(attrs)
return f
return wrap
@func_attr(n=0)
def do_something():
do_something.n += 1
return do_something.n
This is probably cleaner than anything that places the attribute initialization inside the function.
What about using the built-in hasattr
function?
def do_something():
if not hasattr(do_something, 'n'):
do_something.n = 1
do_something.n += 1
return do_something.n
For reference, here is a discussion of hasattr
vs a try-except
:
hasattr() vs try-except block to deal with non-existent attributes
This is was what I had in mind when I referred you to my answer to that other question:
def with_this_arg(func):
def wrapped(*args, **kwargs):
return func(wrapped, *args, **kwargs)
return wrapped
@with_this_arg
def do_something(this):
if not getattr(this, 'n', None):
this.n = 0
this.n += 1
return this.n
for _ in range(10):
print(do_something()) # prints 1 to 10
If you prefer the more "pythonic" EAFP style of coding—which would would be slightly faster—it could be written thusly:
@with_this_arg
def do_something(this):
try:
this.n += 1
except AttributeError: # First call.
this.n = 1
return this.n
This could be combined with @user2357112's answer (if done in the proper order) into something like this which doesn't require checking or exception handling:
def func_attr(**attrs):
def wrap(f):
f.__dict__.update(attrs)
return f
return wrap
def with_this_arg(func):
def wrapped(*args, **kwargs):
return func(wrapped, *args, **kwargs)
return wrapped
@func_attr(n=0)
@with_this_arg
def do_something(this):
this.n += 1
return this.n
for _ in range(10):
print(do_something()) # prints 1 to 10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With