You assign the attributes on the function passed to the decorator, but you return a different function (the wrapped function). functools.wraps
shallow-copies attributes from one to the other, which means it copies the list and dict objects. You then mutate these objects. But you can't mutate the int, so all you are doing is changing the value on the "unwrapped" version of g
, while you print the value of the wrapped version.
Here is an illustrative thing to try:
>>> def g():
... return 'pennyroyal tea'
>>> f = intify(g)
>>> f()
Incremented __int, now __int = 1
'pennyroyal tea'
>>> f.__int
0
>>> g.__int
1
I intified g
but assigned it to f
. You can see that the __int
attribute is updated --- but on the original function, not the wrapped one.
You don't see the difference with the list and dict, because these objects are mutable. There is one list and one dict, both shared by both functions. However, you can again see it if you split out the wrapped functions one by one:
>>> f = dictify(g)
... f2 = listify(f)
... f3 = intify(f2)
>>> f3()
Incremented __int, now __int = 1
Appended 0 to __list, now __list = [1, 2, 3, 0]
Incremented __dictionary, now __dictionary = {0: 1}
'pennyroyal tea'
>>> f3.__list is f2.__list
True
>>> f3.__dictionary is f2.__dictionary
True
>>> f3.__int is f2.__int
False
Your modifications to __list
and __dictionary
mutate the objects, but your modification to __int
creates a new int (since ints can't be mutated), creating a separation between the __int
attributes of the function you pass into the decorator and the wrapped function it gives back.
The basic problem here is that you what you seem to want to do in the decorator is thisFuncion.__list.append(0)
, where thisFunction
is the returned, decorated function, not the to-be-decorated function. That is, you want the wrapper to be able to refer to itself. But you can't do this. There is no general way in Python for a function to refer to itself. In your decorator, you defined a function _func
that refers to a function func
. There are two different functions, _func
is only setting attributes on func
, not on itself.
Of course, the real question is why you'd try to set function attributes like this in the first place. But I gather from your question that you're asking just out of curiosity to understand what's going on, not because you actually want to do this.