What is being referenced by using dot notation with class name ?

naseeam
naseeam used Ask the Experts™
on
Following are code snippets from python 3.6 standard library logging module, filename __init__.py

On line 1732, class RootLogger gets instantiated.  But on line 1733, what is Logger.root ?  dot notation is used with object name, not class name ?
On line 1734, what is Logger.manager ?  Again, why dot notation is used with class name ?

#--------------------------------------------------------------------------- 
1250 #   Logger classes and functions
1251 #---------------------------------------------------------------------------
1252 
1253 class Logger(Filterer):
1254     """
1255     Instances of the Logger class represent a single logging channel. A
1256     "logging channel" indicates an area of an application. Exactly how an
1257     "area" is defined is up to the application developer. Since an
1258     application can have any number of areas, logging channels are identified
1259     by a unique string. Application areas can be nested (e.g. an area
1260     of "input processing" might include sub-areas "read CSV files", "read
1261     XLS files" and "read Gnumeric files"). To cater for this natural nesting,
1262     channel names are organized into a namespace hierarchy where levels are
1263     separated by periods, much like the Java or Python package namespace. So
1264     in the instance given above, channel names might be "input" for the upper
1265     level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
1266     There is no arbitrary limit to the depth of nesting.
1267     """
1268     def __init__(self, name, level=NOTSET):
1269         """
1270         Initialize the logger with a name and an optional level.
1271         """
1272         Filterer.__init__(self)
1273         self.name = name
1274         self.level = _checkLevel(level)
1275         self.parent = None
1276         self.propagate = True
1277         self.handlers = []
1278         self.disabled = False
1279 
1280     def setLevel(self, level):
1281         """
1282         Set the logging level of this logger.  level must be an int or a str.
1283         """
1284         self.level = _checkLevel(level)
1285 
1286     def debug(self, msg, *args, **kwargs):

Open in new window


class RootLogger(Logger):
1577     """
1578     A root logger is not that different to any other logger, except that
1579     it must have a logging level and there is only one instance of it in
1580     the hierarchy.
1581     """
1582     def __init__(self, level):
1583         """
1584         Initialize the logger with the name "root".
1585         """
1586         Logger.__init__(self, "root", level)
1587 
1588 _loggerClass = Logger

Open in new window


root = RootLogger(WARNING)
1733 Logger.root = root
1734 Logger.manager = Manager(Logger.root)

Open in new window


#---------------------------------------------------------------------------
1834 # Utility functions at module level.
1835 # Basically delegate everything to the root logger.
1836 #---------------------------------------------------------------------------
1837 
1838 def getLogger(name=None):
1839     """
1840     Return a logger with the specified name, creating it if necessary.
1841 
1842     If no name is specified, return the root logger.
1843     """
1844     if name:
1845         return Logger.manager.getLogger(name)
1846     else:
1847         return root

Open in new window


class Manager(object):
1146     """
1147     There is [under normal circumstances] just one Manager instance, which
1148     holds the hierarchy of loggers.
1149     """
1150     def __init__(self, rootnode):
1151         """
1152         Initialize the manager with the root node of the logger hierarchy.
1153         """
1154         self.root = rootnode
1155         self.disable = 0
1156         self.emittedNoHandlerWarning = False
1157         self.loggerDict = {}
1158         self.loggerClass = None
1159         self.logRecordFactory = None
1160 
1161     def getLogger(self, name):
1162         """
1163         Get a logger with the specified name (channel name), creating it
1164         if it doesn't yet exist. This name is a dot-separated hierarchical
1165         name, such as "a", "a.b", "a.b.c" or similar.
1166 
1167         If a PlaceHolder existed for the specified name [i.e. the logger
1168         didn't exist but a child of it did], replace it with the created
1169         logger and fix up the parent/child references which pointed to the
1170         placeholder to now point to the logger.
1171         """
1172         rv = None
1173         if not isinstance(name, str):
1174             raise TypeError('A logger name must be a string')
1175         _acquireLock()
1176         try:
1177             if name in self.loggerDict:
1178                 rv = self.loggerDict[name]
1179                 if isinstance(rv, PlaceHolder):
1180                     ph = rv
1181                     rv = (self.loggerClass or _loggerClass)(name)
1182                     rv.manager = self
1183                     self.loggerDict[name] = rv
1184                     self._fixupChildren(ph, rv)
1185                     self._fixupParents(rv)
1186             else:
1187                 rv = (self.loggerClass or _loggerClass)(name)
1188                 rv.manager = self
1189                 self.loggerDict[name] = rv
1190                 self._fixupParents(rv)
1191         finally:
1192             _releaseLock()
1193         return rv

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
class can have class variables and instance variables. Class variables are global to all instances. on the other hand the instance variables are particular to it and the "__init__" method self.variable name is generally created. for example: 

class myClass  (object): 
    root = "something val" 
    def __init __ (self, value): 
        self.root = value 
mc = myClass ("hello") 
print (mc.root) 
print (myClass.root)

you will see that the result shows different values. This class has a "root" variable with class scope therefore it is created only once. on the other hand, the "root" variable that is created in the "__init__" method has an instance scope and has nothing to do with the "root" class variable. In the RootLogger the "root" variable has class scope because it is referred to with the class name. I hope you understand me because my English is so so.

Author

Commented:
>> In the RootLogger the "root" variable has class scope because it is referred to with the class name.
Please look at class RootLogger above, there is no "root" variable.
Do you mean in the class Logger "root" variable has class scope?  If yes, I don't see "root" variable in class Logger?
Line 1733 and 1734 creates class variables.

In Python, the variable does not necessarily have to be previously defined in the class.

Logger.root = root

if  root variable is not defined in the class then it creates it with this line.

Author

Commented:
Thank you for answering the question and providing a good explanation.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial