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

时间:2018-10-26 06:28:07

标签: python exception logging python-3.6

我正在调试调试模块,并且依靠try ... 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消息丢失了。

2 个答案:

答案 0 :(得分:1)

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

  

如果format需要单个参数,则值可能是单个非元组   宾语。 [5]否则,值必须是一个具有正确数字的元组   由格式字符串或单个映射对象指定的项   (例如,字典)。

注意[5]:

  

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

这说明仅当元组与格式字符串要求完全匹配时,才可接受该元组。具有一项本身不是元组的项的元组可能无法匹配任何格式字符串,并且总是引发异常。

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


就我错了的情况而言,您有可能会发现另一个“怪癖”。他们明确警告:

  

此处描述的格式化操作表现出各种怪癖   导致许多常见错误(例如无法显示)   元组和字典正确)。使用较新的格式化字符串   文字或str.format()接口有助于避免这些错误。

答案 1 :(得分:0)

作为解决此问题的方法,我提出了以下解决方案:

@include namespace(cool, '+', stuff) {
  color: green;
}

@include namespace(stuff, '~', things) {
  color: red;
}

@include namespace(stuff, '*:not(.lame)', things) {
  color: red;
}

哪个可以正常运行:

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)