36
36
Shape ,
37
37
final ,
38
38
)
39
+ from pandas .util ._decorators import cache_readonly
39
40
from pandas .util ._validators import validate_bool_kwarg
40
41
41
42
from pandas .core .dtypes .cast import (
@@ -165,7 +166,7 @@ class Block(libinternals.Block, PandasObject):
165
166
_validate_ndim = True
166
167
167
168
@final
168
- @property
169
+ @cache_readonly
169
170
def _consolidate_key (self ):
170
171
return self ._can_consolidate , self .dtype .name
171
172
@@ -188,7 +189,7 @@ def _can_hold_na(self) -> bool:
188
189
return values ._can_hold_na
189
190
190
191
@final
191
- @property
192
+ @cache_readonly
192
193
def is_categorical (self ) -> bool :
193
194
warnings .warn (
194
195
"Block.is_categorical is deprecated and will be removed in a "
@@ -217,6 +218,7 @@ def internal_values(self):
217
218
"""
218
219
return self .values
219
220
221
+ @property
220
222
def array_values (self ) -> ExtensionArray :
221
223
"""
222
224
The array that Series.array returns. Always an ExtensionArray.
@@ -245,7 +247,7 @@ def get_block_values_for_json(self) -> np.ndarray:
245
247
return np .asarray (self .values ).reshape (self .shape )
246
248
247
249
@final
248
- @property
250
+ @cache_readonly
249
251
def fill_value (self ):
250
252
# Used in reindex_indexer
251
253
return na_value_for_dtype (self .dtype , compat = False )
@@ -353,7 +355,7 @@ def shape(self) -> Shape:
353
355
return self .values .shape
354
356
355
357
@final
356
- @property
358
+ @cache_readonly
357
359
def dtype (self ) -> DtypeObj :
358
360
return self .values .dtype
359
361
@@ -378,6 +380,11 @@ def delete(self, loc) -> None:
378
380
"""
379
381
self .values = np .delete (self .values , loc , 0 )
380
382
self .mgr_locs = self ._mgr_locs .delete (loc )
383
+ try :
384
+ self ._cache .clear ()
385
+ except AttributeError :
386
+ # _cache not yet initialized
387
+ pass
381
388
382
389
@final
383
390
def apply (self , func , ** kwargs ) -> List [Block ]:
@@ -592,7 +599,7 @@ def astype(self, dtype, copy: bool = False, errors: str = "raise"):
592
599
"""
593
600
values = self .values
594
601
if values .dtype .kind in ["m" , "M" ]:
595
- values = self .array_values ()
602
+ values = self .array_values
596
603
597
604
new_values = astype_array_safe (values , dtype , copy = copy , errors = errors )
598
605
@@ -931,7 +938,7 @@ def setitem(self, indexer, value):
931
938
return self .coerce_to_target_dtype (value ).setitem (indexer , value )
932
939
933
940
if self .dtype .kind in ["m" , "M" ]:
934
- arr = self .array_values () .T
941
+ arr = self .array_values .T
935
942
arr [indexer ] = value
936
943
return self
937
944
@@ -1445,7 +1452,7 @@ class ExtensionBlock(Block):
1445
1452
1446
1453
values : ExtensionArray
1447
1454
1448
- @property
1455
+ @cache_readonly
1449
1456
def shape (self ) -> Shape :
1450
1457
# TODO(EA2D): override unnecessary with 2D EAs
1451
1458
if self .ndim == 1 :
@@ -1476,6 +1483,12 @@ def set_inplace(self, locs, values):
1476
1483
# see GH#33457
1477
1484
assert locs .tolist () == [0 ]
1478
1485
self .values = values
1486
+ try :
1487
+ # TODO(GH33457) this can be removed
1488
+ self ._cache .clear ()
1489
+ except AttributeError :
1490
+ # _cache not yet initialized
1491
+ pass
1479
1492
1480
1493
def putmask (self , mask , new ) -> List [Block ]:
1481
1494
"""
@@ -1500,7 +1513,7 @@ def is_view(self) -> bool:
1500
1513
"""Extension arrays are never treated as views."""
1501
1514
return False
1502
1515
1503
- @property
1516
+ @cache_readonly
1504
1517
def is_numeric (self ):
1505
1518
return self .values .dtype ._is_numeric
1506
1519
@@ -1549,6 +1562,7 @@ def get_values(self, dtype: Optional[DtypeObj] = None) -> np.ndarray:
1549
1562
# TODO(EA2D): reshape not needed with 2D EAs
1550
1563
return np .asarray (self .values ).reshape (self .shape )
1551
1564
1565
+ @cache_readonly
1552
1566
def array_values (self ) -> ExtensionArray :
1553
1567
return self .values
1554
1568
@@ -1675,10 +1689,7 @@ def where(self, other, cond, errors="raise") -> List[Block]:
1675
1689
# The default `other` for Series / Frame is np.nan
1676
1690
# we want to replace that with the correct NA value
1677
1691
# for the type
1678
-
1679
- # error: Item "dtype[Any]" of "Union[dtype[Any], ExtensionDtype]" has no
1680
- # attribute "na_value"
1681
- other = self .dtype .na_value # type: ignore[union-attr]
1692
+ other = self .dtype .na_value
1682
1693
1683
1694
if is_sparse (self .values ):
1684
1695
# TODO(SparseArray.__setitem__): remove this if condition
@@ -1739,10 +1750,11 @@ class HybridMixin:
1739
1750
array_values : Callable
1740
1751
1741
1752
def _can_hold_element (self , element : Any ) -> bool :
1742
- values = self .array_values ()
1753
+ values = self .array_values
1743
1754
1744
1755
try :
1745
- values ._validate_setitem_value (element )
1756
+ # error: "Callable[..., Any]" has no attribute "_validate_setitem_value"
1757
+ values ._validate_setitem_value (element ) # type: ignore[attr-defined]
1746
1758
return True
1747
1759
except (ValueError , TypeError ):
1748
1760
return False
@@ -1768,9 +1780,7 @@ def _can_hold_element(self, element: Any) -> bool:
1768
1780
if isinstance (element , (IntegerArray , FloatingArray )):
1769
1781
if element ._mask .any ():
1770
1782
return False
1771
- # error: Argument 1 to "can_hold_element" has incompatible type
1772
- # "Union[dtype[Any], ExtensionDtype]"; expected "dtype[Any]"
1773
- return can_hold_element (self .dtype , element ) # type: ignore[arg-type]
1783
+ return can_hold_element (self .dtype , element )
1774
1784
1775
1785
1776
1786
class NDArrayBackedExtensionBlock (HybridMixin , Block ):
@@ -1780,23 +1790,25 @@ class NDArrayBackedExtensionBlock(HybridMixin, Block):
1780
1790
1781
1791
def internal_values (self ):
1782
1792
# Override to return DatetimeArray and TimedeltaArray
1783
- return self .array_values ()
1793
+ return self .array_values
1784
1794
1785
1795
def get_values (self , dtype : Optional [DtypeObj ] = None ) -> np .ndarray :
1786
1796
"""
1787
1797
return object dtype as boxed values, such as Timestamps/Timedelta
1788
1798
"""
1789
- values = self .array_values ()
1799
+ values = self .array_values
1790
1800
if is_object_dtype (dtype ):
1791
1801
# DTA/TDA constructor and astype can handle 2D
1792
- values = values .astype (object )
1802
+ # error: "Callable[..., Any]" has no attribute "astype"
1803
+ values = values .astype (object ) # type: ignore[attr-defined]
1793
1804
# TODO(EA2D): reshape not needed with 2D EAs
1794
1805
return np .asarray (values ).reshape (self .shape )
1795
1806
1796
1807
def iget (self , key ):
1797
1808
# GH#31649 we need to wrap scalars in Timestamp/Timedelta
1798
1809
# TODO(EA2D): this can be removed if we ever have 2D EA
1799
- return self .array_values ().reshape (self .shape )[key ]
1810
+ # error: "Callable[..., Any]" has no attribute "reshape"
1811
+ return self .array_values .reshape (self .shape )[key ] # type: ignore[attr-defined]
1800
1812
1801
1813
def putmask (self , mask , new ) -> List [Block ]:
1802
1814
mask = extract_bool_array (mask )
@@ -1805,14 +1817,16 @@ def putmask(self, mask, new) -> List[Block]:
1805
1817
return self .astype (object ).putmask (mask , new )
1806
1818
1807
1819
# TODO(EA2D): reshape unnecessary with 2D EAs
1808
- arr = self .array_values ().reshape (self .shape )
1820
+ # error: "Callable[..., Any]" has no attribute "reshape"
1821
+ arr = self .array_values .reshape (self .shape ) # type: ignore[attr-defined]
1809
1822
arr = cast ("NDArrayBackedExtensionArray" , arr )
1810
1823
arr .T .putmask (mask , new )
1811
1824
return [self ]
1812
1825
1813
1826
def where (self , other , cond , errors = "raise" ) -> List [Block ]:
1814
1827
# TODO(EA2D): reshape unnecessary with 2D EAs
1815
- arr = self .array_values ().reshape (self .shape )
1828
+ # error: "Callable[..., Any]" has no attribute "reshape"
1829
+ arr = self .array_values .reshape (self .shape ) # type: ignore[attr-defined]
1816
1830
1817
1831
cond = extract_bool_array (cond )
1818
1832
@@ -1848,15 +1862,17 @@ def diff(self, n: int, axis: int = 0) -> List[Block]:
1848
1862
by apply.
1849
1863
"""
1850
1864
# TODO(EA2D): reshape not necessary with 2D EAs
1851
- values = self .array_values ().reshape (self .shape )
1865
+ # error: "Callable[..., Any]" has no attribute "reshape"
1866
+ values = self .array_values .reshape (self .shape ) # type: ignore[attr-defined]
1852
1867
1853
1868
new_values = values - values .shift (n , axis = axis )
1854
1869
new_values = maybe_coerce_values (new_values )
1855
1870
return [self .make_block (new_values )]
1856
1871
1857
1872
def shift (self , periods : int , axis : int = 0 , fill_value : Any = None ) -> List [Block ]:
1858
- # TODO(EA2D) this is unnecessary if these blocks are backed by 2D EAs
1859
- values = self .array_values ().reshape (self .shape )
1873
+ # TODO(EA2D) this is unnecessary if these blocks are backed by 2D EA
1874
+ # error: "Callable[..., Any]" has no attribute "reshape"
1875
+ values = self .array_values .reshape (self .shape ) # type: ignore[attr-defined]
1860
1876
new_values = values .shift (periods , fill_value = fill_value , axis = axis )
1861
1877
new_values = maybe_coerce_values (new_values )
1862
1878
return [self .make_block_same_class (new_values )]
@@ -1871,9 +1887,13 @@ def fillna(
1871
1887
# TODO: don't special-case td64
1872
1888
return self .astype (object ).fillna (value , limit , inplace , downcast )
1873
1889
1874
- values = self .array_values ()
1875
- values = values if inplace else values .copy ()
1876
- new_values = values .fillna (value = value , limit = limit )
1890
+ values = self .array_values
1891
+ # error: "Callable[..., Any]" has no attribute "copy"
1892
+ values = values if inplace else values .copy () # type: ignore[attr-defined]
1893
+ # error: "Callable[..., Any]" has no attribute "fillna"
1894
+ new_values = values .fillna ( # type: ignore[attr-defined]
1895
+ value = value , limit = limit
1896
+ )
1877
1897
new_values = maybe_coerce_values (new_values )
1878
1898
return [self .make_block_same_class (values = new_values )]
1879
1899
@@ -1883,6 +1903,7 @@ class DatetimeLikeBlockMixin(NDArrayBackedExtensionBlock):
1883
1903
1884
1904
is_numeric = False
1885
1905
1906
+ @cache_readonly
1886
1907
def array_values (self ):
1887
1908
return ensure_wrapped_if_datetimelike (self .values )
1888
1909
0 commit comments