LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-11-2022, 05:48 AM   #1
masavini
Member
 
Registered: Jun 2008
Posts: 285

Rep: Reputation: 6
python globals...


hi,
i'm learning python and i can't really guess how do globals work.

if i define a variable in main.py, is there a way to access it in every sub module of the application?

i mean, let's say i have this main.py:
Code:
from loguru import logger
from my_module import my_func

def main():
    my_func()

is there a way to use logger in my_func without re-importing loguru inside my_module and without passing logger as an argument to my_func?

thanks!

Last edited by masavini; 02-11-2022 at 05:50 AM.
 
Old 02-11-2022, 05:57 AM   #2
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,041

Rep: Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348
my_func will not know how to use that logger class without import.
see here: https://stackoverflow.com/questions/...ported-modules
 
Old 02-11-2022, 06:06 AM   #3
masavini
Member
 
Registered: Jun 2008
Posts: 285

Original Poster
Rep: Reputation: 6
and is that a bug or a feature..?
 
Old 02-11-2022, 06:24 AM   #4
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,041

Rep: Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348
this is how is it designed. But you need to do the same in c/c++, java too, so this seems perfectly normal.
 
Old 02-11-2022, 08:58 AM   #5
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
My 2 cents. Instead of assigning global variables. Share the variables between classes, functions, modules, imports.
Code:
#!/usr/bin/python

#Sharing variables between classes demo

class Fred():
    def __init__(self):
        #Local variable for class
        self.bird = 'Bird'
        
        def one(self):
            #Local variables for function one
            self.dog = 'Dog'
            self.cat = 'Cat'
            self.horse = 'Horse'
            #Return 2 variables from function
            return self.dog, self.cat
            
        def two(self):
            #Local variable for function two
            self.num = 5
            return self.num
            
        one(self)
        two(self)
    
class Barney():
    def __init__(self, Fred):
        #From Fred
        self.animal = Fred.dog
        
        def three(self):
            #Shared variable from Fred
            self.a = self.animal
            #Local variables for function three
            self.b = 'Cow'
            self.c = 'Sheep'
            return self.a
        three(self)
        
class Betty():
    def __init__(self, Fred):
        #From Fred
        self.animal = Fred.cat
        
        def four(self):
            #Shared variable from Fred
            self.a = self.animal
            return self.a
        four(self)
        
class Wilma():
    def __init__(self, Fred):
        #From Fred
        self.animal = Fred().bird
        #Print shared variable self.animal from Fred
        print('Shared Variable from Fred in Wilma >', self.animal)
        
class BamBam():
    def __init__(self, Betty):
        #From Betty
        self.animal = Betty.a
        
        def five(self):
            self.animal = Betty.a
            return self.animal
        five(self)
        
class Pebbles():
    def __init__(self, Fred):
        self.num = Fred.num
        self.xyz = (self.num * 10)
        
        def six(self):
            #Shared variable from Fred
            self.a = self.num
            #Local variables for function six
            self.b = (self.a * 2)
            self.c = (self.a * 3)
            self.d = (self.a / 4)
            return self.b, self.c, self.d   
        six(self)
                        
if __name__ == "__main__":
    
    fred = Fred()
    barney = Barney(fred)
    betty = Betty(fred)
    pebbles = Pebbles(fred)
    bambam = BamBam(betty)
    
    #Print local variables in Fred
    print('Local variables from Fred >', fred.cat, fred.dog, fred.horse)
    
    #Print local variables in Barney
    print('Local variables from Barney >', barney.b, barney.c)
    
    #Print shared variable from Fred, shared with Barney
    print('Shared variable from Fred in Barney >', barney.a)
    
    #Print shared variable from Fred, shared with Betty
    print('Shared variable from Fred in Betty >', betty.a)
    
    #Print shared variable from Betty, shared with BamBam
    print('Shared variable from Betty in BamBam >', bambam.animal)
    
    #Print local variables from Pebbles
    print('Local variables from Pebbles >', pebbles.b, pebbles.c, pebbles.d)
    
    #Wilma
    Wilma(Fred)
    
    #Math between classes
    print('(pebbles.xyz ** 3) =', pebbles.xyz ** 3)
    print('(fred.num - pebbles.b) =', fred.num - pebbles.b)
    print('(fred.num + pebbles.c) =', fred.num + pebbles.c)
 
Old 02-11-2022, 09:04 AM   #6
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
Code:
#!/usr/bin/python

#Sharing variables between functions demo

#Function one
def one():
    a = 5
    b = 2
    c = a * b
    return a, b, c

#Function two
def two():
    d = 1
    e = 2
    f = 3
    return d, e, f
    
#Function three
def three():
    g = 10
    h = 20
    i = 30
    return g, h, i
    
#Function four
def four():
    a = 'Cow'
    b = 'Horse'
    c = 'Sheep'
    return a, b, c
    
#Print returns from functions
print('Returns from functions:')
print('Return from one =', one())
print('Return from two =', two())
print('Return from three =', three())
print('Return from three =', four())
print('')

#Math with vars from different functions
print('Math with variables from different functions:')
print('one.c * two.f =', one()[2] * two()[2])
print('three.i / three.g =', three()[2] / three()[0])
print('three.g + two.e =', three()[0] + two()[1])
print('((three.i + one.b) - two.f) =', (three()[2] + one()[1]) - two()[2])
print('')
 
Old 02-11-2022, 09:10 AM   #7
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
globals

Code:
#!/usr/bin/python

m = 'Hello there'

def one():
    global a
    a = 'cow'
    b = 5
    return a, b
    
def two():
    c = a
    d = 'horse'
    return c, d
    
def three():
    e = a
    print(e)
    print(m)
    
one()
print(two())
three()
 
Old 02-11-2022, 09:31 AM   #8
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
Another one.

Code:
#!/usr/bin/python

#Share variables between functions demo

def drawLine(length, label=''):
    line = '-' * length
    if label:
        line += ' ' + label
    print(line)

def interval(num):
    if num > 0:
        interval(num - 1)
        drawLine(num)
        interval(num - 1)

def drawRuler(inches, length):
    drawLine(length, '0')
    for i in range(1, 1 + inches):
        interval(length - 1)
        drawLine(length, str(i))

drawRuler(5, 3)
 
Old 02-11-2022, 02:20 PM   #9
masavini
Member
 
Registered: Jun 2008
Posts: 285

Original Poster
Rep: Reputation: 6
thanks for your all of your replies, but it's still not clear to me (i'm a newbie, after all)... )

i have the module logger.py:
Code:
# -*- coding: utf-8 -*-

"""Configure loguru logger and notifiers

https://github.com/Delgan/loguru

https://github.com/Delgan/loguru/issues/441#issuecomment-842911850

https://notifiers.readthedocs.io/en/latest/providers/telegram.html
"""

import os
import sys


from dotenv import load_dotenv
from loguru import logger
from notifiers.logging import NotificationHandler


def config_logger():
    """Configure loguru logger and notifiers"""

    # Detect whether sys.stdout is attached to a console terminal or not
    # https://stackoverflow.com/questions/1077113/how-do-i-detect-whether-sys-stdout-is-attached-to-terminal-or-not
    is_tty = sys.stdout.isatty()

    if is_tty:
        colorize = True
        level = "DEBUG"
    else:
        colorize = False
        level = "INFO"

    logger.configure(
        handlers=[
            {
                "sink": sys.stderr,
                "level": level,
                "colorize": colorize
            }
        ]
    )

    if is_tty:

        load_dotenv()

        params = {
            "chat_id": os.getenv('TELEGRAM_CHAT_ID'),
            "token": os.getenv('TELEGRAM_BOT_ID')
        }

        logger.debug(*params)

        handler = NotificationHandler("telegram", defaults=params)
        logger.add(handler, level="ERROR", colorize=False)

    return logger


log = config_logger()
and this is main.py:
Code:
from config.logger import log

from demo_pkg.demo_module import demo_function


@log.catch
def main():
    """Main entry point of the app"""
    demo_function()
is there a way to use log in demo_function without importing config.logger inside demo_module?

i guess re-importing config.logger in each module would run config_logger again and again, wouldn't it be a waste of resources?
 
Old 02-11-2022, 03:23 PM   #10
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
You are going to have to stick your nose in the python docs.

These will need to be in the same directory.

mod1.py
Code:
#!/usr/bin/python

class ABC():
    def __init__(self):
        
        self.a = 10
        
        def one(self):
            b = 'Linux'
            print(b)
            
        one(self)
main.py
Code:
#/usr/bin/python

from mod1 import ABC

x = 3
y = 5
z = ABC()

print(z.a)
print((z.a) - x)
print(y + (z.a))
 
Old 02-11-2022, 03:38 PM   #11
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
Where is demo_module?
https://github.com/Delgan/loguru/tree/master/loguru
https://github.com/Delgan/loguru

demo_function
Where is that at?

Quote:
guess re-importing config.logger
Where are you getting that from?

I can't tell what you are doing. You are going to have to give some better info.

If you need a module in every python script then you'll have to import it. If that is what you are doing though, fix your code. Python is slow enough to start with.
 
Old 02-11-2022, 04:35 PM   #12
masavini
Member
 
Registered: Jun 2008
Posts: 285

Original Poster
Rep: Reputation: 6
hi,
sorry for the missing info.

this is the sample tree:
Code:
.
├── poetry.lock
├── pyproject.toml
└── src
    ├── config
    │   ├── __init__.py
    │   └── logger.py
    ├── demo_pkg
    │   ├── demo_module.py
    │   └── __init__.py
    └── main.py
i know i can use log importing config.logger in any package/module.

log, however, is a variable which is going to be be used in pretty much all of the packages and modules of the application, and if the application grows i would like to do it without importing config.logger again and again.

i hope the question is clearer and not too silly...
 
Old 02-11-2022, 06:07 PM   #13
krunch3r
LQ Newbie
 
Registered: Feb 2022
Posts: 2

Rep: Reputation: 1
Cool module namespace (globals) initialized once

Quote:
Originally Posted by masavini View Post
hi,
sorry for the missing info.

this is the sample tree:
Code:
.
├── poetry.lock
├── pyproject.toml
└── src
    ├── config
    │   ├── __init__.py
    │   └── logger.py
    ├── demo_pkg
    │   ├── demo_module.py
    │   └── __init__.py
    └── main.py
i know i can use log importing config.logger in any package/module.

log, however, is a variable which is going to be be used in pretty much all of the packages and modules of the application, and if the application grows i would like to do it without importing config.logger again and again.

i hope the question is clearer and not too silly...
what we have here is a global name in a module namespace that is initialized by a statement in the module. subsequent imports of log from config.logger will not re-execute the initialization of log (or anything in the already initialized module namespace [✪]), so go ahead and add the statement in whatever subpackages/modules need log etc just as if you were declaring any other variable you need:
Code:
from config.logger import log
[✪]
Quote:
Originally Posted by docs.python.org/3/tutorial/modules.html#more-on-modules
A module can contain executable statements as well as function definitions. These statements are intended to initialize the module. They are executed only the first time the module name is encountered in an import statement. 1 (They are also run if the file is executed as a script.)
1 In fact function definitions are also ‘statements’ that are ‘executed’; the execution of a module-level function definition enters the function name in the module’s global symbol table.
✪✪python docs tl;dr: everything in the module is interpreted ONCE


You can confirm this for yourself by writing something to standard out inside of config_logger() and see it will only execute once to form log (e.g. from main but not again when importing demo_module.py).

krunch3r
~~~~~~~~~~~~~~~~~~~~~~~
i krunch therefore i am
 
1 members found this post helpful.
Old 02-12-2022, 02:45 AM   #14
masavini
Member
 
Registered: Jun 2008
Posts: 285

Original Poster
Rep: Reputation: 6
thank you very much for your time and your patience, now it's much clearer to me.

Quote:
You can confirm this for yourself by writing something to standard out inside of config_logger() and see it will only execute once to form log (e.g. from main but not again when importing demo_module.py).
that's indeed what i did yesterday after my last post and that test led me to the same conclusion as yours.

there's still a small drawback with this design, however: what if such an ubiquitous module needs refactoring? let's say in a couple of years i want to change the module's name from logger.py to logging.py, or change the name of its parent folder. at that point the app might contain dozens of modules and i should edit the import statement in each of them... i could use a sed command for that, but it would leave me a little bit scared...
 
Old 02-12-2022, 04:53 PM   #15
krunch3r
LQ Newbie
 
Registered: Feb 2022
Posts: 2

Rep: Reputation: 1
Lightbulb weapon of global destruction

Quote:
Originally Posted by masavini View Post
thank you very much for your time and your patience, now it's much clearer to me.



that's indeed what i did yesterday after my last post and that test led me to the same conclusion as yours.

there's still a small drawback with this design, however: what if such an ubiquitous module needs refactoring? let's say in a couple of years i want to change the module's name from logger.py to logging.py, or change the name of its parent folder. at that point the app might contain dozens of modules and i should edit the import statement in each of them... i could use a sed command for that, but it would leave me a little bit scared...
tl;dr:
to have flexibility in changing package path and/or module name anywhere in the dev lifecycle you may consider these high-level solutions (incomplete) utilizing any combination of these standard modules (module names are underlined)
sys.modules: add key of previously used package_path.module to sys.modules so that it points to the new package_path.module then import as either the old or the new
✬✬ builtins: add log to builtins namespace via dot notation and refer to log directly without dot notation (magick!)
✬✬✬ importlib: use lookup table (inside of __builtins__ or maybe os.environ) to lookup the package.module path (string) as an argument to importlib.import_module



✬if you change the name, you can make references to the imported module by adding a new key to the sys.modules dictionary so that the old name refers to the new name on subsequent imports [1]
Code:
#############
# main.py
import sys

import myconfig.logger # changed from config.logger
sys.modules['config.logger']=myconfig.logger

from my_module.my_module import my_func

########################
# my_module/my_func.py
from config.logger import log

def my_func():
   # use log here
✬✬but you sound like a hacker and who has "outgrown" the sandbox 😋 so you could add log (or perhaps more sanely a lookup table) to the universally "exported" namespace __builtins__ via the builtins module [2,3]

Code:
# main.py
import config.logger
import builtins
builtins.log=config.logger.log
from my_module.my_module import my_func

my_func() # my_func() can refer to log directly without importing it
the above will draw criticism for polluting the builtin namespace but it does demonstrate global in the sense you appear to be thinking of.

you would probably draw less fire if instead you define a lookup table in __builtins__ that contains current the module path then pass it as an argument to importlib.import_modules [4]
✬✬✬
Code:
#./main.py
import os
import builtins
import myconfig.logger

builtins.mymodules=dict()
# builtins.mymodules['config.logger']=config.logger # config.logger not an existing package.module path
builtins.mymodules['config.logger']=myconfig.logger NOTE: this is stringified later for importlib.import_module

from my_module.my_module import my_func
my_func()

# ---------------------
###########################
#./my_module/my_module.py
import importlib
log = importlib.import_module(mymodules['config.logger'].__name__).log
if you use importlib and a lookup table, you could also use os.environ to store keys so as to not pollute __builtins__.

[1] https://docs.python.org/3/library/sys.html#sys.modules
[2] https://docs.python.org/3/reference/...cted-execution
[3] https://docs.python.org/3/library/builtins.html
[4] https://docs.python.org/3/library/importlib.html


krunch3r
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
it is not a question of whether to krunch
 
  


Reply

Tags
python



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
SWAT doesn't display globals, shares, printers, etc. jschwartzman Linux - Software 0 08-24-2008 04:26 PM
Apache-PHP - mod_ssl globals missing otie Linux - Software 2 07-28-2007 12:02 AM
Globals in PHP and Smarty ($_GET) vargadanis Programming 6 12-01-2006 07:21 PM
Register Globals problem vnb400 Linux - Newbie 1 04-28-2006 09:51 AM
PHP 5.0 Register Globals and Apache 2.0.50 latino Linux - Software 1 07-21-2004 06:47 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:22 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration