python add object to variable when using deepcopy

I've got a few questions. Keep in mind i need to use deep copy as my classes will be expanding in complexity.

  • Is there a way to make it not reach the recursion limit when i do a deep copy?
  • When I preform a deep copy I want the new copy to be appended to the NODES variable just like it does in the init?

import copy

# Global
NODES = []

# Classes
class Node(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Truck(Node):
    def __init__(self, name="", age=0):
        super(Truck, self).__init__(name=name, age=age)
        NODES.append(self)

class Car(Node):
    def __init__(self, name="", age=0):
        super(Car, self).__init__(name=name, age=age)
        NODES.append(self)

    def __deepcopy__(self, memo):
        print '__deepcopy__(%s)' % str(memo)
        return Car(copy.deepcopy(self, memo))


Truck( name="Tonka Truck")
Truck( name="Monster Truck")
Truck( name="Pickup Truck")
car = Car( name="Oldsmobile Car")
car.age = 55
new_car = copy.deepcopy( car )

type_name = "Car"
cars = [x for x in NODES if type(x).__name__ == type_name]
print cars

print "NODES:"
for node in NODES:
    print "\t", node.name, node.age

Answers


First, you really should use a defaultdict for Toys. It just meet this requirement If the superclass doesn't exists, it adds and appends the object. So let's go with

Toys = collections.defaultdict(list)

If you did not want to use copy.deepcopy, you could simply change Node.__init__ method to:

class Node(object):
    def __init__(self, name, superclass):
        self.name = name
        self.superclass = superclass
        Toys[superclass].append(self)

It works fine when you create a new Truck:

t = truck()
Toys['Trucks'][-1] is t

gives True

Unfortunately, deepcopy uses a special construction scheme and bypasses __init__ here.

But when __init__ can't do, just call __new__ to help...

__new__ is a lower level special method called as a class method to create the object before __init__ is called. And even deepcopy created objects are created with __new__. As it is a class method, you just need to declare the superclass names (BTW a superclass is another animal and you really should use a different name...) as a class attribute.

You code becomes:

import copy
import collections

# Globals
Toys = collections.defaultdict(list)

class Node(object):
    def __new__(cls):
        obj = super(Node, cls).__new__(cls)
        superclass = cls.superclass
        Toys[superclass].append(obj)
        return obj

    def __init__(self, name=""):
        self.name = name

class Truck(Node):
    superclass = "Trucks"

class Car(Node):
    superclass = "Boats"

class Boat(Node):
    superclass = "Nodes"

class Plane(Node):
    superclass = "Planes"


t = Truck()
t.name = "Tonka Truck"
print Toys
t2 = copy.deepcopy( t )
print t, t2, Toys

With this output:

defaultdict(<type 'list'>, {'Trucks': [<__main__.Truck object at 0x0000000002D71A20>]})
<__main__.Truck object at 0x0000000002D71A20> <__main__.Truck object at 0x0000000002D71B70> defaultdict(<type 'list'>, {'Trucks': [<__main__.Truck object at 0x0000000002D71A20>, <__main__.Truck object at 0x0000000002D71B70>]})

That proves that:

  • Trucks list has automatically been added to Toys
  • t created as Truck() as been correctly added to Toys['Trucks']
  • t2 create with deepcopy as been correctly added to Toys['Trucks']

You now just have to change to superclass name for this code to be acceptable...


Need Your Help

Installing lighttpd in CentOS 6.0

linux webserver centos lighttpd

I never used CentOS, I only used Ubuntu, and I'm really new in web server matters. I couldn't find any easy way to install Lighttpd in CentOS 6.0. Could anyone please instruct me how to install Lig...

CRUD approach with RadGridView, DataForm & MVVM-light

c# telerik mvvm-light radgridview dataform

I have been banging my head on and on, i cant seem to work around the problem i am facing.