This code prints the values of a and b while both refer to the ID of the wrapper's ID,and both return same ID.
def my_decorator(func):
def wrapper():
pass
return id(wrapper)
def some_func():
pass
a = id(my_decorator(some_func))
b = id(my_decorator(some_func))
print(a)
print(b) # both return same ID
Than I'm inserting the values of a & b into f-string and code returns different IDs.
a = f"foo - { id(my_decorator(some_func)) }"
b = f"foo - { id(my_decorator(some_func))} "
print(a)
print(b) # return diff IDs
Why?
There are a couple of implementation details of standard Python you need to be aware of. They are interacting to give the behavior you are seeing. These details might be different in a different Python implementation, or even a future version. Since they're implementation details they're not guaranteed to stay the same.
First the id()
of an object is the object's memory address. Two different objects can have the same id if they coincidentally end up at the same address. Of course this is impossible if both objects exist at the same time.
Second, objects are garbage collected immediately when there are no more references to them. Once an object is garbage collected, its memory is available for a new object.
In both cases, your calls to my_decorator
are creating a new object that is not being assigned to a reference so it will be garbage collected at the end of the statement. In the first case there's nothing else going on so nothing gets in the way of the second object being allocated at the same place as the first. In the second case you're creating an f-string which is more work, probably causing some other object to occupy the newly freed space.