在类定义尚未完成时,Python不允许我在类中使用方法

Ham*_*jan 2 python oop methods class python-2.6

我使用Python 2.6作为批处理脚本替换.它将通过双击启动,因此用户将丢失/忽略对stdout的所有输出.所以,我决定添加日志记录,为了简单起见,我为此写了一个类.我的想法是,我可以Logging.Logger在我的代码中的任何地方使用,并且记录器将准备就绪.

我希望目录中的日志文件不超过10个,因此我手动清除旧的日志文件.我没有通过API找到这样的功能,而且我是偏执狂,并希望记录所有内容,事件是日志目录中有文件具有意外名称的事实.

所以,下面是我尝试这样的类,但是当我尝试测试(运行)它时出现错误:

>>> ================================ RESTART ================================
>>> 

Traceback (most recent call last):
  File "C:/AutomationScripts/build scripts/Deleteme.py", line 6, in <module>
    class Logging:
  File "C:/AutomationScripts/build scripts/Deleteme.py", line 42, in Logging
    __clearOldLogs(dummySetting)
  File "C:/AutomationScripts/build scripts/Deleteme.py", line 38, in __clearOldLogs
    _assert(Logger, 'Logger does not exist yet! Why?')
NameError: global name '_assert' is not defined
>>> 
Run Code Online (Sandbox Code Playgroud)

是的,我来自Java/C#背景.我可能不会做"Pythonic"的方式.请帮我做正确的事,请给出一个完整的答案,而不是简单地指出我的知识漏洞.我相信我提供了足够的代码示例.对不起,如果没有设置类,它就不会运行,但希望你明白了.

# This file has been tested on Python 2.6.*. For Windows only.

import logging          # For actual logging
import tkMessageBox     # To display an error (if logging is unavailable)

class Logging:
    """
    Logging class provides simplified interface to logging
    as well as provides some handy functions.
    """

    # To be set when the logger is properly configured.
    Logger = None

    @staticmethod
    def _assert(condition, message):
        """ Like a regular assert, except that it should be visible to the user. """
        if condition: return
        # Else log and fail
        if Logger:
            Logger.debug(traceback.format_stack())
            Logger.error('Assert failed: ' + message)
        else:
            tkMessageBox.showinfo('Assert failed: ' + message, traceback.format_stack())            
        assert(condition)

    @staticmethod
    def _removeFromEnd(string, endString):
        _assert(string.endswith(endString),
                "String '{0}' does not end in '{1}'.".format(string, endString))
        return string[:-len(endString)]

    def __clearOldLogs(logSettings):
        """
        We want to clear old (by date) files if we get too many.
        We should call this method only after variable 'Logger' has been created.
        """
        # The following check should not be necessary from outside of
        # Logging class, when it is fully defined
        _assert(Logger, 'Logger does not exist yet! Why?')
        # Do more work here

    def __createLogger(logSettings):
        logFileName = logSettings.LogFileNameFunc()
        #_assert(False, 'Test')
        logName = _removeFromEnd(logFileName, logSettings.FileExtension)
        logFileName = os.path.join(logSettings.BaseDir, logFileName)
        # If someone tried to log something before basicConfig is called,
        # Python creates a default handler that goes to the console and will
        # ignore further basicConfig calls. Remove the handler if there is one.
        root = logging.getLogger()
        if root.handlers:
            for handler in root.handlers:
                root.removeHandler(handler)
        logging.basicConfig(filename = logFileName, name = logName, level = logging.DEBUG, format = "%(asctime)s - %(levelname)s - %(message)s")
        logger = logging.getLogger(logName)
        return logger

    # Settings is a separate class (not dependent on this one).    
    Logger = __createLogger(Settings.LOGGING)
    __clearOldLogs(Settings.LOGGING)

if __name__ == '__main__':
    # This code section will not run when the class is imported.
    # If it is run directly, then we will print debugging info.
    logger = Logging.Logger
    logger.debug('Test debug message.')
    logger.info('Test info message.')
    logger.warning('Test warning message.')
    logger.error('Test error message.')
    logger.critical('Test critical message.')
Run Code Online (Sandbox Code Playgroud)

欢迎提出相关问题,风格建议和完整答案.谢谢!

kin*_*all 5

你得到那个例外,因为你是打电话_assert()而不是Logging._assert().错误消息告诉您它正在_assert()模块的全局命名空间而不是类命名空间中查找; 要让它查看后者,你必须明确指定它.

当然,在这种情况下,你正在尝试在类仍然被定义时执行它,并且在类完成之前名称不可用,因此要使这项工作变得困难.

一个解决方案是取消缩进以下两行(我已编辑为使用完全限定名),以便它们在类定义之外; 它们将在它之后立即执行.

Logger = Logging.__createLogger(Settings.LOGGING)
Logging.__clearOldLogs(Settings.LOGGING)
Run Code Online (Sandbox Code Playgroud)

一个样式建议将有所帮助:而不是使用一堆静态方法创建一个类,考虑将它们作为模块中的顶级函数.模块的用户(包括您自己)会发现更容易获得他们想要的功能.没有理由将一个类用作容器; 模块本身就已经是这样一个容器了.

模块基本上是一个单独的*.py文件(虽然你可以创建具有多个文件的模块,但现在这样做).当你这样做时import,你导入的是一个模块.在您的示例中,tkMessageBox并且logging都是模块.因此,只需创建一个单独的文件(确保其名称与现有的Python模块名称不冲突),将其保存在与主脚本相同的目录中,然后将其导入主脚本中.如果你对它mylogging.py进行了命名,那么你就可以import mylogging访问其中的函数mylogging.clearOldLogs()或者其他函数(类似于你现在作为一个类来解决它们的方式).

Python中的"全局"名称并不是真正的全局名称,它们只是它们所定义的模块的全局名称.因此,模块是划分功能的好方法,尤其是您预期会在很多情况下重复使用的部分(如日志记录)你未来的剧本.