# Methods

Strings, lists, dictionaries, sets, and bytes values carry methods that you call with dot
notation, such as `"a,b".split(",")` or `items.append(3)`. This page lists every method with its
signature, behavior, and an example.

## Conventions

Methods accept positional arguments only, apart from `str.format`, which also takes keyword
arguments, and `dict.update`, which takes keyword arguments as new keys. A parameter followed by
`?` is optional, and `*others` accepts any number of arguments.

Methods that change a value (`append`, `update`, `pop`, and the like) fail on a frozen value with a
message such as `append: cannot append to frozen list`. Values loaded from another file, and values
shared with `steps.parallel` tasks, are frozen. See
[Execution Model](/automation/reference/execution-model#frozen-values). Changing a list or dictionary
while a `for` loop iterates over it also fails, for example
`append: cannot append to list during iteration`.

String and bytes methods always return new values, because strings and bytes are immutable.
Methods that change a list, dictionary, or set in place return `None`, except where they return a
removed or looked-up element, as `pop` does.

Where a signature shows a default, such as `default=None`, pass the argument by position.

Indexes in `start` and `end` parameters count bytes of the UTF-8 encoding, accept negative
values from the end of the string, and may be `None` to mean the default.

## String methods

- **`s.capitalize()`**
  Copy with the first character in title case and the rest in lowercase.
- **`s.codepoint_ords()`**
  Iterable of the Unicode code points of 
  `s`
   as integers.
- **`s.codepoints()`**
  Iterable of the characters of 
  `s`
  , one string per code point.
- **`s.count(sub, start?, end?)`**
  Number of non-overlapping occurrences of 
  `sub`
  .
- **`s.elem_ords()`**
  Iterable of the UTF-8 bytes of 
  `s`
   as integers.
- **`s.elems()`**
  Iterable of the UTF-8 bytes of 
  `s`
  , one single-byte string each.
- **`s.endswith(suffix, start?, end?)`**
  Whether 
  `s`
   ends with 
  `suffix`
  , a string or a tuple of strings.
- **`s.find(sub, start?, end?)`**
  Index of the first occurrence of 
  `sub`
  , or -1.
- **`s.format(*args, **kwargs)`**
  Substitute 
  `{}`
   replacement fields with the arguments.
- **`s.index(sub, start?, end?)`**
  Like 
  `find`
  , but fails when 
  `sub`
   is missing.
- **`s.isalnum()`**
  Whether 
  `s`
   is non-empty and every character is a letter or digit.
- **`s.isalpha()`**
  Whether 
  `s`
   is non-empty and every character is a letter.
- **`s.isdigit()`**
  Whether 
  `s`
   is non-empty and every character is a digit.
- **`s.islower()`**
  Whether 
  `s`
   has a cased character and no uppercase characters.
- **`s.isspace()`**
  Whether 
  `s`
   is non-empty and every character is whitespace.
- **`s.istitle()`**
  Whether each word starts with an uppercase character followed by lowercase ones.
- **`s.isupper()`**
  Whether 
  `s`
   has a cased character and no lowercase characters.
- **`s.join(iterable)`**
  Concatenate the strings of 
  `iterable`
  , separated by 
  `s`
  .
- **`s.lower()`**
  Copy converted to lowercase.
- **`s.lstrip(chars?)`**
  Copy without leading whitespace, or without leading characters in 
  `chars`
  .
- **`s.partition(sep)`**
  Split at the first 
  `sep`
   into a tuple of three strings.
- **`s.removeprefix(prefix)`**
  Copy without 
  `prefix`
   when 
  `s`
   starts with it.
- **`s.removesuffix(suffix)`**
  Copy without 
  `suffix`
   when 
  `s`
   ends with it.
- **`s.replace(old, new, count?)`**
  Copy with occurrences of 
  `old`
   replaced, at most 
  `count`
   of them.
- **`s.rfind(sub, start?, end?)`**
  Index of the last occurrence of 
  `sub`
  , or -1.
- **`s.rindex(sub, start?, end?)`**
  Like 
  `rfind`
  , but fails when 
  `sub`
   is missing.
- **`s.rpartition(sep)`**
  Split at the last 
  `sep`
   into a tuple of three strings.
- **`s.rsplit(sep?, maxsplit?)`**
  Split from the right into a list of strings.
- **`s.rstrip(chars?)`**
  Copy without trailing whitespace, or without trailing characters in 
  `chars`
  .
- **`s.split(sep?, maxsplit?)`**
  Split into a list of strings.
- **`s.splitlines(keepends?)`**
  Split at newlines into a list of lines.
- **`s.startswith(prefix, start?, end?)`**
  Whether 
  `s`
   starts with 
  `prefix`
  , a string or a tuple of strings.
- **`s.strip(chars?)`**
  Copy without leading and trailing whitespace, or characters in 
  `chars`
  .
- **`s.title()`**
  Copy with each word in title case.
- **`s.upper()`**
  Copy converted to uppercase.

The `codepoints`, `codepoint_ords`, `elems`, and `elem_ords` methods return an iterable value for
use in a `for` loop or a call to `list()`. Strings are not iterable themselves, so
`for c in "abc"` fails with `string value is not iterable`; write
`for c in "abc".codepoints()` instead.

The `strip` family treats `chars` as a set of characters to remove, not as a prefix or suffix.
Without `count`, `replace` replaces every occurrence. A `split` call without a separator, or with
`None`, splits on runs of whitespace and discards empty fields, while `split` with a separator
keeps empty fields. An empty separator fails. The `is...` methods return `False` for an empty
string.

### Case and character tests

```python
print("hello world".capitalize(), "HELLO".capitalize())  # Hello world Hello
print("hello world".title())                              # Hello World
print("ABC".lower(), "abc".upper())                       # abc ABC
print("abc1".isalnum(), "abc".isalpha(), "123".isdigit()) # True True True
print("abc".islower(), "ABC".isupper(), " \t".isspace())  # True True True
print("Hello World".istitle())                            # True
```

### Iterating characters and bytes

```python
print(list("héy".codepoints()))       # ["h", "é", "y"]
print(list("héy".codepoint_ords()))   # [104, 233, 121]
print(list("héy".elem_ords()))        # [104, 195, 169, 121]
print(list("ab".elems()))             # ["a", "b"]
```

### Searching

```python
print("banana".count("an"))                  # 2
print("banana".find("na"), "banana".find("z"))  # 2 -1
print("banana".index("na"))                  # 2
print("banana".rfind("a"), "banana".rindex("a"))  # 5 5
print("file.tf".startswith("file"))          # True
print("file.tf".startswith(("x", "f")))      # True
print("file.tf".endswith(".tf"))             # True
print("file.tf".endswith((".md", ".tf")))    # True
```

The `find` and `index` methods search `s[start:end]`, so `"banana".find("a", 2)` returns 3.

### Splitting and joining

```python
print("a b  c".split())                    # ["a", "b", "c"]
print("a,b,c".split(",", 1))               # ["a", "b,c"]
print("a,b,c".rsplit(",", 1))              # ["a,b", "c"]
print("a\nb\n".splitlines())               # ["a", "b"]
print("a\nb\n".splitlines(True))           # ["a\n", "b\n"]
print("a=b=c".partition("="))              # ("a", "=", "b=c")
print("a=b=c".rpartition("="))             # ("a=b", "=", "c")
print(",".join(["a", "b"]))                # a,b
```

The `partition` method returns `(s, "", "")` and `rpartition` returns `("", "", s)` when the separator is
missing.

### Trimming and replacing

```python
print("  x ".strip() + "|", "--x--".strip("-"))  # x| x
print("  x ".lstrip() + "|", "xxay".lstrip("x"))  # x | ay
print("|" + " x  ".rstrip(), "xayy".rstrip("y"))  # | x xa
print("v1.2".removeprefix("v"), "a.tf".removesuffix(".tf"))  # 1.2 a
print("aaa".replace("a", "b"), "aaa".replace("a", "b", 2))   # bbb bba
```

### Formatting

The `format` method replaces each `{}` with the next positional argument, `{0}` with a numbered argument, and
`{name}` with a keyword argument. The conversion `!r` uses the `repr()` form, and `{{` and `}}`
write literal braces. Format specifications such as `{:>5}` and attribute or index lookups such as
`{a.b}` are not supported. The `%` operator offers the conversions `%s`, `%d`, `%i`, `%r`, `%x`,
`%X`, `%o`, `%e`, `%f`, `%g`, `%c`, and `%%`, with `%(name)s` for dictionary lookups. It has no
width, precision, or padding modifiers.

```python
print("{} is {}".format("a", 1))   # a is 1
print("{name}!".format(name="n"))  # n!
print("{0}-{0}".format("z"))       # z-z
print("{!r}".format("q"))          # "q"
print("%s=%d" % ("n", 3))          # n=3
```

## List methods

- **`l.append(x)`**
  Add 
  `x`
   to the end of the list.
- **`l.clear()`**
  Remove every element.
- **`l.extend(iterable)`**
  Add every element of 
  `iterable`
   to the end.
- **`l.index(x, start?, end?)`**
  Index of the first element equal to 
  `x`
  ; fails when none is found.
- **`l.insert(i, x)`**
  Insert 
  `x`
   before index 
  `i`
  . Negative 
  `i`
   counts from the end; out-of-range values clamp to the ends.
- **`l.pop(i=-1)`**
  Remove and return the element at index 
  `i`
  , by default the last. Fails when 
  `i`
   is out of range.
- **`l.remove(x)`**
  Remove the first element equal to 
  `x`
  ; fails when none is found.

All list methods change the list in place. The methods `append`, `clear`, `extend`, `insert`, and `remove`
return `None`.

```python
items = [3, 1]
items.append(2)
print(items)                    # [3, 1, 2]
items.extend([9, 8])
print(items, items.index(9))    # [3, 1, 2, 9, 8] 3
items.insert(0, 7)
print(items)                    # [7, 3, 1, 2, 9, 8]
print(items.pop(), items.pop(0))  # 8 7
items.remove(1)
print(items)                    # [3, 2, 9]
items.clear()
print(items)                    # []
```

## Dictionary methods

- **`d.clear()`**
  Remove every entry.
- **`d.get(key, default=None)`**
  Value for 
  `key`
  , or 
  `default`
   when the key is missing.
- **`d.items()`**
  List of 
  `(key, value)`
   tuples in insertion order.
- **`d.keys()`**
  List of keys in insertion order.
- **`d.pop(key, default?)`**
  Remove 
  `key`
   and return its value. Without 
  `default`
  , a missing key fails.
- **`d.popitem()`**
  Remove and return the first 
  `(key, value)`
   entry. Fails on an empty dictionary.
- **`d.setdefault(key, default=None)`**
  Return the value for 
  `key`
  , first adding 
  `default`
   when the key is missing.
- **`d.update(pairs?, **kwargs)`**
  Add entries from a dictionary or an iterable of pairs, then from keyword arguments.
- **`d.values()`**
  List of values in insertion order.

Dictionaries keep insertion order. The methods `items`, `keys`, and `values` return new lists, so changing the
dictionary afterwards does not change them.

```python
config = {"a": 1, "b": 2}
print(config.get("a"), config.get("z"), config.get("z", 0))  # 1 None 0
print(config.items())              # [("a", 1), ("b", 2)]
print(config.keys(), config.values())  # ["a", "b"] [1, 2]
print(config.pop("a"), config.pop("zz", None))  # 1 None
config.update({"c": 3}, e=5)
print(config)                      # {"b": 2, "c": 3, "e": 5}
print(config.setdefault("f", 6))   # 6
print(config.popitem())            # ("b", 2)
config.clear()
print(config)                      # {}
```

## Set methods

- **`s.add(x)`**
  Add 
  `x`
   to the set.
- **`s.clear()`**
  Remove every element.
- **`s.difference(iterable)`**
  New set of the elements not in 
  `iterable`
  .
- **`s.discard(x)`**
  Remove 
  `x`
   if present. A missing element is not an error.
- **`s.intersection(iterable)`**
  New set of the elements also in 
  `iterable`
  .
- **`s.issubset(iterable)`**
  Whether every element of 
  `s`
   is in 
  `iterable`
  .
- **`s.issuperset(iterable)`**
  Whether every element of 
  `iterable`
   is in 
  `s`
  .
- **`s.pop()`**
  Remove and return the first element in insertion order. Fails on an empty set.
- **`s.remove(x)`**
  Remove 
  `x`
  ; fails when 
  `x`
   is missing.
- **`s.symmetric_difference(iterable)`**
  New set of the elements in exactly one of 
  `s`
   and 
  `iterable`
  .
- **`s.union(*others)`**
  New set of the elements of 
  `s`
   and of every iterable in 
  `others`
  .
- **`s.update(*others)`**
  Add every element of each iterable in 
  `others`
   to 
  `s`
  .

Sets hold hashable values, keep insertion order, and also support the operators `|`, `&`, `-`,
and `^` for union, intersection, difference, and symmetric difference. The methods that take an
`iterable` accept any iterable, not only a set.

```python
names = set([1, 2])
names.add(3)
print(names)                                  # set([1, 2, 3])
print(names.difference([1]))                  # set([2, 3])
print(names.intersection([2, 3, 4]))          # set([2, 3])
print(names.symmetric_difference([3, 4]))     # set([1, 2, 4])
print(names.union([5], [6]))                  # set([1, 2, 3, 5, 6])
print(names.issubset([1, 2, 3, 4]), names.issuperset([1]))  # True True
names.discard(9)
names.discard(1)
print(names)                                  # set([2, 3])
print(names.pop(), names)                     # 2 set([3])
names.remove(3)
names.update([7, 8], [9])
print(names)                                  # set([7, 8, 9])
names.clear()
print(names)                                  # set([])
```

## Bytes methods

- **`b.elems()`**
  Iterable of the bytes of 
  `b`
   as integers from 0 to 255.

```python
data = bytes("abc")
print(list(data.elems()))  # [97, 98, 99]
```

Bytes values also support `len`, indexing and slicing (which return `bytes` values), `+`, and
`in`. The `in` operator accepts an integer or a `bytes` value on its left. The `str()` function
decodes bytes as UTF-8. See [Data Types](/automation/reference/data-types) for the full list of
operations.

## Where to go next

For the universal functions such as `len`, `sorted`, and `enumerate`, see
[Built-in Functions](/automation/reference/builtin-functions). For how frozen values restrict
mutation, see [Execution Model](/automation/reference/execution-model#frozen-values).
