Skip to content

Conversation

Xiaokang2022
Copy link
Contributor

@Xiaokang2022 Xiaokang2022 commented Jan 7, 2025

@Xiaokang2022 Xiaokang2022 changed the title GH-128576: feat: Add decorator functools.lru_cache to method tkinter.Misc.winfo_rgb gh-128576: feat: Add decorator functools.lru_cache to method tkinter.Misc.winfo_rgb Jan 7, 2025
Copy link
Member

@picnixz picnixz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LRU-cached methods should be carefully implemented: see https://docs.python.org/3/faq/programming.html#faq-cache-method-calls. Since Misc is a mixin class, we should be even more careful.

return self.tk.getint(
self.tk.call('winfo', 'reqwidth', self._w))

@functools.lru_cache
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LRU-cached methods do not play well with functools.lru_cache if __hash__ and __eq__ are not implemented (see https://docs.python.org/3/faq/programming.html#faq-cache-method-calls) because it also caches the instance.

Copy link
Contributor Author

@Xiaokang2022 Xiaokang2022 Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the lru_cache approach work when the station_id is mutable, the class needs to define the __eq__() and __hash__() methods so that the cache can detect relevant attribute updates:

The above is quoted from: https://docs.python.org/3.13/faq/programming.html#faq-cache-method-calls

But in reality, no matter how the attribute is updated, the return value of the method winfo_rgb will not change for a particular parameter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is not the return value. It's how the cache is built. The instance itself is cached by lru_cache. I'm not sure we want to keep them alive. The method will know in advance all the existing instances of Misc that were created and that used this method. This is something we don't want (the cache is a full-fledged dictionary so a reference to those widgets will remain)

Copy link
Member

@picnixz picnixz Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, even if you add those magic methods, the instance will stil be cached. By the way, is it possible to change the color display of the current widget (e.g., directcolor to greyscale) and that this would affect the return value? if so, we cannot cache this method.

I am really not comfortable with caching tk widgets in general. Those objects should be released whenever they can. It would be an overkill to clear the cache when one object has been deleted as well =/

If LRU-caching is possible, instead of storing the instance itself in the cache, we could store the type and the hash of that instance using a class attribute. We could also remove the instance in __del__ so that the hash value can be reused by other objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, is it possible to change the color display of the current widget (e.g., directcolor to greyscale) and that this would affect the return value?

After my testing, this doesn't affect the return value of the method, if my test method is not wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the result is the same for any widget, perhaps the method should be a class method instead of an instance method. This may eliminate the need to cache instances.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is this always the same? according to the docs, this depends on the widget itself so I'm afraid we cannot do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the documentation says that, I haven't found a way to corroborate what the documentation says, and if there is a way, hopefully it can be pointed out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result is not constant. It cannot be cached.

@Xiaokang2022
Copy link
Contributor Author

If there are no further questions, then I will close the PR and the corresponding issue later. Sorry for the interruption.

@Xiaokang2022 Xiaokang2022 deleted the improve-tk-winfo_rgb branch January 7, 2025 13:50
@serhiy-storchaka
Copy link
Member

Also, lru_cache() should not in general be used for methods, as it adds a reference to an instance to global cache, prolonging its life time. This is not desirable for widget objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants