Python - InExcludeData initialization problem

I had a problem (again) with InExcludeData. this time with initializing the thing

Also, it seems like there is no way to merge two different InExcludeData fields to make a single InExcludeData list with no object duplicates on it.

Can any of you can explain to me how can I really do this using Python?
8333ccd7-1f71-49e9-aa85-e7296b4a2eee-image.png
It basically was unclear for me as of now...

Hi,

the docs are trying to tell you that the argument v is an optional argument. For the rest, see the attached example.

Cheers,
zipit

""" Run this in the Script Manager.

You will need to select an object in your scene, which has InExcludeData 
fields as its first and second user data element. The fields should be
ideally populated with overlapping sets of objects (e.g. [a, b, c] and [b, 
c, d]). The script will write the union of those two object sets to the first
InExcludeData field.
"""

import c4d

def get_objects(doc, op):
    """Returns the objects referenced by an InExcludeData as a list.
    
    Args:
        doc (c4d.documents.BaseDocument): The document the referenced 
         objects are attached to.
        op (c4d.InExcludeData): The InExcludeData to get the objects from.
    
    Returns:
        list[c4d.BaseObject]: The referenced objects.
    """
    return [op.ObjectFromIndex(doc, i) 
            for i in range(op.GetObjectCount())]

def main():
    """
    """
    if op is None:
        return

    # The two InExcludeData
    inex_a = op[c4d.ID_USERDATA, 1]
    inex_b = op[c4d.ID_USERDATA, 2]

    # Get the objects 
    nodes_a = get_objects(doc, inex_a)
    nodes_b = get_objects(doc, inex_b)
    print "nodes in inex_a:", nodes_a
    print "nodes in inex_b:", nodes_b

    # Create a new InExcludeData, using the default constructor.
    inex_c = c4d.InExcludeData()
    # Unsurprisingly there is nothing in there.
    print "nodes in inex_c:", get_objects(doc, inex_c)

    # Create a new InExcludeData, using the copy constructor.  
    inex_d = c4d.InExcludeData(inex_a)
    # Since we copied from inex_a, it references the same objects.
    print "nodes in inex_d:", get_objects(doc, inex_d)

    # Adding the union of the object sets a and b to a new InExcludeData is
    # a little bit convoluted, because the type InExcludeData is not a set
    # by nature and nodes not being hashable prevents us from using Python's
    # sets.
    nodes_union = nodes_a + [n for n in nodes_b if n not in nodes_a]
    inex_union = c4d.InExcludeData()
    for node in nodes_union:
        inex_union.InsertObject(node, 0)

    # Write the union back to the first InExcludeData. 
    op[c4d.ID_USERDATA, 1] = inex_union
    c4d.EventAdd()


if __name__=='__main__':
    main()```

Hi @SolarPH, thanks for reaching out us.

With regard to your question, actually initializing the InExcludeData has nothing to do with having the list not including duplicates.
The v parameter pointed out in the documentation is used to fill the to-be-created InExcludeData with the values found in the passed InExcludeData as @zipit has shown in line 48.
To avoid duplication instead you've to manually browse the items in the lists and pickup from the second only those not found in the first. Again @zippit code perfectly shows this.

Cheers, R

@zipit Thanks for sharing the code. Now I know that initializing the InExcludeData is not InExcludeData.__init__ and the correct way was c4d.InExcludeData(), which I really did not think of when initializing specialized data containers.

Hi,

@SolarPH said in Python - InExcludeData initialization problem:

Now I know that initializing the InExcludeData is not InExcludeData.__init__ and the correct way was c4d.InExcludeData(), ...

I am not quite sure how you did mean this, but InExcludeData.__init__ is one of the methods called when you invoke c4d.InExcludeData(). Like all double underscore methods __init__ implements an operator, in that case the construction operator. Invoking SomeClass() will first call the constructor SomeClass.__new__ and after that the initialisator SomeClass.__init__. Due to the fact that __new__ only rarely has to be implemented explicitly and because people are accustomed to talking about constructor functions, __init__ is also often called a constructor, while technically it is just the initialisator. A prime example would be both the InExcludeData documentation and my example code, which both talk about a copy constructor, but are actually referring to __init__ and not __new__.

Cheers,
zipit