-
-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a dedicated namespace for private objs on Parameterized #766
Conversation
I had a look at a previous PR (#386) that turned
So there was at the time a concern with circular references, which would indeed have been generated every time a Parameterized was created had import param
import gc
gc.collect()
gc.set_debug(gc.DEBUG_SAVEALL)
class P(param.Parameterized):
x = param.Number()
@param.depends('x', watch=True)
def debug(self): pass
p = P()
del p
gc.collect()
print(gc.garbage) Output (would be an empty list without circular references):
I believe that circular reference is caused by the attribute As it stands I think that this PR doesn't make the situation worse wrt circular references. |
An alternative to the private namespace implemented in this PR would be to rely on conventions, with e.g. every private attribute of Parameterized being prefixed with |
I'm in favor of separating private variables into their own namespace purely to clean up the code. I would maybe reduce the names from If the dedicated namespace is used, I would also consider removing Regarding the cyclic references for the dedicated namespace, is it possible to "hide" it in the |
Having a variable starting with two underscores exposes it to name mangling. This is not necessarily bad, but it'd need to be done and checked carefully as Param does some meta-stuff that maybe don't play well with it (there's code that manually mangles some names).
Just to make sure I understand, do you think that it would make Param's code cleaner or some other code? If it's Param's code, I'm not entirely sure as adding a private namespace adds a level of nesting which requires some more handling. It does make the overall Parameterized namespace cleaner.
I also thought about that but then saw that #386 superseded #384 that was abandoned due to #384 (comment):
|
I need to add that #740 added a new private attribute |
@philippjfr @jbednar I'm interested in your feedback on this PR and the various approaches suggested in the comments. |
I am in favor of collecting the various attributes into a single private namespace; seems like a great way to clean things up! I agree that pickling is likely to be affected and should be tested well. Unfortunately our most extensive usage of pickling is in the topographica code, which has not been updated for years and would take a lot of work to be compatible with param 2 so that we could use its tests.
I agree. |
Ok so compared to my original post we now have:
So Parameterized classes and instances have the same public and private attributes, all the previous private attributes plus As now parameter values on a Parameterized instance are stored on the private name space (in a dict) and no longer in the Parameterized instance In addition to updating the docs and docstrings, here's what I would like to do next on this PR:
|
That all sounds great; thanks so much! @philippjfr or @jlstevens , please do review it carefully. |
This indeed looks like great work, but it also makes me a little uneasy. One major issue here is that we never provided a public API to access watchers. This meant that Panel, Lumen and at least some user code likely started accessing the
We did provide |
Thanks for your review! I opened #780 for us to have a discussion on what public API we'd like to add to access the watchers. Expecting you to chime in in there @philippjfr as the main user of the private I'll update this PR to keep |
I ran the newly added benchmark against this PR and saw no noticeable performance degradation, I'm going to merge it and soon follow up with an API to access the watchers (#780). |
At this stage this is more of a POC, that I wanted to share to see whether it's going in the right direction. The idea with this PR is to cleanup the private namespace of Parameterized classes and instances, mostly by defining a private namespace that we can defend and document, hopefully making it less likely for users to get name collisions. Some additional clean-up/renaming could also be done.
Take this example:
Ignoring dunder methods and some public & private API meant to be removed for Param 2.0 (#767), these are the attributes (calling
dir()
) ofA
anda
on the main branch currently:A
:a
:Among these:
_{{ClassName}}__params
(class+instance) are Parameter dicts, mangled directly by Param. The double underscore after the class name is good IMO as it makes name clashes a lot less likelyparam/param/parameterized.py
Line 2127 in 154afe6
_{{AttributeName}}_param_value
(instance) is the internal variable name that holds the current attribute value. It doesn't look too bad, the variable name including double underscore wouldn't hurt._param
(class+instance) is the reference to the classParameters
object, that is returned when you callA.param
(on a Parameterized instance likea
callinga.param
returns every time a newParameters
instance)._param
seems very prone to name clashes._parameters_state
(class+instance),_dynamic_watchers
(instance),_param_watchers
(instance),_instance__params
(instance) andinitialized
(instance) are internal attributes.initialized
is obviously the most embarrassing one, it's not private and is a pretty common variable name (@jlstevens had a problem with that just recently).What I have done in this PR so far is to:
_param__private
for now) and adapted the code accordingly. I've renamed them under this namespace, removing their starting underscore._param
to_param__parameters
These are the updated namespaces after these changes:
A
:a
:Additional notes:
initialized
attribute. I've also found 8 occurrences of_param_watchers
being accessed in Panel and 1 in Lumen. Maybe there's a need for a public API to_param_watchers
?__setstate__
for instance.EDIT: