|
| 1 | +--- |
| 2 | +related: |
| 3 | + - title: Introduction to ophyd |
| 4 | + url: learn/devices/introduction-to-ophyd.md |
| 5 | + - title: Change Config Signals from the BEC IPython Client |
| 6 | + url: how-to/devices/change-config-signals-from-the-bec-ipython-client.md |
| 7 | + - title: EPICS put completion |
| 8 | + url: learn/devices/epics-put-completion.md |
| 9 | +--- |
| 10 | + |
| 11 | +# `set()` vs `put()` in `ophyd` |
| 12 | + |
| 13 | +In ophyd, both `set()` and `put()` can write a new value to a writable signal, but they serve different purposes. |
| 14 | + |
| 15 | +The short version is: |
| 16 | + |
| 17 | +- use `put()` for a direct low-level write |
| 18 | +- use `set()` when you want a write operation with completion tracking |
| 19 | + |
| 20 | +That distinction matters in BEC because user-facing device operations often need clear completion semantics, while device-internal helper signals often just need to publish a new value immediately. |
| 21 | + |
| 22 | +## What `put()` does |
| 23 | + |
| 24 | +`put()` is the low-level write method on a signal. |
| 25 | + |
| 26 | +It sends a value to the signal and returns immediately. It does not return a `Status` object and is therefore not the right abstraction when the caller needs to wait for completion in a structured way. |
| 27 | + |
| 28 | +`put()` is a direct wrapper around the underlying control layer, i.e. in the case of pyepics (default for ophyd_devices), it is calling `epics.PV.put()`. |
| 29 | + |
| 30 | +Typical uses of `put()` include: |
| 31 | + |
| 32 | +- updating a soft signal inside device implementation code |
| 33 | +- writing trigger-like signals that should be pushed directly |
| 34 | +- direct signal writes where completion tracking is not needed or not meaningful |
| 35 | + |
| 36 | +Example: |
| 37 | + |
| 38 | +```python |
| 39 | +my_signal.put(5) |
| 40 | +``` |
| 41 | + |
| 42 | +## What `set()` does |
| 43 | + |
| 44 | +`set()` is the higher-level write method. |
| 45 | + |
| 46 | +It starts a write operation and returns a `Status` object that tells the caller when the operation is considered complete or has failed. This makes `set()` a better fit for coordinated device actions, plans, and user-facing control flows. |
| 47 | + |
| 48 | +Example: |
| 49 | + |
| 50 | +```python |
| 51 | +status = my_signal.set(5) |
| 52 | +status.wait() |
| 53 | +``` |
| 54 | + |
| 55 | +In other words, `set()` is not just about sending a value. It is about sending a value and giving the caller a standard way to observe completion. |
| 56 | +Under the hood, `set()` uses `put()` to perform the actual write, but it adds the completion tracking layer on top. |
| 57 | + |
| 58 | +## The practical difference |
| 59 | + |
| 60 | +The key difference is the API contract: |
| 61 | + |
| 62 | +<table> |
| 63 | + <colgroup> |
| 64 | + <col style="width: 20%;"> |
| 65 | + <col style="width: 80%;"> |
| 66 | + </colgroup> |
| 67 | + <thead> |
| 68 | + <tr> |
| 69 | + <th>Method</th> |
| 70 | + <th>Behavior</th> |
| 71 | + </tr> |
| 72 | + </thead> |
| 73 | + <tbody> |
| 74 | + <tr> |
| 75 | + <td style="white-space: nowrap;"><code>put()</code></td> |
| 76 | + <td>Perform a direct write. No <code>Status</code> object is returned.</td> |
| 77 | + </tr> |
| 78 | + <tr> |
| 79 | + <td style="white-space: nowrap;"><code>set()</code></td> |
| 80 | + <td>Perform a write operation with completion tracking and return a <code>Status</code>.</td> |
| 81 | + </tr> |
| 82 | + </tbody> |
| 83 | +</table> |
| 84 | + |
| 85 | +That means the choice is usually driven by what the caller needs: |
| 86 | + |
| 87 | +- If you only need to publish or write a value, `put()` is often enough. |
| 88 | +- If the caller needs to wait until the operation is done, use `set()`. |
| 89 | + |
| 90 | +## How `set()` decides it is done |
| 91 | + |
| 92 | +For a basic ophyd `Signal`, `set()` uses the lower-level write path and then waits until the signal readback reaches the target value within the configured tolerances. |
| 93 | + |
| 94 | +This is why `set()` is often described as a write-and-wait operation rather than just a write. |
| 95 | + |
| 96 | +For `EpicsSignal`, there is one extra detail worth knowing: `put_complete` changes how `set()` decides that the write has finished. That EPICS-specific behavior is covered separately in [EPICS put completion](../../learn/devices/epics-put-completion.md). |
| 97 | + |
| 98 | + |
| 99 | +## Choosing between them |
| 100 | + |
| 101 | +In practice, the choice is simple: |
| 102 | + |
| 103 | +- use `put()` when you only need to write a value |
| 104 | +- use `set()` when the caller needs a `Status` and clear completion semantics |
| 105 | + |
| 106 | +!!! info "What to remember" |
| 107 | + - `put()` is the low-level write method for directly updating a signal value. |
| 108 | + - `set()` is the higher-level write method that returns a `Status` so callers can wait for completion. |
| 109 | + - For a basic ophyd `Signal`, `set()` writes the value and waits until the readback reaches the target. |
| 110 | + - If you are working with `EpicsSignal`, `put_complete` adds EPICS-specific completion behavior for `set()`. |
0 commit comments