You cannot materialize an object from a non-existing reference. Python names have to exist for them to work.
Instead, give the data3 keyword a default, then when the keyword is not specified, create the instance:
_sentinel = object()
class my_data():
def __init__(self, data1, data2, data3=_sentinel):
if data3 is _sentinel:
data3 = my_data(None, None, None)
self.data1 = data1
self.data2 = data2
self.data3 = data3
Now you can create instances of my_data() with a default new instance for data3:
>>> d2 = my_data('a', 'b')
>>> d1 = d2.data3
>>> d1
<__main__.my_data instance at 0x10e994cf8>
>>> vars(d2), vars(d1)
({'data1': 'a', 'data3': <__main__.my_data instance at 0x10e994cf8>, 'data2': 'b'}, {'data1': None, 'data3': None, 'data2': None})
Because we used a sentinel default value, you can still set data3 to None as well:
>>> d3 = my_data('a', 'b', None)
>>> d3.data3 is None
True
A mutable list on the class can hold all instances; just set the list as a class attribute and append new instances to that:
_sentinel = object()
class my_data():
instances = []
def __init__(self, data1, data2, data3=_sentinel):
if data3 is _sentinel:
data3 = my_data(None, None, None)
self.data1 = data1
self.data2 = data2
self.data3 = data3
my_data.instances.append(self)
and you can list all instances with my_data.instances.
Do note that this creates circular references, keeping instances alive even when you no longer use them anywhere else. Use the weakref module if you want to prevent this.