# Idioms and Antipatterns

Here is a list of idioms and antipatterns in SymPy. You should use the former, and avoid the latter.

For most antipatterns, try to add an example of how it should be done instead.

## Idioms

### Rebuilding an expression

Rebuild an expression using `expr.func(*expr.args)`.

### Args invariants

When creating custom subclasses of `Basic` or `Expr`, make sure that it satisfies `expr == expr.func(*expr.args)`. Many very basic functions in SymPy rely on this idiom to modify an expression and rebuild it, such as `subs`.

### Subclassing

TODO: How to properly subclass Basic and Expr (and when to).

## Antipatterns

### Wild and match

When using `Wild`, be sure to use the `exclude` keyword to make the pattern deterministic.

Don't

```x, y = Symbols("x y")
a, b = Wild('a'), Wild('b')
(2*x + 3*y).match(a*x + b*y)```

Do

```x, y = Symbols("x y")
a, b = Wild('a', exclude=[x, y]), Wild('b', exclude=[x, y])
(2*x + 3*y).match(a*x + b*y)```

Reason

Without the exclude pattern, you may get matches that are technically correct, but not what you wanted. This is especially likely if the expression you are matching doesn't actually match your pattern. For example, using the above without `exclude`:

```>>> (2 + 3*y).match(a*x + b*y)
{a: 2/x, b: 3}```

This is technically correct, because `(2/x)*x + 3*y == 2 + 3*y`, but you probably wanted it to not match at all. The issue is that you really didn't want `a` and `b` to include `x` and `y`, and the `exclude` parameter lets you specify exactly this. With the `exclude` parameter, the above match gives `None`, meaning it did not match.

### Strings as input

Don't use strings as input to functions. Rather, create the objects symbolically using Symbols and the appropriate SymPy functions, and manipulate them.

Don't

```>>> simplify("(x**2 + x)/x")
x + 1```

Do

```>>> x = Symbol('x')
>>> simplify((x**2 + x)/x)
x + 1```

Reason

Support for string input is in many ways accidental. It only happens because functions call `sympify()` on their input to ensure that it is a SymPy object, and `sympify()` translates strings. Support for this may go away in a future version.

There are many disadvantages to using strings:

• They are not explicit. They make code much harder to read.

• `sympify()` automatically turns all undefined names into Symbols of Functions, so if you have a typo, the string will still parse correctly, but the output will not be what you expect. For example

```>>> expand_trig("sine(x + y)")
sine(x + y)```
``````>>> expand_trig(sine(x + y))
Traceback (most recent call last):
File "<ipython-input-41-a8617eceeca5>", line 1, in <module>
expand_trig(sine(x + y))
NameError: name 'sine' is not defined
>>> expand_trig(sin(x + y))
sin(x)*cos(y) + sin(y)*cos(x)
``````

In the first example, `sine`, a typo for `sin` is parsed into `Function("sine")`, and it appears that `expand_trig` cannot handle it. In the second case, we immediately get an error from the undefined name `sine`, and fixing our typo, we see that `expand_trig` can indeed do what we want.

• See also the section on `S('x')` in the "Creating Symbols" section below. Symbol names can contain any character, including things that aren't valid Python. But using strings as input will pass the string to `sympify`, even the argument to the function requires a Symbol. For example,
```>>> x = Symbol('2x')
>>> solve(x - 1, x)
[1]
>>> solve(x - 1, '2x')
Traceback (most recent call last):
File "<ipython-input-12-71e92ee34319>", line 1, in <module>
solve(Symbol('2d') - 1, '2d ')
File "/Users/aaronmeurer/Documents/Python/sympy/sympy/sympy/solvers/solvers.py", line 672, in solve
f, symbols = (_sympified_list(w) for w in [f, symbols])
File "/Users/aaronmeurer/Documents/Python/sympy/sympy/sympy/solvers/solvers.py", line 672, in <genexpr>
f, symbols = (_sympified_list(w) for w in [f, symbols])
File "/Users/aaronmeurer/Documents/Python/sympy/sympy/sympy/solvers/solvers.py", line 663, in _sympified_list
return map(sympify, w if iterable(w) else [w])
File "/Users/aaronmeurer/Documents/Python/sympy/sympy/sympy/core/sympify.py", line 297, in sympify
raise SympifyError('could not parse %r' % a, exc)
SympifyError: Sympify of expression 'could not parse u'2d'' failed, because of exception being raised:
SyntaxError: invalid syntax (<string>, line 1)```
• If you use strings, syntax errors won't be caught until the line is run. If you build up the expressions, syntax errors will be caught when Python compiles the script before any of it runs.

• In code editors that do syntax highlighting, strings will be highlighted all one color, whereas Python expressions will be highlighted according to their actual content.

• As mentioned, they are not officially supported or tested, and so may go away at any time.

### Creating Symbols

There are several ways to create Symbols:

1. `x = Symbol('x')`.
2. `x, y, z = map(Symbol, 'xyz')`
3. `var('x y z')`
4. `from sympy.abc import x, y, z`
5. `x = S('x') # or sympify('x')`
6. Using `isympy -a`
7. `x, y, z = symbols('x y z')`

There are also some variations on the above. For example, 7 can also be spelled `symbols('x,y,z')` or `symbols('x:z')`.

The recommended way to create Symbols is to use `symbols`, i.e., number 7. Some of the other methods are useful when working interactively, but should be avoided when writing more permanent code. Here is a discussion on each of the above:

1. `x = Symbol('x')`

This way is actually the next best way, and if you are only creating a single Symbol, it is fine. `Symbol` is the class of Symbol, so creating a Symbol this way calls the constructor directly. The primary disadvantage of this method is that it does not generalize easily to creating multiple Symbols. The one situation where this method is convenient is if you wish to create a Symbol with a character in the name that will be parsed by `symbols`, such as a space, `,`, or `:`. (To do this with `symbols` requires escaping the special characters.)

2. `x, y, z = map(Symbol, 'xyz')`

There is no reason to do this. Just use `symbols` instead. It is easier to read, and has nice syntax for things like numbered symbols (see below). Also, `map` works differently than `symbols` (if you put in space, you will get the wrong thing), and it is harder to create multicharacter Symbols with this method.

3. `var('x y z')`

`var` uses the exact same syntax as `symbols`. The difference is that `var` automatically injects Symbols into the namespace. Thus, it is sufficient to type just `var('x y z')` instead of `x, y, z = var('x y z')`. There are a few reasons this should be avoided in permanent places like scripts, libraries, and notebooks. First, it is harder to read, both by humans and by libraries that parse source code. Second, it uses `inspect.currentframe` to inject the symbols, which is not guaranteed to always work. For example, it may not behave as expected in certain nested scopes, or in alternate Python implementations from CPython.

4. `from sympy.abc import x, y, z`

This method is convenient, and should work fine. The biggest disadvantage to using `sympy.abc` is that it does not generalize to Symbol names that are not single letters. On the other hand, `symbols`, which is about as much typing, does. Also, SymPy defines some single-letter names such as `I` and `Q`, which would get overwritten by `from sympy.abc import I` or `from sympy.abc import *`.

5. `x = S('x')`

`sympify` will create Symbols, but this is just a side effect of its string parsing abilities (see also the previous section). The biggest issue here is that if you mistype something (or heaven forbid you use pass user-input through this), it will create that whole expression instead of the Symbol.

6. `isympy -a`

This is the easiest way to work interactively and not have to worry about defining Symbol names. With the `-a` option, `isympy` will automatically parse input for undefined names and convert them to Symbols. This requires IPython to work. The disadvantage here is that if you later wish to move something you wrote to a script, you will need to define all the Symbols. Another disadvantage is that if you mistype a function name, it will create a Symbol for it, instead of failing with NameError as usual. There are some other subtleties with this method. See the section on `-a` in `isympy --help` for more info.

7. `x, y, z = symbols('x y z')`

This is the best way to create Symbols. It works for single symbols (`x = symbols('x')`), but generalizes easily to multiple symbols. It has convenient syntax for creating multiple Symbols at once. For example, `symbols('x0:5')`, or just `symbols('x:5')` will create `x0, x1, x2, x3, x4`. `symbols('a:z')` will create a Symbol for every lowercase letter in the English alphabet. `symbols` also generalizes to other `Symbol`-like classes, like `Wild` or `Dummy` (or actually, any class that takes a string argument). Just use `x, y, z = symbols('x y z', cls=Dummy)`. See the docstring of `symbols` for more information on what this function can do.

In summary

Don't

Don't use `map(Symbols, 'xyz')` or `sympify` (2 or 5) to create Symbols.

Do

Do use `symbols` (number 7). If you are working strictly interactively, use `var` or `isympy -a` to avoid the hassle of creating symbols. `Symbol('x')` and `from sympy.abc import x` are OK, but are not as general as `symbols`.