The former, since it's more explicit about what the parameters are and what the object requires.
If you do need to pass in your data as a tuple, there's a shortcut you can use. Instead of doing the latter, or something like:
test = Test(data[0], data[1], data[2], data[3])
You can instead unpack the list/tuple and do:
test = Test(*data)
If you need to pass in a bunch of data (more then 4-5), you should look into either using optional/keyword arguments, creating a custom object to hold some of the data, or using a dictionary:
config = Config(a, b, c, d)
test = Test(e, f, config, foo=13, bar=True)
I would probably refactor your Link class to look like this:
class Node(object):
def __init__(self, node, setback, bearing):
self.node = node
self.setback = setback
self.bearing = bearing
class Connection(object):
def __init__(self, lanes, left, right, speed, fspd, capacity):
self.lanes = lanes
self.left = left
self.right = right
self.speed = speed
self.fspd = fspd
self.capacity = capacity
class Link(object):
def __init__(self, street, length, ltype, use, a, b, ab, ba):
self.street = street
self.length = length
self.ltype = ltype
self.use = use
self.a = a
self.b = b
self.ab = ab
self.ba = ba
I saw that you had some duplicate data, so pulled those off into a separate object. While this doesn't reduce on the number of fields you have, overall, it does make the parameters you need to pass in smaller.
Having a large number of fields isn't bad, but having a large number of parameters generally is. If you can write your methods in a way that they don't need a huge amount of parameters by bundling together data, then it doesn't really matter how many fields you have.
Test(b=4, a=3, d=1, c=1)Test(*[1, 2, 3, 4]).cfg = {'a': 1, 'b':2, ...}and pass it asTest(**cfg).