4

I have define a class in Python

class node(object):
    def __init__(self, children = []):
        self.children = children

I would like to create a list or array of default objects of class node. For example, something like in C++

node * nodes = node[100];

then nodes will point to an array of 100 default objects of class node.

How is it done similarly in Python? Thanks.

Tim
  • 1
  • 141
  • 372
  • 590
  • 3
    You might want to make `children = None and if not children: children = []` – Padraic Cunningham Aug 21 '14 at 22:24
  • 2
    @PadraicCunningham He definitely should do that, but I don't think you should use `if not children:`, in case you later want to initialize it as an empty list or something else that tests as `False`. Safer, more clear, and not much longer to use `if children is None:`. – Roger Fan Aug 21 '14 at 22:28
  • @PadraicCunningham: I don't quite understand why my class definition is not good and what you suggest me to do. can you modify my class definition in your post as well? – Tim Aug 21 '14 at 22:31
  • 2
    The blog post [Gotcha - Mutable default arguments](http://pythonconquerstheuniverse.wordpress.com/2012/02/15/mutable-default-arguments/) explains why assigning an empty list as a default argument is likely to be an error. – Steven Rumbalski Aug 21 '14 at 22:31
  • @Tim, I added a quick example – Padraic Cunningham Aug 21 '14 at 22:35
  • Also see [this question](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) for the canonical SO question about mutable-objects-as-default-arguments. – dano Aug 21 '14 at 23:26

3 Answers3

7

Using a list comprehension:

nodes = [node() for _ in range(100)]
Roger Fan
  • 4,945
  • 31
  • 38
5

You can use a list comprehension:

nodes = [node() for _ in range(100)]

Python doesn't have a concept of "arrays" per se, but it has lists which are a higher-level structure. Lists can be indexed just like C arrays, and support many more complex operations.

arshajii
  • 127,459
  • 24
  • 238
  • 287
3
[node() for _ in range(100)]

And as I said in my comment:

class node(object):
    def __init__(self, children=None):
        if children is None: children = []
        self.children = children

If you used def __init__(self, children= []):, any changes you make to the list will change for all instances:

In [18]: class node(object):
   ....:     def __init__(self, children = []):
   ....:            self.children = children
   ....:         

In [19]: n1= node()

In [20]: n2 = node()

In [21]: n1.children.append("foo") # add using n1 

In [22]: n1.children
Out[22]: ['foo']

In [23]: n2.children # also effects n2's children list
Out[23]: ['foo']

Correct way:

In [24]: class node(object):
   ....:     def __init__(self, children=None):
   ....:            if children is None: children = []
   ....:            self.children = children
   ....:         

In [25]: n1= node()

In [26]: n2 = node()

In [27]: n1.children.append("foo")

In [28]: n1.children
Out[28]: ['foo']

In [29]: n2.children
Out[29]: []
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • why if using "def __init__(self, children= []):, any changes you make to the list will change for all instances"? – Tim Aug 21 '14 at 22:38
  • 1
    `map(node, range(100))` will construct `node(0)`, `node(1)`, etc., which will lead to problems when you try to use the `children` attributes of those nodes as lists. – jwodder Aug 21 '14 at 22:39
  • @Tim: Default arguments are evaluated at the time the function is created -- not when the function is called. Another way of saying this is that `def` is an executable statement. – Steven Rumbalski Aug 21 '14 at 22:42
  • @Tim, yes the list is created once, so if you have a mutable default argument then you will have one object created when the function is created. – Padraic Cunningham Aug 21 '14 at 22:45