From 56e3a4a913e3e761928210d8dbdb7068a0f68ce5 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 19 Nov 2014 02:45:56 -0600 Subject: [PATCH] Finish dictionaries, lists, and tuples. --- _drafts/python-object-replacement.md | 95 +++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/_drafts/python-object-replacement.md b/_drafts/python-object-replacement.md index 27584bf..d2fd9ad 100644 --- a/_drafts/python-object-replacement.md +++ b/_drafts/python-object-replacement.md @@ -565,26 +565,105 @@ should work for any case where `a` is in a dictionary-like object. ## Handling different reference types -We'll continue by wrapping this code up in a nice function: +We'll continue by wrapping this code up in a nice function, which we will +expand as we go: {% highlight python %} +import guppy +from guppy.heapy import Path + +hp = guppy.hpy() + def replace(old, new): - pass + for path in hp.iso(old).pathsin: + relation = path.path[1] + if isinstance(relation, Path.R_INDEXVAL): + path.src.theone[relation.r] = new {% endhighlight %} -### Dictionaries +### Dictionaries, lists, and tuples + +As noted above, this is versatile to handle many dictionary-like situations, +including `__dict__`, which means we already know how to replace object +attributes: + +{% highlight pycon %} + +>>> a, b = A(), B() +>>> +>>> class X(object): +... pass +... +>>> X.cattr = a +>>> x = X() +>>> x.iattr = a +>>> d1 = {1: a} +>>> d2 = [{1: {0: ("foo", "bar", {"a": a, "b": b})}}] +>>> +>>> replace(a, b) +>>> +>>> print a +<__main__.B object at 0x1042b9910> +>>> print X.cattr +<__main__.B object at 0x1042b9910> +>>> print x.iattr +<__main__.B object at 0x1042b9910> +>>> print d1[1] +<__main__.B object at 0x1042b9910> +>>> print d2[0][1][0][2]["a"] +<__main__.B object at 0x1042b9910> + +{% endhighlight %} + +Lists can be handled exactly the same as dictionaries, although the keys in +this case (i.e., `relation.r`) will always be integers. -dicts, class attributes via `__dict__`, locals() +{% highlight pycon %} -### Lists +>>> a, b = A(), B() +>>> L = [0, 1, 2, a, b] +>>> print L +[0, 1, 2, <__main__.A object at 0x104598950>, <__main__.B object at 0x104598910>] +>>> replace(a, b) +>>> print L +[0, 1, 2, <__main__.B object at 0x104598910>, <__main__.B object at 0x104598910>] -simple replacement +{% endhighlight %} -### Tuples +Tuples are interesting. We can't modify them directly because they're +immutable, but we _can_ create a new tuple with the new value, and then replace +that tuple just like we replaced our original object: -recursively replace parent since immutable +{% highlight python %} + + # Meanwhile, in replace()... + if isinstance(relation, Path.R_INDEXVAL): + source = path.src.theone + if isinstance(source, tuple): + temp = list(source) + temp[relation.r] = new + replace(source, tuple(temp)) + else: + source[relation.r] = new + +{% endhighlight %} + +As a result: + +{% highlight pycon %} + +>>> a, b = A(), B() +>>> t1 = (0, 1, 2, a) +>>> t2 = (0, (1, (2, (3, (4, (5, (a,))))))) +>>> replace(a, b) +>>> print t1 +(0, 1, 2, <__main__.B object at 0x104598e50>) +>>> print t2 +(0, (1, (2, (3, (4, (5, (<__main__.B object at 0x104598e50>,))))))) + +{% endhighlight %} ### Bound methods