Why doesn't the MySQLdb Connection context manager close the cursor?

前端 未结 1 595
长情又很酷
长情又很酷 2021-02-12 14:59

MySQLdb Connections have a rudimentary context manager that creates a cursor on enter, either rolls back or commits on exit, and implicitly doesn\

相关标签:
1条回答
  • 2021-02-12 16:00

    To answer your question directly: I cannot see any harm whatsoever in closing at the end of a with block. I cannot say why it is not done in this case. But, as there is a dearth of activity on this question, I had a search through the code history and will throw in a few thoughts (guesses) on why the close() may not be called:

    1. There is a small chance that spinning through calls to nextset() may throw an exception - possibly this had been observed and seen as undesirable. This may be why the newer version of cursors.py contains this structure in close():

      def close(self):
          """Close the cursor. No further queries will be possible."""
          if not self.connection:
              return
      
          self._flush()
          try:
              while self.nextset():
                  pass
          except:
              pass
          self.connection = None
      
    2. There is the (somewhat remote) potential that it might take some time to spin through all the remaining results doing nothing. Therefore close() may not be called to avoid doing some unnecessary iterations. Whether you think it's worth saving those clock cycles is subjective, I suppose, but you could argue along the lines of "if it's not necessary, don't do it".

    3. Browsing the sourceforge commits, the functionality was added to the trunk by this commit in 2007 and it appears that this section of connections.py has not changed since. That's a merge based on this commit, which has the message

      Add Python-2.5 support for with statement as described in http://docs.python.org/whatsnew/pep-343.html Please test

      And the code you quote has never changed since.

      This prompts my final thought - it's probably just a first attempt / prototype that just worked and therefore never got changed.


    More modern version

    You link to source for a legacy version of the connector. I note there is a more active fork of the same library here, which I link to in my comments about "newer version" in point 1.

    Note that the more recent version of this module has implemented __enter__() and __exit__() within cursor itself: see here. __exit__() here does call self.close() and perhaps this provides a more standard way to use the with syntax e.g.

    with conn.cursor() as c:
        #Do your thing with the cursor
    

    End notes

    N.B. I guess I should add, as far as I understand garbage collection (not an expert either) once there are no references to conn, it will be deallocated. At this point there will be no references to the cursor object and it will be deallocated too.

    However calling cursor.close() does not mean that it will be garbage collected. It simply burns through the results and set the connection to None. This means it can't be re-used, but it won't be garbage collected immediately. You can convince yourself of that by manually calling cursor.close() after your with block and then, say, printing some attribute of cursor


    N.B. 2 I think this is a somewhat unusual use of the with syntax as the conn object persists because it is already in the outer scope - unlike, say, the more common with open('filename') as f: where there are no objects hanging around with references after the end of the with block.

    0 讨论(0)
提交回复
热议问题