【问题标题】:where is the __enter__ and __exit__ defined for zipfile?为 zipfile 定义的 __enter__ 和 __exit__ 在哪里?
【发布时间】:2011-10-09 21:08:58
【问题描述】:

基于with statement

  • 加载上下文管理器的__exit__() 以供以后使用。
  • 上下文管理器的__enter__() 方法被调用。

我见过zipfile的其中一种用法

问题> 我已经检查了位于此处的 zipfile 的源代码:

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

不知道__enter____exit__函数是在哪里定义的?

谢谢

【问题讨论】:

    标签: python with-statement contextmanager


    【解决方案1】:

    zipfile.ZipFile 在 2.6 中不是上下文管理器,这已在 2.7 中添加。

    【讨论】:

    • 如果我必须坚持使用 Python 2.6 并以安全的方式使用 ZipFile,您有什么好的建议吗?
    • @q0987:使用contextlib.closing
    【解决方案2】:

    我已将此添加为另一个答案,因为它通常不是最初问题的答案。不过,它可以帮助您解决问题。

    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
    

    用法:

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

    如果你输入

    help(MyZipFile)
    

    您可以看到原始zipfile.ZipFile的所有方法以及您自己的方法:initenterexit。如果需要,您可以添加其他自己的功能。 祝你好运!

    【讨论】:

    • 您好 ghostmansd,非常感谢您的大力帮助。关于您的 MyZipFile 课程,我还有一个问题。我检查了与 Python 3.2 关联的 ZipFile,发现 init 的签名定义为__init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):。我们至少应该包含第一个参数 self 吗? -thx
    • 哦,对不起,我错过了。是的,您必须始终在 init 中包含 self 参数。正确地说,将 self 包含在任何函数的 args 中总是一个好主意,因为它可以让您访问类变量。
    • 不要忘记。您可以创建自己的类,它只使用您需要的方法。例如,您的 MyZipFile 类只能支持文件的提取,但不支持文件的导入。为此,您应该基于对象(而不是 zipfile.ZipFile 等)创建类并使用自变量。如果你愿意,我可以给你看。
    • 你好ghostmansd,如果我理解正确的话,你必须将'self'作为你的成员函数的第一个参数。 'self' 只是一种传统的命名方式,您可以将其命名为 selfself 无问题。因此,在您的类中,函数 init 必须将 self 作为其第一个参数。如果我在这里错了,请纠正我。
    • @ghostmansd:不,抱歉,self 不是 Python 中的保留名称。
    【解决方案3】:

    使用对象类创建类的示例:

    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()
    

    用法:

    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
    

    如果你运行'help(ZipExtractor)',你会看到五个方法:

    __init__, __enter__, __exit__, close, SuperExtract
    

    希望我对你有所帮助。我没有测试它,所以你可能需要改进它。

    【讨论】:

      【解决方案4】:

      cat-plus-plus 是对的。但是,如果您愿意,您可以编写自己的类来添加“错过”的功能。您需要做的就是在您的类中添加两个函数(基于 zipfile):

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

      这应该足够了,AFAIR。

      【讨论】:

      • 我是 Python 新手。能不能给个小细节。我应该继承 ZipFile 还是将其用作组件?
      • 我已经回答了你的问题。我为你做了一个简单的类并对其进行了注释,所以我想你会理解 Python 类的主要部分。
      • 请删除这个 - 只是增加你接受的答案中包含的噪音 - 让我知道,我会支持那个,这样你就不会失去任何声誉;)
      猜你喜欢
      • 2010-12-31
      • 1970-01-01
      • 2017-03-25
      • 2016-10-31
      • 2014-04-20
      • 2013-03-12
      • 1970-01-01
      • 2016-12-13
      相关资源
      最近更新 更多