[tor-commits] [stem/master] Explaining python's 'with' keyword

atagar at torproject.org atagar at torproject.org
Thu Aug 29 17:15:18 UTC 2013


commit a7ec700c1b366b5cd96ba894916ad0a6e6fa0b4c
Author: Damian Johnson <atagar at torproject.org>
Date:   Thu Aug 29 10:13:48 2013 -0700

    Explaining python's 'with' keyword
    
    We've had a couple stem newcomers that saw the 'with' keyword in our examples
    then misused it in their scripts. Adding a little tutorial on the keyword and
    the common mistake they've been making.
---
 docs/faq.rst                                   |   62 ++++++++++++++++++++++++
 docs/tutorials/the_little_relay_that_could.rst |    4 +-
 2 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/docs/faq.rst b/docs/faq.rst
index f1edeee..76e7c91 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -14,6 +14,7 @@ Frequently Asked Questions
  * :ref:`how_do_i_request_a_new_identity_from_tor`
  * :ref:`how_do_i_get_information_about_my_exits`
  * :ref:`how_do_i_reload_my_torrc`
+ * :ref:`what_is_that_with_keyword_i_keep_seeing_in_the_tutorials`
 
 * **Development**
 
@@ -180,6 +181,67 @@ Tor is configured through its `torrc <https://www.torproject.org/docs/faq.html.e
     controller.authenticate()
     controller.signal(Signal.SIGHUP)
 
+.. _what_is_that_with_keyword_i_keep_seeing_in_the_tutorials:
+
+What is that 'with' keyword I keep seeing in the tutorials?
+-----------------------------------------------------------
+
+Python's '**with**' keyword is shorthand for a try/finally block. With a :class:`~stem.control.Controller` the following...
+
+::
+
+  with Controller.from_port(port = 9051) as controller:
+    # do my stuff
+
+... is equivialnt to...
+
+::
+
+  controller = Controller.from_port(port = 9051)
+
+  try:
+    # do my stuff
+  finally:
+    controller.close()
+
+This helps to make sure that regardless of if your code raises an exception or not the control connection will be cleaned up afterward. Note that this means that if you leave the 'with' scope your :class:`~stem.control.Controller` will be closed. For instance...
+
+::
+
+  class BandwidthReporter(object):
+    def __init__(self, controller):
+      self.controller = controller
+
+    def print_bandwidth(self):
+      bytes_read = self.controller.get_info("traffic/read")
+      bytes_written = self.controller.get_info("traffic/written")
+
+      print "My Tor relay has read %s bytes and written %s." % (bytes_read, bytes_written)
+
+  if __name__ == '__main__':
+    with Controller.from_port(port = 9051) as controller:
+      reporter = BandwidthReporter(controller)
+
+    # The following line is broken because the 'controller' we initialised
+    # above was disconnected once we left the 'with' scope.
+
+    reporter.print_bandwidth()
+
+To fix this we could either move the print_bandwidth() call into the 'with' scope, or simply avoid using 'with' all together...
+
+::
+
+  if __name__ == '__main__':
+    controller = Controller.from_port(port = 9051)
+
+    try:
+      reporter = BandwidthReporter(controller)
+      reporter.print_bandwidth()
+    finally:
+      controller.close()
+
+For more information about the 'with' keyword see `here <http://effbot.org/zone/python-with-statement.htm>`_.
+
 Development
 ===========
 
diff --git a/docs/tutorials/the_little_relay_that_could.rst b/docs/tutorials/the_little_relay_that_could.rst
index 74fbe46..c30ae55 100644
--- a/docs/tutorials/the_little_relay_that_could.rst
+++ b/docs/tutorials/the_little_relay_that_could.rst
@@ -42,7 +42,9 @@ the following configuration options...
 
 When you change your torrc you'll need to either restart Tor is issue a SIGHUP
 for the new settings to take effect. Now let's write a script that tells us how
-many bytes Tor has sent and received since it started...
+many bytes Tor has sent and received since it started. If you're unfamiliar
+with the '**with**' keyword then see `here
+<../faq.html#what-is-that-with-keyword-i-keep-seeing-in-the-tutorials>`_...
 
 ::
 



More information about the tor-commits mailing list