BUG: Index.intersection returns reference instead of new instance
Pandas version checks
-
[x] I have checked that this issue has not already been reported.
-
[x] I have confirmed this bug exists on the latest version of pandas.
-
[x] I have confirmed this bug exists on the main branch of pandas.
Reproducible Example
>>> import pandas as pd
>>>
>>> index1 = pd.Index([0, 1])
>>> index2 = pd.Index([0, 1])
>>> index3 = index1.intersection(index2)
>>> index3 is index1
True
Issue Description
The documentation for Index.intersection states:
This returns a new Index with elements common to the index and other.
However, there are cases where a reference to one of the operands is returned instead of a new instance. Subsequent operations on the returned object can end up mutating one of the operands, which is unexpected.
Expected Behavior
Index.intersection should always return a new instance.
Installed Versions
INSTALLED VERSIONS
commit : 7bf666098400d1f09a8491c10f163c972d19c946 python : 3.13.7 python-bits : 64 OS : Linux OS-release : 6.17.8-arch1-1 Version : #1 SMP PREEMPT_DYNAMIC Fri, 14 Nov 2025 06:54:20 +0000 machine : x86_64 processor : byteorder : little LC_ALL : None LANG : en_US.UTF-8 LOCALE : en_US.UTF-8
pandas : 3.0.0.dev0+2728.g7bf6660984 numpy : 2.3.5 dateutil : 2.9.0.post0 pip : 25.2 Cython : None sphinx : None IPython : None adbc-driver-postgresql: None adbc-driver-sqlite : None bs4 : None bottleneck : None fastparquet : None fsspec : None html5lib : None hypothesis : None gcsfs : None jinja2 : None lxml.etree : None matplotlib : None numba : None numexpr : None odfpy : None openpyxl : None psycopg2 : None pymysql : None pyarrow : None pyiceberg : None pyreadstat : None pytest : None python-calamine : None pytz : 2025.2 pyxlsb : None s3fs : None scipy : None sqlalchemy : None tables : None tabulate : None xarray : None xlrd : None xlsxwriter : None zstandard : None qtpy : None pyqt5 : None
May I work on this
Index.union exhibits the same behavior:
>>> import pandas as pd
>>>
>>> index1 = pd.Index([0, 1])
>>> index2 = pd.Index([0, 1])
>>> index3 = index1.union(index2)
>>> index3 is index1
True
Just to add more examples to this issue, Index.intersection can still return a reference even when the dtypes do not match:
>>> import pandas as pd
>>>
>>> index1 = pd.Index([0, 1])
>>> index2 = pd.Index([0.0, 1.0])
>>> assert index1.dtype != index2.dtype
>>>
>>> index3 = index1.intersection(index2)
>>> index3 is index1
True
For this example, Index.union does return a new instance:
>>> index3 = index1.union(index2)
>>> index3 is index1
False
>>> index3 is index2
False
@deniskrds, do your proposed changes address this case as well?
Yes, the fix addresses this. As you observed, union already returns a new instance in this case, but intersection doesn't. The fix ensures both operations consistently return new Index instances (via shallow copy) rather than returning self. Since Index is immutable, sharing the underlying data is safe—what matters is you no longer get the same Python object. MultiIndex had the same issue, so the fix applies there as well. @warwickmm