I was wondering what the best (most pythonic) solution is to pass a list or a variable number of arguments to a function/method.
For example I have to following class:
class Dataset():
def __init__(self, *args):
self.data_set = args
and this is a part of the setter property:
@data_set.setter
def data_set(self, args):
data = []
for item in args:
if type(item) is list:
data = [k for k in item]
break
data.append(item)
self._data_set = data
I searched the web, but coudn't find much on the topic. My goal here is to design the class constructor such that it works with either a list as given parameter:
ds1 = Dataset([4,3,5])
or variable number or arguments:
ds1 = Dataset(4,3,5)
So, what is the best implementation and am I on the right track?
You can try this,
class Dataset():
def __init__(self, *args):
if isinstance(args[0], list) and len(args) == 1:
print('Received a list')
else:
print('Received:', args)
obj = Dataset(1,2,3)
obj = Dataset([1,2,3], 2)
obj = Dataset([1,2,3])
ouputs:
Received: (1, 2, 3)
Received: ([1, 2, 3], 2)
Received a list
This code does what you want in a simple way. Nothing more. There are other ways, they don't look simple to me.
Your comment is actually an excellent question.
The problem is not in this code, but in what you are asking and the Python language. You want method overloading, and Python doesn't have it.
Testing argument types is unpythonic because Python is a dynamic typed language.You can do it, but you are restricting your functions usefulness to a specific type.
Testing the argument type also results in a typical if..elif
chain.
If you are writing functions take a look at functools.singledispatch
decorator.
That eliminates the if..elif
chain from code. Using it you can define a base function and register specific implementations for each type. Simple and readable. But this routes to the function implementation based on first argument. Now, for instance methods, this won't work because of self
. You can change that, but it doesn't look simple any more.
Because Python doesn't support method/function overloading directly, what you asked is not a common pattern to use.
Now Aran Fey gives you good advice. Coding behaviour like this is uncommon in Python and actually introduces ambiguity. Your API contract becomes unclear. Should I pass a list or varargs. And why the choice? Just because you already have tuples and dicts with *args and *kwargs and want lists too? What about building the "varargs" as the list elements?
You ask for a list or a variable number of arguments, but a list has also a "variable number of arguments" in itself.
So use one or the other. If you go ahead with the initial idea, at least keep it simple like in this answer.