opened
flying-sheep
username_0
This here:

https://github.com/theislab/anndata/blob/38c500dc8e9becd4c78a82897dea5febcdb9e0a4/anndata/anndata.py#L669

would e.g. be nicer as

```py
def concatenate(self, *adatas, batch_key='batch', batch_categories=None):
    ...
```
Use splats in API
issue
created
falexwolf
username_1
I agree that splats are nicer... and they have been used in Scanpy since the very first lines, e.g. 
https://github.com/theislab/scanpy/blob/218a2cb53c4fdb4cd834efc5a8ff6fcaabf16d91/scanpy/logging.py#L47

However, both pandas and numpy don't use it in their concat function 
([np](https://docs.scipy.org/doc/numpy/reference/generated/numpy.concatenate.html#numpy.concatenate), [pd](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.concat.html)) and I took these as the model for AnnDatas concat function.

Hence, I'm not sure whether we should deviate from this - I think we should be as close as possible to numpy and pandas whenever it's not completely outrageous.

PS: The Scanpy users are often not very python experienced, and they are used to passing lists without a splat star (`*alist`) also in many other places, like plotting an AnnData with several colors
```
sc.pl.scatter(adata, color=['anno1', 'anno2', 'anno3'])
```
comment
created
flying-sheep
username_0
i see. that’s unfortunate, since numpy’s API [is confusing](https://stackoverflow.com/questions/9236926/concatenating-two-one-dimensional-numpy-arrays) for newbies as well.

so we’re stuck between a rock and a hard place: be confusing for python beginners or be confusing for numpy-experienced users.

i think that a good error message goes a long way – using splats means the user can’t pass further arguments by position but only by keyword (which is a good thing), and we could provide either a custom error message, or special handling of sequences being passed as only positional argument, like:

```py
def concatenate(*adatas, batch_key='batch', batch_categories=None):
    if len(adatas) == 1 and not isinstance(adatas[0], AnnData):
        try:  # convert iterable into tuple
            adatas = tuple(adatas[0])
        except Exception:
            pass
```
comment
closed
falexwolf
username_1
issue