3

Based on the with statement

  • The context manager’s __exit__() is loaded for later use.
  • The context manager’s __enter__() method is invoked.

I have seen one of the with usage with zipfile

Question> I have checked the source code of zipfile located here:

/usr/lib/python2.6/zipfile.py

I don't know where the __enter__ and __exit__ functions are defined?

Thank you

Community
  • 1
  • 1
q0987
  • 34,938
  • 69
  • 242
  • 387

4 Answers4

9

zipfile.ZipFile is not a context manager in 2.6, this has been added in 2.7.

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
4

I've added this as another answer because it is generally not an answer to initial question. However, it can help to fix your problem.

class MyZipFile(zipfile.ZipFile): # Create class based on zipfile.ZipFile
  def __init__(file, mode='r'): # Initial part of our module
    zipfile.ZipFile.__init__(file, mode) # Create ZipFile object

  def __enter__(self): # On entering...
    return(self) # Return object created in __init__ part
  def __exit__(self, exc_type, exc_val, exc_tb): # On exiting...
    self.close() # Use close method of zipfile.ZipFile

Usage:

with MyZipFile('new.zip', 'w') as tempzip: # Use content manager of MyZipFile
  tempzip.write('sbdtools.py') # Write file to our archive

If you type

help(MyZipFile)

you can see all methods of original zipfile.ZipFile and your own methods: init, enter and exit. You can add another own functions if you want. Good luck!

ghostmansd
  • 3,285
  • 5
  • 30
  • 44
  • Hello ghostmansd, I really appreciate your great helps. I have one more question regarding your class MyZipFile. I have checked the ZipFile associated with Python 3.2 and find that the signature of __init__ is defined as `__init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):`. Should we as least include the first parameter self? -thx – q0987 Oct 10 '11 at 14:47
  • Oh, sorry, I missed it. Yes, you must always include self parameter to __init__. To say correctly, it's always good idea to include self to args of any function, because it will give you access to class variables. – ghostmansd Oct 10 '11 at 14:54
  • Not to forget. You can create your own class which uses only methods what you need. For example, your class MyZipFile can support only extracting of files, but no importing of files. To do it, you should create your class basing on object (not zipfile.ZipFile etc.) and use self-variables. If you want, I can show you. – ghostmansd Oct 10 '11 at 14:59
  • 1
    Hello ghostmansd, if I understood it right, you have to include 'self' as the first parameter of your member function. 'self' is just a conventional way to name it and you can name it as selfself w/o problems. So in your class, the function __init__ has to have the self as its first parameter. Correct me if I am wrong here. – q0987 Oct 10 '11 at 15:27
  • Hello ghostmands, I know the difference between inheritance and composite and understand how to implement them in C++ but not for python. it would be great if you can give me a little detail for that. – q0987 Oct 10 '11 at 15:29
  • You have understood correctly. It seems you understand Python faster than I understand C++... :-) I've answered your question about how to use object while making your class and tried to show how to use self variable. – ghostmansd Oct 10 '11 at 16:18
  • One error: name of self cannot be selfself etc. You must always use name "self", because it's reserved name. – ghostmansd Oct 10 '11 at 19:07
  • 1
    @ghostmansd: No, sorry, `self` is not a reserved name in Python. – martineau Dec 28 '11 at 00:24
2

Example of creating a class using object class:

class ZipExtractor(object): # Create class that can only extract zip files
  def __init__(self, path): # Initial part
    import zipfile # Import old zipfile
    self.Path = path # To make path available to all class
    try: open(self.Path, 'rb') # To check whether file exists
    except IOError: print('File doesn\'t exist') # Catch error and print it
    else: # If file can be opened
      with open(self.Path, 'rb') as temp:
        self.Header = temp.read(4) # Read first 4 bytes
        if self.Header != '\x50\x4B\x03\x04':
          print('Your file is not a zip archive!')
        else: self.ZipObject = zipfile.ZipFile(self.Path, 'r')

  def __enter__(self): # On entering...
    return(self) # Return object created in __init__ part
  def __exit__(self, exc_type, exc_val, exc_tb): # On exiting...
    self.close() # Use close method of our class

  def SuperExtract(member=None, path=None):
    '''Used to extract files from zip archive. If arg 'member'
    was not set, extract all files. If path was set, extract file(s)
    to selected folder.'''
    print('Extracting ZIP archive %s' % self.Path) # Print path of zip
    print('Archive has header %s' % self.Header) # Print header of zip
    if filename=None:
      self.ZipObject.extractall(path) # Extract all if member was not set
    else:
      self.ZipObject.extract(mamber, path) # Else extract selected file

  def close(self): # To close our file
    self.ZipObject.close()

Usage:

with ZipExtractor('/path/to/zip') as zfile:
  zfile.SuperExtract('file') # Extract file to current dir
  zfile.SuperExtract(None, path='/your/folder') # Extract all to selected dir

# another way
zfile = ZipExtractor('/path/to/zip')
zfile.SuperExtract('file')
zfile.close() # Don't forget that line to clear memory

If you run 'help(ZipExtractor)', you will see five methods:

__init__, __enter__, __exit__, close, SuperExtract

I hope I've helped you. I didn't test it, so you might have to improve it.

ghostmansd
  • 3,285
  • 5
  • 30
  • 44
0

cat-plus-plus is right. But if you want, you can write your own class to add "missed" features. All you need to do is to add two functions in your class (which is based on zipfile):

def __enter__(self):
  return(self)
def __exit__(self, exc_type, exc_val, exc_tb):
  self.close()

That should be enough, AFAIR.

ghostmansd
  • 3,285
  • 5
  • 30
  • 44
  • I am new to Python. Can you give a little detail. Should I subclass ZipFile or use it as a component? – q0987 Oct 09 '11 at 21:50
  • 1
    I've answered your question. I made a simple class for you and commented it, so I think you'll understand main part of Python's classes. – ghostmansd Oct 10 '11 at 12:52
  • Please delete this - just adds noise it is contained in your accepted answer - let me know and I will upvote that one so you won't lose any reputation ;) – Mr_and_Mrs_D Jun 24 '16 at 13:10