代码之家  ›  专栏  ›  技术社区  ›  Evandro Coan

为什么'var'{1:'variable'}打印'var',而不是像'var'%(1,)那样引发异常TypeError?

  •  0
  • Evandro Coan  · 技术社区  · 7 年前

    我正在调试我的调试模块,我依靠一个尝试。。。catch检测TypeError并正确格式化日志,然后我注意到当传递字典时,Python不会引发传统的异常。

    >>> 'var' % {1: 'variable'}
    'var'
    >>> 'var' % (1,)
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    

    这是日志模块的一个最小示例:

    import logging
    
    class SmartLogRecord(logging.LogRecord):
    
        def _getMessage(self, remaining_arguments):
    
            try:
    
                if self.args:
                    remaining_arguments.append( self.msg % self.args )
    
                else:
                    remaining_arguments.append( self.msg )
    
                return False
    
            except TypeError as error:
                last = self.args[-1]
                self.args = self.args[:-1]
                remaining_arguments.append( str( last ) )
    
                if len( self.args ):
                    return True
    
                else:
                    remaining_arguments.append( self.msg )
                    return False
    
        def getMessage(self):
            """
            Return the message for this LogRecord.
    
            Return the message for this LogRecord after merging any user-supplied
            arguments with the message.
            """
            remaining_arguments = []
            self.msg = str( self.msg )
    
            while self._getMessage( remaining_arguments ): pass
            return " ".join( reversed( remaining_arguments ) )
    
    logging.setLogRecordFactory(SmartLogRecord)
    
    var = 'SmartLogRecord'
    logging.warning('I am a', var)
    
    dumb = {1: 'variable'}
    logging.warning('I am a', dumb)
    

    运行它你会得到:

    WARNING:root:I am a SmartLogRecord
    WARNING:root:I am a
    

    正如你所注意到的,最后 dumb 消息丢失。

    1 回复  |  直到 7 年前
        1
  •  1
  •   VPfB    7 年前

    我认为观察到的行为符合 docs

    如果格式需要单个参数,则值可以是单个非元组 对象[5] 否则,值必须是正好包含数字的元组 由格式字符串或单个映射对象指定的项

    注[5]:

    因此,要仅格式化一个元组,您应该提供一个单例元组 其唯一元素是要格式化的元组。

    它还解释了dict总是被接受为类型,但可能会产生其他错误。


    在我错的情况下,有一种普遍的可能性,你刚刚发现了另一个“怪癖”。他们明确警告:

    这里描述的格式化操作表现出各种各样的怪癖 这会导致一些常见错误(例如无法显示 元组和字典)。使用较新的格式化字符串

        2
  •  0
  •   Evandro Coan    7 年前

    import sys
    import logging
    
    if sys.version_info[0] < 3:
        is_python2 = True
        from collections import MutableMapping
    else:
        from collections.abc import MutableMapping
    
    class SmartLogRecord(logging.LogRecord):
    
        def _getMessage(self, remaining_arguments):
    
            try:
                args = self.args
    
                if args:
    
                    # if isinstance( args, dict ):
                    if isinstance( args, MutableMapping ):
                        new_msg = self.msg % args
    
                        if new_msg == self.msg:
                            remaining_arguments.append( str( args ) )
                            remaining_arguments.append( new_msg )
    
                        else:
                            remaining_arguments.append( new_msg )
    
                    else:
                        remaining_arguments.append( self.msg % args )
    
                else:
                    remaining_arguments.append( self.msg )
    
                return False
    
            except TypeError as error:
                self.args = args[:-1]
                remaining_arguments.append( str( args[-1] ) )
    
                if len( args ) - 1 > 0:
                    return True
    
                else:
                    remaining_arguments.append( self.msg )
                    return False
    
        def getMessage(self):
            """
            Return the message for this LogRecord.
    
            Return the message for this LogRecord after merging any user-supplied
            arguments with the message.
            """
            remaining_arguments = []
            self.msg = str( self.msg )
    
            while self._getMessage( remaining_arguments ): pass
            return " ".join( reversed( remaining_arguments ) )
    
    logging.setLogRecordFactory(SmartLogRecord)
    
    var = 'SmartLogRecord'
    logging.warning('I am a', var)
    
    dumb = {1: 'variable'}
    logging.warning('I am a', dumb)
    

    正确运行:

    WARNING:root:I am a SmartLogRecord
    WARNING:root:I am a {1: 'variable'}