How do you copy custom property without referencing it?

This has been haunting me for so long.

I have a custom property.
On my code, I copy this as a template, and modify accordingly, without updating the original custom property.

Consider a reference dictionary with nested dictionary and color set to red.

image

When my code runs, I will copy the reference and modify the color values.
The shallow color will not get modified
The deep color will be modified. WTH!!!

illustration:

Input Colors:

image

My code:

Original Dictionary became:

image

Any BEST solution to this?

This is simply how jython (and Python in general) handles object assignments. You get references instead of copies for anything that isn't a primitive type (number, string).

You can perform shallow copy by passing the original dictionary-like object to the dict() function (constructor, really). Note that you'll get a shallow copy--a new dict, but any objects within it will be references.

To truly break off your own modifiable dictionary, you need a deep copy. Python stdlib has a function that does this for pure python types.

See my integration toolkit for Ignition helpers. (Or do your own recursive function.)

My Toolkit, of course. /shameless plug.

4 Likes

:heart:
I see. I did not pay attention last time, thank you for re-stating.

Who would want to shallow copy.?!

My own recursive:

d = system.util.jsonDecode(system.util.jsonEncode(original_object))

Shallow copying is much cheaper, especially as object graphs get more complex. It's a reasonable default.

Ewwww! Converting to and from JSON is really expensive.

1 Like

If you must do this without Phil’s module:

How you read my mind.
Here goes. When a novice developer wants to copy an object. He meant to deepcopy.. And should be the default.

I also encountered deepcopy throwing an error, so went to look another options.
But why do you need to deepcopy an object that was already encoded-decoded:

pen = deepcopy(system.util.jsonDecode(system.util.jsonEncode(self.view.custom.penEjemplo)))

Someday!

See Phil’s comments above. Option two in that thread is using phythons stdlib deepCopy, as shown by the import.

option 1 is the option that I would take and recommend.

FWIW, this is the one you want for Perspective applications:

unQualify()

1 Like
def deepcopy(node):
	"""
	Create a deep copy of nested data structures.

	Recursively copies dictionaries, iterables, and primitive values to create
	a completely independent copy of the original data structure. Handles nested
	combinations of dicts, lists, and other iterables.

	Args:
		node: The data structure to copy (dict, list, tuple, or primitive value)

	Returns:
		A deep copy of the input node with the same structure but independent objects
	"""
	if hasattr(node, 'items'):
		return {k: deepcopy(v) for k, v in node.iteritems()}
	elif hasattr(node, '__iter__'):
		return map(deepcopy, node)
	else:
		return node
1 Like

Jython's naive deepcopy (and Pascal's example) will fail to recurse into qualified values, which Perspective wraps around everything.

I'm pretty sure I've used this on some ignition wrappers.
What do you have in mind ?

Whenever I've used a naive deepcopy with a perspective array, it hands back a new array of the original QVs. That is, a shallow copy. So too with nested objects inside Perspective objects or arrays.