Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-07-27T12:30:38.383Z
Answers.Text: FYI https://pastebin.com/3QBnVsKU
Answers.UserDisplayName: Chris_Rands
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-07-27T08:52:49.947Z
Answers.LastActivityDate: 2018-07-27T08:52:49.947Z
Answers.UserDisplayName: bli
Body: <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>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-07-27T09:15:50.103Z
Comments.Text: 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?
Comments.UserDisplayName: Chris_Rands
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-07-27T09:18:38.447Z
Comments.Text: @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
Comments.UserDisplayName: bli
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-07-27T09:25:11.100Z
Comments.Text: 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
Comments.UserDisplayName: bli
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-07-27T09:30:38.520Z
Comments.Text: Or rather, this one: https://github.com/daler/pybedtools/blob/master/pybedtools/cbedtools.pyx#L256
Comments.UserDisplayName: bli
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-07-27T09:31:35.337Z
Comments.Text: 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)
Comments.UserDisplayName: Chris_Rands
Tags: <python><pybedtools>
Title: How to efficiently extract coordinates from a `pybedtools.Interval`?
ThreadText: # How to efficiently extract coordinates from a `pybedtools.Interval`?
  
  (Asked by: username_0 on 2018-07-27)
  
  I'm using [pybedtools](https://daler.github.io/pybedtools) to process data, and at some point, I loop over a `BedTool` object and use [*unpacking*](http://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/) 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 `Interval`s 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**: @username_1 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](https://daler.github.io/pybedtools/intervals.html#indexing-into-interval-objects) 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  
  
  ---
  
  