简体   繁体   中英

assigning an object to multiple variables - python

Is it possible to assign a single numpy object to several variables in one go?

For instance, I have many variables that I'd like to initiate with np.zeros((2,), dtype=np.object)

I thought of doing a,b,c = np.zeros((2,), dtype=np.object) but got a ValueError . a=b=c=np.zeros((2,), dtype=np.object) doesn't work either because if I change one variable the others also change.

With three variables like the example above it isn't a problem to do it manually but when I have dozens it would be convenient to be able to do this in a more effient way.

EDIT - A more concrete example would be:

a = np.zeros((2,),dtype=np.object)
b = np.zeros((2,),dtype=np.object)
c = np.zeros((2,),dtype=np.object)


a[0] = pd.Series(data=np.random.rand(10))
a[1] = pd.Series(data=np.random.rand(5))

b[0] = 'text1'
b[1] = 'text2'

c[0] = [0,0,0,0,0,0,0,0,0]
c[1] = [1,1,1,1,1]

data = {'a':a, 'b':b, 'c':c}

sio.savemat('test.mat',{'data':data})

Use a list comprehension:

>>> a, b, c = [np.zeros((2,), dtype=np.object) for _ in xrange(3)]
>>> [id(x) for x in (a,b,c)]      
[172542064, 171775688, 168893512] #Different objects

If you're planning to add dozens of variables like this, then better use a dictionary :

>>> my_vars = {x:np.zeros((2,), dtype=np.object) for x in 'abcdef'}
>>> my_vars
{'a': array([0, 0], dtype=object), 'c': array([0, 0], dtype=object), 'b': array([0, 0], dtype=object), 'e': array([0, 0], dtype=object), 'd': array([0, 0], dtype=object), 'f': array([0, 0], dtype=object)}

In your actual code, there is no reason to have these variables just so you can insert them all into a dict. And there's also no reason to initialize the values to equal arrays in the first place just so you can then mutate them into the arrays you actually want. If you write everything in the obvious way, the problem you're trying to solve never even arises:

data = {}
data['a'] = np.array([pd.Series(data=np.random.rand(10)),
                      pd.Series(data=np.random.rand(5))])
data['b'] = np.array(['text1', 'text2'])
data['c'] = np.array([[0,0,0,0,0,0,0,0,0], [1,1,1,1,1]])
sio.savemat('test.mat',{'data':data})

If you think you need to pre-create and then mutate the arrays to guarantee that you get the results you want, as you claim in the comments… well, first, just run this code and you'll see that you get three 1D object arrays, not 2D arrays of something else. But if you don't know how to determine that for yourself, and don't want to just try it and test, you can always explicitly specify the dtype (either as object , or as a complex type) to force it.

And meanwhile, even if you did need to pre-create the arrays (which, again, you don't), there would still be no reason to create dozens of separate variables and then put them in a dict after the fact. In other words, just do this:

arrays = np.zeros((3,2), dtype=np.object)
data = dict(zip(string.ascii_lowercase, arrays))

Or, if you really want entirely separate arrays for some reason instead of sliced out of a higher-dimensional array:

arrays = [np.zeros((2,), dtype=np.object) for _ in range(3)]
data = dict(zip(string.ascii_lowercase, arrays))

And of course you can wrap this all up in a function if you're doing it multiple times.

A nice way to make several arrays is to add the number of desired output arrays as the first dimension ( axis 0 ). So, if you want three arrays of length two, filled with zeros of dtype object, you can do this:

a, b, c = np.zeros((3,2), object)

This works for any array, where the unpacking is from the first axis, for some examples:

a, b, c = np.random.rand(3, 4, 5)
a, b  = np.arange(12).reshape(2,-1)

NB: This is not identical to doing

a, b, c = [np.zeros((2,), object) for _ in xrange(3)]

Because in that case each of the arrays were created separately, and won't necessarily be contiguous in memory. If you use the unpacking of a single array, the original array was first created as one single contiguous array, and the new arrays are just views of the original array. You haven't saved the original array, so I can't see this in any effect, but if you did store, then split the array, you'd see they shared data:

In [96]: orig = np.zeros((3,2), dtype=np.object)

In [97]: a, b, c = orig

In [98]: orig
Out[98]: 
array([[0, 0],
       [0, 0],
       [0, 0]], dtype=object)

In [99]: a
Out[99]: array([0, 0], dtype=object)

In [100]: a[0] = 9

In [101]: a
Out[101]: array([9, 0], dtype=object)

In [102]: orig
Out[102]: 
array([[9, 0],
       [0, 0],
       [0, 0]], dtype=object)

But without the orig array being saved/referred to elsewhere, I can't see this being an issue. The only way to see the difference is by checking the flags:

In [103]: a, b, c = np.zeros((3,2), dtype=np.object)

In [104]: a.flags.owndata
Out[104]: False

In [105]: a, b, c = [np.zeros((2,), dtype=np.object) for _ in xrange(3)]

In [106]: a.flags.owndata
Out[106]: True

The below is absolutely not recommended, but cool nevertheless

locals().update({
    'x%d' % i : np.zeros((2,), dtype=np.object)
    for i in range(3)
})
print x2
=> array([0, 0], dtype=object)

But, again, don't do it. Use a list (for example) instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM