pola-rs/polars · error · TypeError
unsupported operand type(s) for op: ('Expr' - 'Selector')
Error message
unsupported operand type(s) for op: ('Expr' - 'Selector') What it means
Selector.__rsub__ always raises: `something - selector` where the left operand is not itself a selector (a scalar, numpy array, etc.) is rejected instead of being guessed as either set-difference or arithmetic subtraction with reflected operands.
Source
Thrown at py-polars/src/polars/selectors.py:524
return self.as_expr().__ror__(other)
@overload
def __sub__(self, other: Selector) -> Selector: ...
@overload
def __sub__(self, other: Any) -> Expr: ...
def __sub__(self, other: Any) -> Selector | Expr:
if is_selector(other):
return Selector._from_pyselector(
PySelector.difference(self._pyselector, other._pyselector)
)
else:
return self.as_expr().__sub__(other)
def __rsub__(self, other: Any) -> NoReturn:
msg = "unsupported operand type(s) for op: ('Expr' - 'Selector')"
raise TypeError(msg)
@overload
def __xor__(self, other: Selector) -> Selector: ...
@overload
def __xor__(self, other: Any) -> Expr: ...
def __xor__(self, other: Any) -> Selector | Expr:
if is_column(other): # @2.0: remove
other = by_name(other.meta.output_name())
if is_selector(other):
return Selector._from_pyselector(
PySelector.exclusive_or(self._pyselector, other._pyselector)
)
else:
return self.as_expr().__xor__(other)
def __rxor__(self, other: Any) -> Expr:View on GitHub (pinned to df599052da)
Solutions
- Move the selector to the left for ARITHMETIC subtraction: cs.numeric() - 1 (Selector.__sub__ with a non-selector does expression arithmetic)
- For constant-minus-column, convert the selector first: pl.lit(1) - cs.numeric().as_expr()
- For set difference keep the selector left: cs.all() - cs.by_name('id')
- Select the columns first, then operate on them in a subsequent step
Example fix
# before
df.select(1 - cs.numeric())
# after
df.select(pl.lit(1) - cs.numeric().as_expr())
# arithmetic with selector on the left also works:
df.select((cs.numeric() - 1).name.suffix('_dec')) Defensive patterns
Strategy: type-guard
Validate before calling
from polars.selectors import is_selector
if is_selector(right) and not is_selector(left):
expr = pl.lit(left) - right.as_expr() # never rely on `left - selector` Type guard
from polars.selectors import is_selector
def safe_sub(left, right):
if is_selector(right):
return right.as_expr().__rsub__(left)
return left - right Prevention
- Keep selectors on the LEFT of arithmetic; they only support forward ops
- Use .as_expr() to drop into normal expression algebra when reflection is needed
When it happens
Trigger: 1 - cs.numeric() in select/with_columns; np_array - cs.all(); any expression where a Selector ends up on the right side of a minus with a non-selector left operand.
Common situations: Writing constant-minus-column expressions (deltas, inversions) with the selector on the right; vectorized numpy-style code pasted into polars expressions.
Related errors
- unsupported operand type(s) for op: ('Selector' + 'Selector'
- expected a selector; found {selector!r} instead.
- expected one or more `str`, `DataType` or selector; found {i
- cannot parse input {input_type} into Polars selector{input_d
- `new` argument is required if `old` argument is not a Mappin
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/eaa91dffd7062e31.
Report an issue: GitHub.