欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python日志打印里logging.getLogger源碼分析詳解

 更新時(shí)間:2021年01月17日 13:42:10   作者:授客  
在本篇文章里小編給大家整理的是一篇關(guān)于Python logging.getLogger源碼分析的相關(guān)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)參考下。

實(shí)踐環(huán)境

WIN 10

Python 3.6.5

函數(shù)說(shuō)明

logging.getLogger(name=None)

getLogger函數(shù)位于logging/__init__.py腳本

源碼分析

_loggerClass = Logger
# ...略
 
root = RootLogger(WARNING)
Logger.root = root
Logger.manager = Manager(Logger.root)
 
# ...略
 
def getLogger(name=None):
  """
  Return a logger with the specified name, creating it if necessary.
 
  If no name is specified, return the root logger.
  """
  if name:
    return Logger.manager.getLogger(name)
  else:
    return root

結(jié)論:如函數(shù)注釋所述,如果調(diào)用getLogger時(shí),如果沒(méi)有指定函數(shù)參數(shù)(即要獲取的日志打印器名稱)或者參數(shù)值不為真,則默認(rèn)返回root打印器

Logger.manager.getLogger(self, name)源碼分析

該函數(shù)位于logging/__init__.py腳本

class Manager(object):
  """
  There is [under normal circumstances] just one Manager instance, which
  holds the hierarchy of loggers.
  """
  def __init__(self, rootnode):
    """
    Initialize the manager with the root node of the logger hierarchy.
    """
    self.root = rootnode
    self.disable = 0
    self.emittedNoHandlerWarning = False
    self.loggerDict = {}
    self.loggerClass = None
    self.logRecordFactory = None
 
  def getLogger(self, name):
    """
    Get a logger with the specified name (channel name), creating it
    if it doesn't yet exist. This name is a dot-separated hierarchical
    name, such as "a", "a.b", "a.b.c" or similar.
 
    If a PlaceHolder existed for the specified name [i.e. the logger
    didn't exist but a child of it did], replace it with the created
    logger and fix up the parent/child references which pointed to the
    placeholder to now point to the logger.
    """
    rv = None
    if not isinstance(name, str):
      raise TypeError('A logger name must be a string')
    _acquireLock()
    try:
      if name in self.loggerDict:
        rv = self.loggerDict[name]
        if isinstance(rv, PlaceHolder):
          ph = rv
          rv = (self.loggerClass or _loggerClass)(name)
          rv.manager = self
          self.loggerDict[name] = rv
          self._fixupChildren(ph, rv)
          self._fixupParents(rv)
      else:
        rv = (self.loggerClass or _loggerClass)(name) # _loggerClass = Logger
        rv.manager = self
        self.loggerDict[name] = rv
        self._fixupParents(rv)
    finally:
      _releaseLock()
    return rv

Logger源碼分析

_nameToLevel = {
  'CRITICAL': CRITICAL,
  'FATAL': FATAL,
  'ERROR': ERROR,
  'WARN': WARNING,
  'WARNING': WARNING,
  'INFO': INFO,
  'DEBUG': DEBUG,
  'NOTSET': NOTSET,
}
 
# ...略
 
def _checkLevel(level):
  if isinstance(level, int):
    rv = level
  elif str(level) == level:
    if level not in _nameToLevel:
      raise ValueError("Unknown level: %r" % level)
    rv = _nameToLevel[level]
  else:
    raise TypeError("Level not an integer or a valid string: %r" % level)
  return rv
 
# ...略
class PlaceHolder(object):
  """
  PlaceHolder instances are used in the Manager logger hierarchy to take
  the place of nodes for which no loggers have been defined. This class is
  intended for internal use only and not as part of the public API.
  """
  def __init__(self, alogger):
    """
    Initialize with the specified logger being a child of this placeholder.
    """
    self.loggerMap = { alogger : None }
 
  def append(self, alogger):
    """
    Add the specified logger as a child of this placeholder.
    """
    if alogger not in self.loggerMap:
      self.loggerMap[alogger] = None
 
 
 
class Logger(Filterer):
  """
  Instances of the Logger class represent a single logging channel. A
  "logging channel" indicates an area of an application. Exactly how an
  "area" is defined is up to the application developer. Since an
  application can have any number of areas, logging channels are identified
  by a unique string. Application areas can be nested (e.g. an area
  of "input processing" might include sub-areas "read CSV files", "read
  XLS files" and "read Gnumeric files"). To cater for this natural nesting,
  channel names are organized into a namespace hierarchy where levels are
  separated by periods, much like the Java or Python package namespace. So
  in the instance given above, channel names might be "input" for the upper
  level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
  There is no arbitrary limit to the depth of nesting.
  """
  def __init__(self, name, level=NOTSET):
    """
    Initialize the logger with a name and an optional level.
    """
    Filterer.__init__(self)
    self.name = name
    self.level = _checkLevel(level)
    self.parent = None
    self.propagate = True
    self.handlers = []
    self.disabled = False
 
  # ... 略

結(jié)論:如果調(diào)用logging.getLogger()時(shí),有指定日志打印器名稱,且名稱為真(不為空字符串,0,F(xiàn)alse等False值),

1)如果名稱為不存在的日志打印器名稱,則,且參數(shù)值為真,但是即要獲取的日志打印器名稱)或者參數(shù)值不為真,則創(chuàng)建一個(gè)名為給定參數(shù)值的日志打印器,該日志打印器,默認(rèn)級(jí)別默認(rèn)為NOTSET,disable_existing_loggers配置為False,propagate配置為True。然后在日志打印器字典中記錄該名稱和日志打印器的映射關(guān)系,接著調(diào)用 _fixupParents(創(chuàng)建的日志打印器實(shí)例)類實(shí)例方法--為日志打印器設(shè)置上級(jí)日志打印器,最后返回該日志打印器。

2)如果名稱已存在日志打印器名稱,則獲取該日志打印器,然后判斷日志打印器是否為PlaceHolder類實(shí)例,如果是,則創(chuàng)建一個(gè)名為所給參數(shù)值的日志打印器,同第1)點(diǎn),該日志打印器,默認(rèn)級(jí)別默認(rèn)為NOTSET,disable_existing_loggers配置為False,propagate配置為True。然后在日志打印器字典中記錄該名稱和日志打印器的映射關(guān)系,接著調(diào)用 _fixupParents(創(chuàng)建的打印器實(shí)例)類實(shí)例方法,_fixupChildren(PlaceHolder類實(shí)例--根據(jù)名稱獲取的日志打印器,新建的日志打印器實(shí)例)--為新建日志打印器設(shè)置上級(jí)日志打印器,為PlaceHolder類實(shí)例現(xiàn)有下級(jí)PlaceHolder日志打印器實(shí)例重新設(shè)置上級(jí)日志打印器,最后返回該日志打印器。

_fixupParents及_fixupChildren函數(shù)源碼分析

# _fixupParents
 
# ...略
class Manager(object):
  # ...略
  def _fixupParents(self, alogger):
    """
    Ensure that there are either loggers or placeholders all the way
    from the specified logger to the root of the logger hierarchy.
    """
    name = alogger.name # 獲取日志打印器名稱
    i = name.rfind(".")
    rv = None # 存放alogger日志打印器的上級(jí)日志打印器
    while (i > 0) and not rv: # 如果名稱中存在英文的點(diǎn),并且找到上級(jí)日志打印器
      substr = name[:i] # 獲取名稱中位于最后一個(gè)英文的點(diǎn)的左側(cè)字符串(暫且稱至為 點(diǎn)分上級(jí))
      if substr not in self.loggerDict: # 如果 點(diǎn)分上級(jí) 不存在日志打印器字典中
        self.loggerDict[substr] = PlaceHolder(alogger) # 創(chuàng)建PlaceHolder實(shí)例作為 點(diǎn)分上級(jí) 對(duì)應(yīng)的日志打印器 # 繼續(xù)查找點(diǎn)分上級(jí)日志打印器 # 注意,這里的PlaceHolder僅是占位用,不是真的打印器,這里為了方便描述,暫且稱之為PlaceHolder日志打印器
      else: # 否則
        obj = self.loggerDict[substr] # 獲取 點(diǎn)分上級(jí) 對(duì)應(yīng)的日志打印器
        if isinstance(obj, Logger): # 如果為L(zhǎng)ogger實(shí)例,如果是,則跳出循環(huán),執(zhí)行 # 為日志打印器設(shè)置上級(jí)
          rv = obj
        else: # 否則
          assert isinstance(obj, PlaceHolder) # 斷言它為PlaceHolder的實(shí)例
          obj.append(alogger) # 把日志打印器添加為點(diǎn)分上級(jí)對(duì)應(yīng)的PlaceHolder日志打印器實(shí)例的下級(jí)日志打印器 執(zhí)行 # 繼續(xù)查找點(diǎn)分上級(jí)日志打印器
      i = name.rfind(".", 0, i - 1) # 繼續(xù)查找點(diǎn)分上級(jí)日志打印器
    if not rv: # 找不到點(diǎn)分上級(jí)、或者遍歷完所有點(diǎn)分上級(jí),都沒(méi)找到上級(jí)日志打印器
      rv = self.root # 則 把root日志打印器設(shè)置為alogger日志打印器的上級(jí)日志打印器
    alogger.parent = rv # 為日志打印器設(shè)置上級(jí)
 
 
 
  def _fixupChildren(self, ph, alogger):
    """
    Ensure that children of the placeholder ph are connected to the
    specified logger.
    """
    name = alogger.name # 獲取日志打印器名稱
    namelen = len(name) # 獲取日志打印器名稱長(zhǎng)度
    for c in ph.loggerMap.keys(): # 遍歷獲取的PlaceHolder日志打印器實(shí)例的子級(jí)日志打印器
      #The if means ... if not c.parent.name.startswith(nm)
      if c.parent.name[:namelen] != name: # 如果PlaceHolder日志打印器實(shí)例名稱不以alogger日志打印器名稱為前綴,
        alogger.parent = c.parent # 那么,設(shè)置alogger日志打印器的上級(jí)日志打印器為PlaceHolder日志打印器
        c.parent = alogger # 設(shè)置alogger日志打印器為PlaceHolder日志打印器原有下級(jí)PlaceHolder日志打印器的上級(jí)

結(jié)論:日志打印器都是分父子級(jí)的,這個(gè)父子層級(jí)是怎么形成的,參見(jiàn)上述函數(shù)代碼注解

到此這篇關(guān)于Python日志打印里logging.getLogger源碼分析詳解的文章就介紹到這了,更多相關(guān)Python logging.getLogger源碼分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python圖像讀寫方法對(duì)比

    Python圖像讀寫方法對(duì)比

    這篇文章主要介紹了Python圖像讀寫方法對(duì)比的相關(guān)資料,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-11-11
  • Python??reduce()函數(shù)的用法示例代碼

    Python??reduce()函數(shù)的用法示例代碼

    reduce函數(shù)原本在python2中也是個(gè)內(nèi)置函數(shù),不過(guò)在python3中被移到functools模塊中,這篇文章主要介紹了Python reduce()函數(shù)的用法,需要的朋友可以參考下
    2023-05-05
  • python軟件都是免費(fèi)的嗎

    python軟件都是免費(fèi)的嗎

    在本篇文章中小編給大家整理的是關(guān)于python軟件免是否費(fèi)的相關(guān)知識(shí)點(diǎn),需要的朋友們可以參考下。
    2020-06-06
  • python+django+rest框架配置創(chuàng)建方法

    python+django+rest框架配置創(chuàng)建方法

    今天小編就為大家分享一篇python+django+rest框架配置創(chuàng)建方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-08-08
  • Python批量按比例縮小圖片腳本分享

    Python批量按比例縮小圖片腳本分享

    這篇文章主要介紹了Python批量按比例縮小圖片腳本分享,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2015-05-05
  • Pycharm如何對(duì)python文件進(jìn)行打包

    Pycharm如何對(duì)python文件進(jìn)行打包

    這篇文章主要介紹了Pycharm如何對(duì)python文件進(jìn)行打包,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Python常用工具類之a(chǎn)dbtool示例代碼

    Python常用工具類之a(chǎn)dbtool示例代碼

    本文主要介紹了Python中常用工具類之a(chǎn)db命令的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • python使用zip將list轉(zhuǎn)為json的方法

    python使用zip將list轉(zhuǎn)為json的方法

    今天小編就為大家分享一篇python使用zip將list轉(zhuǎn)為json的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • PyTorch使用自動(dòng)微分模塊的方法和理解

    PyTorch使用自動(dòng)微分模塊的方法和理解

    自動(dòng)微分模塊Autograd為張量增加了自動(dòng)求導(dǎo)功能,是神經(jīng)網(wǎng)絡(luò)訓(xùn)練不可或缺的組成部分,通過(guò)backward方法和grad屬性,實(shí)現(xiàn)梯度的計(jì)算和訪問(wèn),本小節(jié)主要講解了 PyTorch 中非常重要的自動(dòng)微分模塊的使用和理解,感興趣的朋友一起看看吧
    2024-09-09
  • python skimage 連通性區(qū)域檢測(cè)方法

    python skimage 連通性區(qū)域檢測(cè)方法

    今天小編就為大家分享一篇python skimage 連通性區(qū)域檢測(cè)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06

最新評(píng)論