Giter Site home page Giter Site logo

Comments (37)

rmorshea avatar rmorshea commented on July 20, 2024

This is being looked at right now in #70. The current plan is to introduce an install_descriptors hook that can be overwritten to add obj attributes that are required to run instance_init.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea I don't see how install_descriptors solves my problem? I've merged Sylvain's recent pull request into my code, and I can't seem to figure out how to initialize the size on the object. The size is passed in the arguments to the constructor. init_instance is called from __new__. If HasTraits are at the top of the MRO, the child classes won't have a change to install the attribute in their __new__. Overriding install_descriptors would work if there were a default size or something, but I need to initialize it to a passed-in value.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

Is size a static attribute?

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

Also it seems odd that the function shape exists on the TraitType. Unless that's used to initialize a value on the TraitType, it should probably be associated with the value of that attribute instead because TraitTypes are set on HasTraits classes rather than instances. I may be misunderstanding the application, but it seems that the obj should be provided to the value rather than the TraitType, which means this should be something that's handled upon setting signal.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea : size is passed to the constructor of the object (the HasTraits instance). The reason shape exists on TraitType is so that the NDArray class can create an array of the right size. The problem is getting shape to answer correctly. I don't understand your last sentence probably because I don't understand traitlets well enough.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

Ok, this is a case where you'd want to use dynamic defaults:

old api - _'name'_default
new api (#76) @default

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea If this works, it looks like you guys have thought of everything. What connects the x default to the trait i?

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

In the old api, and using your case, to create a dynamic default generator for the trait signal you would define a method _signal_default(self) on the HasTraits instance which returned the desired value.

This method is not called when creating the instance though. Instead it is called the first time the trait is accessed iff no value has already been set (see TraitType._dynamic_default_callable).

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Yes, thanks, just figuring it out now. Looking forward to your pull request being accepted. FYI I think your pull request should have x = Int() —not i = Int() in the first comment.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

Thanks, glad I could help.
On Thu, Sep 24, 2015 at 8:12 PM Neil [email protected] wrote:

@rmorshea https://github.com/rmorshea Yes, thanks, just figuring it out
now. Looking forward to your pull request being accepted.


Reply to this email directly or view it on GitHub
#90 (comment).

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea I really appreciate it!

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

Just reopening this as a reminder to implement install_descriptors or whatever mechanism will exist to support this.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

@NeilGirdhar, the name has been changed from install_descriptors to setup_instance with the introduction of the @defualt decorator (in addition to HasDescriptors.setup_instance there is now a MetaHasDescriptors.setup_class method that is called within the metaclass). The same logic from #70 still applies to setup_instance though, which means BaseDescriptor.instance_init only accepts one argument, which is by default, the HasTraits instance which is running setup_instance.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Thanks. Will this allow me to initialize a trait after the instance has done his regular __init__?

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

@NeilGirdhar - see #171

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Thanks a lot! I think that will work for my purpose.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

@NeilGirdhar, this is subjective, but I don't really think there's a need to pass args and kwargs to an instance_init-like function. Anything that's general enough to be applied to an entire class of descriptors is probably information that's important enough to keep on the HasDescriptors instance.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea I'm having trouble keeping track of what is what. What's the HasDescriptors instance? Is that the HasTraits instance?

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

HasTraits inherits from HasDescriptors.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Right, so, instance_init is called on the trait. Some of my traits are numpy arrays whose shape depends on the HasDescriptors instance they live on.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

All that is passed to instance_init is the HasDescriptors instance the traits live on. So as long as the relevant information (like size in your example) also lives on that HasDescriptors instance, you should be fine.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea With your change you mean? Because right now I had to work around it. Also, it looks like you're not passing in the HasDescriptors instance, but its args and kwargs, right? (Although this is good enough for me.)

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

Yes, #171 makes this possible. From what I can discern, this cannot be done on master right now.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

In terms of what's being passed to what, note the difference between HasDescriptors.setup_instance and BaseDescriptor.instance_init. While args and kwargs from HasDescriptors' constructor are passed to setup_instance, only the HasDescriptors instance calling setup_instance (i.e. self in setup_instance) is being passed to instance_init.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

@NeilGirdhar does that make sense?

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Right, but that self hasn't had its __init__ called yet since we're still in __new__. So what should I do? Should I inherit from HasTraits, which is what I'm doing now:

class NDArrayInitializer(HasTraits):

    """
    We would like to have this in instance_init, but because of the design of
    traitlets, the instance hasn't had its __init__ called until after
    instance_init is called.  This class allows us to do these in the order we
    want.
    """
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for trait in self.class_traits().values():
            if not isinstance(trait, NDArray):
                continue
            try:
                shape = trait.shape(self)
                dtype = trait.dtype(self)
                trait.set(self, np.zeros(shape, dtype=dtype))
            except KeyError:
                pass

Or is there a better solution?

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

With #171, the new way to do this would be:

class NDArray(TraitType):

    def instance_init(self, inst):
        shape = inst.shape
        dtype = inst.dtype
        # do something
        print(shape, dtype)

class NDArrayInitializer(HasTraits):

    a = NDArray()

    def setup_instance(self, *args, **kwargs):
        self.shape = kwargs.get('shape', None)
        self.dtype = kwargs.get('dtype', None)
        super(NDArrayInitializer, self).setup_instance(*args, **kwargs)

ndai = NDArrayInitializer()

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Yup, that is nicer :)

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea But wait, why can't I just do this in __new__? Why even bother with overriding setup_instance?

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

@NeilGirdhar, check out problem case from #171. If we consider the example of NDArray I just gave, the issue there is that you need to call super().__new__(...) to get a new instance that you would assign shape and dtype to. However super().__new__ would call this chain of functions:

HasDescriptors.__new__ --> HasDescriptors.setup_instance --> NDArray.instance_init

Which will cause NDArray.instance_init to raise an AttributeError since the new instance won't have the required attributes.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Right! I forgot about that. I looked at this once and discovered this too. Okay, thanks again for the explanation.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

@NeilGirdhar, in reviewing the thread, we'd talked about using dynamic defaults to solve this problem. Is that approach no longer appropriate? This is what a solution using dynamic defaults would look like:

class NDArray(TraitType): pass

class NDArrayInitializer(HasTraits):

    a = NDArray()

    @default('a')
    def _make_default(self):
        return np.zeros(self.shape, dtype=self.dtype)

print(NDArrayInitializer().a)

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Then I have to do that every time I instantiate NDArray? I'd rather do that in one place.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

What if this were possible (it isn't right now):

class NDArray(TraitType):

    def make_dynamic_default(self, inst):
        shape = inst.shape
        dtype = inst.dtype
        # do something

class NDArrayInitializer(HasTraits):

    a = NDArray()

print(NDArrayInitializer().a)

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea Yeah, that's not bad. I'd rather initialize on object creation rather than trait access personally, so I prefer your earlier solution.

from traitlets.

rmorshea avatar rmorshea commented on July 20, 2024

From your earlier example I noticed you using trait.set to "create a default value", however using trait.set to do this isn't quite right since it will cause notifications to be fired. If this is done in instance_init, notifications that depend on other traits having been initialized will fail.

from traitlets.

NeilGirdhar avatar NeilGirdhar commented on July 20, 2024

@rmorshea I see, thanks. I will use your nicer solution as soon as the relevant changelists are checked in. I am now subscribed to them. :)

from traitlets.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.