Clone and replace attributes that are instances of a specific class
You are overly complicating what you are trying to achieve by defining your Replacer class. You need two passes because your logic is:


store each id of custom objects into visited, associated to a copy of it;
change the value associated to ids of T objects into 100.


See how in 1. you already made a copy? You don't need that, you need to change how objects are copied in the first place.

The deepcopy function tries to copy a custom object x using one of 3 functions, in that order:


x.__deepcopy__;
x.__reduce_ex__(2);
x.__reduce__().


__reduce_ex__ and __reduce__ are a bit special and provided by object by default so better not to touch it. __deepcopy__, however, is copy.deepcopy own mechanism and should be used anytime you want to change how deepcopy should create new objects out of old ones.

If all you want to do is to turn all Ts into 100 when deepcopying an arbitrary object, then all you have to do is to implement T.__deepcopy__ in such a way:

class T(object):
    def __deepcopy__(self, memo): # expected signature for copy.deepcopy
        return 100


Every deepcopy will then turn each T into 100:


Ex1:

&gt;&gt;&gt; b = [1,2,"hello",T(),('a',3,T()),T()]
&gt;&gt;&gt; copy.deepcopy(b)
[1, 2, 'hello', 100, ('a', 3, 100), 100]

Ex2, using your A and B classes:

&gt;&gt;&gt; b = B()
&gt;&gt;&gt; bb = copy.deepcopy(b)
&gt;&gt;&gt; bb.t2
100
&gt;&gt;&gt; bb.a.t1
100



Note that in the context of your implementation and various calls, the T.__deepcopy__'s memo parameter would be an alias to visited, use it as you see fit if you want to implement custom logic. Read the last paragraph of the documentation for specific use cases.