<p>The reason why unpacking an <code>Interval</code> results in strings instead of ints might be related to how <a href="https://daler.github.io/pybedtools/intervals.html#indexing-into-interval-objects" rel="nofollow noreferrer">indexing by position</a> works.</p>

<p>Even without considering the string/int issue, it seems slightly more efficient to access the interval's attributes rather than unpacking them directly:</p>

<pre><code>In [311]: %timeit [(chrom, start, end, strand) for (chrom, start, end, _, _, strand) in my_bedtool]
306 ms ± 26.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [312]: %timeit [(interval.chrom, interval.start, interval.end, interval.strand) for interval in my_bedtool]
238 ms ± 24.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
</code></pre>

<p>To resolve the ugliness issue, attribute access can be made more compact through the use of <code>operator.attrgetter</code>:</p>

<pre><code>In [313]: from operator import attrgetter

In [314]: get_interval_attrs = attrgetter("chrom", "start", "stop", "strand")

In [315]: %timeit [get_interval_attrs(interval) for interval in my_bedtool]
239 ms ± 26.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
</code></pre>

CC BY-SA 4.0
2018-07-27T12:30:38.383Z
FYI https://pastebin.com/3QBnVsKU
Chris_Rands
CC BY-SA 4.0
2018-07-27T08:52:49.947Z
2018-07-27T08:52:49.947Z
bli
<p>I'm using <a href="https://daler.github.io/pybedtools" rel="nofollow noreferrer">pybedtools</a> to process data, and at some point, I loop over a <code>BedTool</code> object and use <a href="http://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/" rel="nofollow noreferrer"><em>unpacking</em></a> to extract coordinates from the <code>Interval</code>:</p>

<pre><code>for interval in my_bedtool:
    (chrom, start, end, _, _, strand) = interval
</code></pre>

<p>Suppose I want to compute the interval length, as follows:</p>

<pre><code>    length = end - start
</code></pre>

<p>This results in a <code>TypeError: unsupported operand type(s) for -: 'str' and 'str'</code>.</p>

<p>It happens that the unpacked <code>end</code> and <code>start</code> variables are strings.
Converting them to ints is probably suboptimal given that <code>Interval</code>s can be created by providing ints for the coordinates:</p>

<pre><code>from pybedtool import Interval
interval = Interval("X", 0, 100, strand="+")
</code></pre>

<p>The <code>start</code> and <code>end</code> attributes of an <code>Interval</code> are ints.</p>

<p>I could do:</p>

<pre><code>    (chrom, start, end, strand) = (
        interval.chrom, interval.start, interval.end, interval.strand)
</code></pre>

<p>But I think this looks a bit ugly.</p>

<p>Is there a better approach?</p>

CC BY-SA 4.0
2018-07-27T09:15:50.103Z
i do not know `pybedtools` but `list(Interval("X", 0, 100, strand="+"))` >>> `['X', '0', '100', '.', '.', '+']`- shouldn't the conversion of integers to strings be considered a bug?
Chris_Rands
CC BY-SA 4.0
2018-07-27T09:18:38.447Z
@Chris_Rands I was indeed surprised by this behaviour. As I say in my answer, I guess it might be related to how indexing works. It seems to rely on a string representation of the genomic interval: https://daler.github.io/pybedtools/intervals.html#indexing-into-interval-objects
bli
CC BY-SA 4.0
2018-07-27T09:25:11.100Z
I'm not sure, but the explanation of the behaviour could be found around these lines: https://github.com/daler/pybedtools/blob/master/pybedtools/cbedtools.pyx#L512
bli
CC BY-SA 4.0
2018-07-27T09:30:38.520Z
Or rather, this one: https://github.com/daler/pybedtools/blob/master/pybedtools/cbedtools.pyx#L256
bli
CC BY-SA 4.0
2018-07-27T09:31:35.337Z
Yes exactly, I was peaking at the same source code myself; so it's a design decision not a bug i guess, still seems odd to me (my guess is that keeping a homogenous list in terms of types might allow some performance benefits for cython)
Chris_Rands
<python><pybedtools>
How to efficiently extract coordinates from a `pybedtools.Interval`?
# How to efficiently extract coordinates from a `pybedtools.Interval`?

(Asked by: username_0 on 2018-07-27)

I'm using pybedtools to process data, and at some point, I loop over a BedTool object and use unpacking to extract coordinates from the Interval:
for interval in my_bedtool:
    (chrom, start, end, _, _, strand) = interval

Suppose I want to compute the interval length, as follows:
    length = end - start

This results in a TypeError: unsupported operand type(s) for -: 'str' and 'str'.
It happens that the unpacked end and start variables are strings.
Converting them to ints is probably suboptimal given that Intervals can be created by providing ints for the coordinates:
from pybedtool import Interval
interval = Interval("X", 0, 100, strand="+")

The start and end attributes of an Interval are ints.
I could do:
    (chrom, start, end, strand) = (
        interval.chrom, interval.start, interval.end, interval.strand)

But I think this looks a bit ugly.
Is there a better approach?

**Tags:** python, pybedtools
> **Comments:**
> **username_1**: i do not know `pybedtools` but `list(Interval("X", 0, 100, strand="+"))` >>> `['X', '0', '100', '.', '.', '+']`- shouldn't the conversion of integers to strings be considered a bug?  
> **username_0**: @Chris_Rands I was indeed surprised by this behaviour. As I say in my answer, I guess it might be related to how indexing works. It seems to rely on a string representation of the genomic interval: https://daler.github.io/pybedtools/intervals.html#indexing-into-interval-objects  
> **username_0**: I'm not sure, but the explanation of the behaviour could be found around these lines: https://github.com/daler/pybedtools/blob/master/pybedtools/cbedtools.pyx#L512  
> **username_0**: Or rather, this one: https://github.com/daler/pybedtools/blob/master/pybedtools/cbedtools.pyx#L256  
> **username_1**: Yes exactly, I was peaking at the same source code myself; so it's a design decision not a bug i guess, still seems odd to me (my guess is that keeping a homogenous list in terms of types might allow some performance benefits for cython)  

---

## 1 answers

### Answer by username_0 on 2018-07-27. Score: 2 | Accepted answer

The reason why unpacking an Interval results in strings instead of ints might be related to how indexing by position works.
Even without considering the string/int issue, it seems slightly more efficient to access the interval's attributes rather than unpacking them directly:
In [311]: %timeit [(chrom, start, end, strand) for (chrom, start, end, _, _, strand) in my_bedtool]
306 ms ± 26.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [312]: %timeit [(interval.chrom, interval.start, interval.end, interval.strand) for interval in my_bedtool]
238 ms ± 24.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

To resolve the ugliness issue, attribute access can be made more compact through the use of operator.attrgetter:
In [313]: from operator import attrgetter

In [314]: get_interval_attrs = attrgetter("chrom", "start", "stop", "strand")

In [315]: %timeit [get_interval_attrs(interval) for interval in my_bedtool]
239 ms ± 26.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

> **Comments:**
> **username_1**: FYI https://pastebin.com/3QBnVsKU  

---

