16
16
17
17
from pandas .core .algorithms import take_1d
18
18
import pandas .compat as compat
19
+ from pandas .core import accessors
20
+
19
21
from pandas .core .accessors import AccessorProperty
20
22
from pandas .core .base import NoNewAttributesMixin
21
23
from pandas .util ._decorators import Appender
@@ -1437,7 +1439,11 @@ class StringMethods(NoNewAttributesMixin):
1437
1439
1438
1440
def __init__ (self , data ):
1439
1441
self ._is_categorical = is_categorical_dtype (data )
1440
- self ._data = data .cat .categories if self ._is_categorical else data
1442
+ if self ._is_categorical :
1443
+ self ._data = data .cat .categories
1444
+ else :
1445
+ self ._data = data
1446
+
1441
1447
# save orig to blow up categoricals to the right type
1442
1448
self ._orig = data
1443
1449
self ._freeze ()
@@ -1456,8 +1462,7 @@ def __iter__(self):
1456
1462
i += 1
1457
1463
g = self .get (i )
1458
1464
1459
- def _wrap_result (self , result , use_codes = True ,
1460
- name = None , expand = None ):
1465
+ def _wrap_result (self , result , use_codes = True , name = None , expand = None ):
1461
1466
1462
1467
from pandas .core .index import Index , MultiIndex
1463
1468
@@ -1475,7 +1480,7 @@ def _wrap_result(self, result, use_codes=True,
1475
1480
1476
1481
if expand is None :
1477
1482
# infer from ndim if expand is not specified
1478
- expand = False if result .ndim == 1 else True
1483
+ expand = result .ndim != 1
1479
1484
1480
1485
elif expand is True and not isinstance (self ._orig , Index ):
1481
1486
# required when expand=True is explicitly specified
@@ -1527,7 +1532,10 @@ def cons_row(x):
1527
1532
1528
1533
@copy_doc (str_cat )
1529
1534
def cat (self , others = None , sep = None , na_rep = None ):
1530
- data = self ._orig if self ._is_categorical else self ._data
1535
+ if self ._is_categorical :
1536
+ data = self ._orig
1537
+ else :
1538
+ data = self ._data
1531
1539
result = str_cat (data , others = others , sep = sep , na_rep = na_rep )
1532
1540
return self ._wrap_result (result , use_codes = (not self ._is_categorical ))
1533
1541
@@ -1739,7 +1747,10 @@ def wrap(self, width, **kwargs):
1739
1747
def get_dummies (self , sep = '|' ):
1740
1748
# we need to cast to Series of strings as only that has all
1741
1749
# methods available for making the dummies...
1742
- data = self ._orig .astype (str ) if self ._is_categorical else self ._data
1750
+ if self ._is_categorical :
1751
+ data = self ._orig .astype (str )
1752
+ else :
1753
+ data = self ._data
1743
1754
result , name = str_get_dummies (data , sep )
1744
1755
return self ._wrap_result (result , use_codes = (not self ._is_categorical ),
1745
1756
name = name , expand = True )
@@ -1900,18 +1911,14 @@ def rindex(self, sub, start=0, end=None):
1900
1911
docstring = _shared_docs ['ismethods' ] %
1901
1912
_shared_docs ['isdecimal' ])
1902
1913
1903
-
1904
- class StringAccessorMixin (object ):
1905
- """ Mixin to add a `.str` acessor to the class."""
1906
-
1907
- # string methods
1908
- def _make_str_accessor (self ):
1914
+ @classmethod
1915
+ def _make_accessor (cls , data ):
1909
1916
from pandas .core .index import Index
1910
1917
1911
- if (isinstance (self , ABCSeries ) and
1912
- not ((is_categorical_dtype (self .dtype ) and
1913
- is_object_dtype (self .values .categories )) or
1914
- (is_object_dtype (self .dtype )))):
1918
+ if (isinstance (data , ABCSeries ) and
1919
+ not ((is_categorical_dtype (data .dtype ) and
1920
+ is_object_dtype (data .values .categories )) or
1921
+ (is_object_dtype (data .dtype )))):
1915
1922
# it's neither a string series not a categorical series with
1916
1923
# strings inside the categories.
1917
1924
# this really should exclude all series with any non-string values
@@ -1920,23 +1927,34 @@ def _make_str_accessor(self):
1920
1927
raise AttributeError ("Can only use .str accessor with string "
1921
1928
"values, which use np.object_ dtype in "
1922
1929
"pandas" )
1923
- elif isinstance (self , Index ):
1930
+ elif isinstance (data , Index ):
1924
1931
# can't use ABCIndex to exclude non-str
1925
1932
1926
1933
# see scc/inferrence.pyx which can contain string values
1927
1934
allowed_types = ('string' , 'unicode' , 'mixed' , 'mixed-integer' )
1928
- if self .inferred_type not in allowed_types :
1935
+ if data .inferred_type not in allowed_types :
1929
1936
message = ("Can only use .str accessor with string values "
1930
1937
"(i.e. inferred_type is 'string', 'unicode' or "
1931
1938
"'mixed')" )
1932
1939
raise AttributeError (message )
1933
- if self .nlevels > 1 :
1940
+ if data .nlevels > 1 :
1934
1941
message = ("Can only use .str accessor with Index, not "
1935
1942
"MultiIndex" )
1936
1943
raise AttributeError (message )
1937
- return StringMethods (self )
1944
+ return StringAccessor (data )
1945
+
1946
+ StringAccessor = StringMethods # Alias to mirror CategoricalAccessor
1947
+
1948
+
1949
+ # TODO: This is only mixed in to Index (this PR takes it out of Series)
1950
+ # and the _dir_additions/_dir_deletions won't play nicely with
1951
+ # any other class this gets mixed into that *does* implement its own
1952
+ # _dir_additions/_dir_deletions. This should be deprecated.
1953
+ class StringAccessorMixin (object ):
1954
+ """ Mixin to add a `.str` acessor to the class."""
1955
+
1938
1956
1939
- str = AccessorProperty (StringMethods , _make_str_accessor )
1957
+ str = accessors . AccessorProperty (StringAccessor )
1940
1958
1941
1959
def _dir_additions (self ):
1942
1960
return set ()
0 commit comments