@@ -110,6 +110,12 @@ def __new__(cls, data, dtype=None, copy=False, name=None, **kwargs):
110
110
return Int64Index (data , copy = copy , dtype = dtype , name = name )
111
111
112
112
subarr = com ._asarray_tuplesafe (data , dtype = object )
113
+
114
+ # _asarray_tuplesafe does not always copy underlying data,
115
+ # so need to make sure that this happens
116
+ if copy :
117
+ subarr = subarr .copy ()
118
+
113
119
elif np .isscalar (data ):
114
120
raise TypeError ('Index(...) must be called with a collection '
115
121
'of some kind, %s was passed' % repr (data ))
@@ -120,7 +126,7 @@ def __new__(cls, data, dtype=None, copy=False, name=None, **kwargs):
120
126
if dtype is None :
121
127
inferred = lib .infer_dtype (subarr )
122
128
if inferred == 'integer' :
123
- return Int64Index (subarr .astype ('i8' ), name = name )
129
+ return Int64Index (subarr .astype ('i8' ), copy = copy , name = name )
124
130
elif inferred != 'string' :
125
131
if (inferred .startswith ('datetime' ) or
126
132
tslib .is_timestamp_array (subarr )):
@@ -145,6 +151,41 @@ def __array_finalize__(self, obj):
145
151
def _shallow_copy (self ):
146
152
return self .view ()
147
153
154
+ def copy (self , names = None , name = None , dtype = None , deep = False ):
155
+ """
156
+ Make a copy of this object. Name and dtype sets those attributes on
157
+ the new object.
158
+
159
+ Parameters
160
+ ----------
161
+ name : string, optional
162
+ dtype : numpy dtype or pandas type
163
+
164
+ Returns
165
+ -------
166
+ copy : Index
167
+
168
+ Notes
169
+ -----
170
+ In most cases, there should be no functional difference from using
171
+ ``deep``, but if ``deep`` is passed it will attempt to deepcopy.
172
+ """
173
+ if names is not None and name is not None :
174
+ raise TypeError ("Can only provide one of `names` and `name`" )
175
+ if deep :
176
+ from copy import deepcopy
177
+ new_index = np .ndarray .__deepcopy__ (self , {}).view (self .__class__ )
178
+ name = name or deepcopy (self .name )
179
+ else :
180
+ new_index = super (Index , self ).copy ()
181
+ if name is not None :
182
+ names = [name ]
183
+ if names :
184
+ new_index = new_index .set_names (names )
185
+ if dtype :
186
+ new_index = new_index .astype (dtype )
187
+ return new_index
188
+
148
189
def __unicode__ (self ):
149
190
"""
150
191
Return a string representation for a particular Index
@@ -338,10 +379,7 @@ def __setstate__(self, state):
338
379
np .ndarray .__setstate__ (self , state )
339
380
340
381
def __deepcopy__ (self , memo = {}):
341
- """
342
- Index is not mutable, so disabling deepcopy
343
- """
344
- return self ._shallow_copy ()
382
+ return self .copy (deep = True )
345
383
346
384
def __contains__ (self , key ):
347
385
hash (key )
@@ -1440,9 +1478,9 @@ class MultiIndex(Index):
1440
1478
1441
1479
Parameters
1442
1480
----------
1443
- levels : list or tuple of arrays
1481
+ levels : sequence of arrays
1444
1482
The unique labels for each level
1445
- labels : list or tuple of arrays
1483
+ labels : sequence of arrays
1446
1484
Integers for each level designating which label at each location
1447
1485
sortorder : optional int
1448
1486
Level of sortedness (must be lexicographically sorted by that
@@ -1455,7 +1493,8 @@ class MultiIndex(Index):
1455
1493
_levels = FrozenList ()
1456
1494
_labels = FrozenList ()
1457
1495
1458
- def __new__ (cls , levels = None , labels = None , sortorder = None , names = None ):
1496
+ def __new__ (cls , levels = None , labels = None , sortorder = None , names = None ,
1497
+ copy = False ):
1459
1498
if len (levels ) != len (labels ):
1460
1499
raise ValueError (
1461
1500
'Length of levels and labels must be the same' )
@@ -1467,12 +1506,12 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None):
1467
1506
else :
1468
1507
name = None
1469
1508
1470
- return Index (levels [0 ], name = name ).take (labels [0 ])
1509
+ return Index (levels [0 ], name = name , copy = True ).take (labels [0 ])
1471
1510
1472
1511
# v3, 0.8.0
1473
1512
subarr = np .empty (0 , dtype = object ).view (cls )
1474
- subarr ._set_levels (levels )
1475
- subarr ._set_labels (labels )
1513
+ subarr ._set_levels (levels , copy = copy )
1514
+ subarr ._set_labels (labels , copy = copy )
1476
1515
1477
1516
if names is not None :
1478
1517
subarr ._set_names (names )
@@ -1489,13 +1528,13 @@ def _get_levels(self):
1489
1528
return self ._levels
1490
1529
1491
1530
1492
- def _set_levels (self , levels ):
1531
+ def _set_levels (self , levels , copy = False ):
1493
1532
# This is NOT part of the levels property because it should be
1494
1533
# externally not allowed to set levels. User beware if you change
1495
1534
# _levels directly
1496
1535
if len (levels ) == 0 :
1497
1536
raise ValueError ("Must set non-zero number of levels." )
1498
- levels = FrozenList (_ensure_index (lev )._shallow_copy ()
1537
+ levels = FrozenList (_ensure_index (lev , copy = copy )._shallow_copy ()
1499
1538
for lev in levels )
1500
1539
names = self .names
1501
1540
self ._levels = levels
@@ -1534,10 +1573,11 @@ def set_levels(self, levels, inplace=False):
1534
1573
def _get_labels (self ):
1535
1574
return self ._labels
1536
1575
1537
- def _set_labels (self , labels ):
1576
+ def _set_labels (self , labels , copy = False ):
1538
1577
if len (labels ) != self .nlevels :
1539
1578
raise ValueError ("Length of levels and labels must be the same." )
1540
- self ._labels = FrozenList (_ensure_frozen (labs )._shallow_copy () for labs in labels )
1579
+ self ._labels = FrozenList (_ensure_frozen (labs ,copy = copy )._shallow_copy ()
1580
+ for labs in labels )
1541
1581
1542
1582
def set_labels (self , labels , inplace = False ):
1543
1583
"""
@@ -1546,8 +1586,8 @@ def set_labels(self, labels, inplace=False):
1546
1586
1547
1587
Parameters
1548
1588
----------
1549
- labels : sequence
1550
- new levels to apply
1589
+ labels : sequence of arrays
1590
+ new labels to apply
1551
1591
inplace : bool
1552
1592
if True, mutates in place
1553
1593
@@ -1592,6 +1632,11 @@ def copy(self, names=None, dtype=None, levels=None, labels=None,
1592
1632
This could be potentially expensive on large MultiIndex objects.
1593
1633
"""
1594
1634
new_index = np .ndarray .copy (self )
1635
+ if deep :
1636
+ from copy import deepcopy
1637
+ levels = levels if levels is not None else deepcopy (self .levels )
1638
+ labels = labels if labels is not None else deepcopy (self .labels )
1639
+ names = names if names is not None else deepcopy (self .names )
1595
1640
if levels is not None :
1596
1641
new_index = new_index .set_levels (levels )
1597
1642
if labels is not None :
@@ -2831,11 +2876,13 @@ def _sparsify(label_list, start=0,sentinal=''):
2831
2876
return lzip (* result )
2832
2877
2833
2878
2834
- def _ensure_index (index_like ):
2879
+ def _ensure_index (index_like , copy = False ):
2835
2880
if isinstance (index_like , Index ):
2881
+ if copy :
2882
+ index_like = index_like .copy ()
2836
2883
return index_like
2837
2884
if hasattr (index_like , 'name' ):
2838
- return Index (index_like , name = index_like .name )
2885
+ return Index (index_like , name = index_like .name , copy = copy )
2839
2886
2840
2887
# must check for exactly list here because of strict type
2841
2888
# check in clean_index_list
@@ -2849,15 +2896,27 @@ def _ensure_index(index_like):
2849
2896
return MultiIndex .from_arrays (converted )
2850
2897
else :
2851
2898
index_like = converted
2899
+ else :
2900
+ # clean_index_list does the equivalent of copying
2901
+ # so only need to do this if not list instance
2902
+ if copy :
2903
+ from copy import copy
2904
+ index_like = copy (index_like )
2852
2905
2853
2906
return Index (index_like )
2854
2907
2855
- def _ensure_frozen (nd_array_like ):
2856
- if isinstance (nd_array_like , FrozenNDArray ):
2857
- return nd_array_like
2858
- else :
2908
+
2909
+ def _ensure_frozen (nd_array_like , copy = False ):
2910
+ if not isinstance (nd_array_like , FrozenNDArray ):
2859
2911
arr = np .asarray (nd_array_like , dtype = np .int_ )
2860
- return arr .view (FrozenNDArray )
2912
+ # have to do this separately so that non-index input gets copied
2913
+ if copy :
2914
+ arr = arr .copy ()
2915
+ nd_array_like = arr .view (FrozenNDArray )
2916
+ else :
2917
+ if copy :
2918
+ nd_array_like = nd_array_like .copy ()
2919
+ return nd_array_like
2861
2920
2862
2921
2863
2922
def _validate_join_method (method ):
0 commit comments