• Passing information between modules

    From Stefan Ram@21:1/5 to All on Fri Nov 18 10:53:45 2022
    Can I use "sys.argv" to pass information between modules
    as follows?

    in module A:

    import sys
    sys.argv.append( "Hi there!" )

    in module B:

    import sys
    message = sys.argv[ -1 ]

    . "sys.argv" is said to be a list by the standard
    documentation, so it should be guaranteed to be
    appendable as lists are appendable.

    Moreover, in my own program, after its startup, third parties
    do not inspect "sys.argv". So by appending something to it
    (or modifying it) I do not tamper with information that might
    be misinterpreted by any third party outside of my own code.

    Another hack might be:

    in module A

    import builtins
    builtins.message = "Hi there!"

    in module B

    import builtins
    message = builtins.message

    But I'm not sure whether modules (such as "builtins" here)
    are guaranteed to be modifyable and visible by the language
    reference in this way though

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tobiah@21:1/5 to Stefan Ram on Fri Nov 18 07:19:42 2022
    On 11/18/22 02:53, Stefan Ram wrote:
    Can I use "sys.argv" to pass information between modules
    as follows?

    in module A:

    import sys
    sys.argv.append( "Hi there!" )

    in module B:

    import sys
    message = sys.argv[ -1 ]

    Kind of seems like a code smell. I think you would normally
    just inject the dependencies like:

    module_b.do_thing("Hi there!")

    If you really want to have a module-global space,
    you could just create a module globals.py, and
    import that in every module that needs to share globals.
    You can just do globals.message = "Hi there!" and
    from another module do print globals.message.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Tobiah on Fri Nov 18 14:24:32 2022
    On 11/18/2022 10:19 AM, Tobiah wrote:
    On 11/18/22 02:53, Stefan Ram wrote:
       Can I use "sys.argv" to pass information between modules
       as follows?

       in module A:

    import sys
    sys.argv.append( "Hi there!" )

       in module B:

    import sys
    message = sys.argv[ -1 ]

    Kind of seems like a code smell.  I think you would normally
    just inject the dependencies like:

        module_b.do_thing("Hi there!")

    If you really want to have a module-global space,
    you could just create a module globals.py, and
    import that in every module that needs to share globals.
    You can just do globals.message = "Hi there!" and
    from another module do print globals.message.

    The module can even create the message or variable dynamically. I have
    one that, when it is loaded, asks git for the branch and changeset hash
    the code's working directory is using. This module is imported by
    others that use the branch and changeset data in one way or another.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Axy@21:1/5 to Stefan Ram on Fri Nov 18 19:28:24 2022
    On 18/11/2022 10:53, Stefan Ram wrote:
    Can I use "sys.argv" to pass information between modules
    as follows?

    in module A:

    import sys
    sys.argv.append( "Hi there!" )

    in module B:

    import sys
    message = sys.argv[ -1 ]

    This idea has a couple of flaws so can be regarded as bad.

    However, if nothing else works (including suggested globals.py module),
    then os.environ could be a better way.

    Axy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Stefan Ram on Sun Nov 20 08:37:29 2022
    On 18/11/2022 23.53, Stefan Ram wrote:
    Can I use "sys.argv" to pass information between modules
    as follows?

    in module A:

    import sys
    sys.argv.append( "Hi there!" )

    in module B:

    import sys
    message = sys.argv[ -1 ]

    . "sys.argv" is said to be a list by the standard
    documentation, so it should be guaranteed to be
    appendable as lists are appendable.

    Moreover, in my own program, after its startup, third parties
    do not inspect "sys.argv". So by appending something to it
    (or modifying it) I do not tamper with information that might
    be misinterpreted by any third party outside of my own code.

    Another hack might be:

    in module A

    import builtins
    builtins.message = "Hi there!"

    in module B

    import builtins
    message = builtins.message

    But I'm not sure whether modules (such as "builtins" here)
    are guaranteed to be modifyable and visible by the language
    reference in this way though


    The re-use of built-in features is risky, if only because of the remote possibility that a future version of Python will add something that
    clashes. That's why Python makes such good (and careful) use of namespaces!

    In some respects we have the (OP) problem because Python does not have "interfaces" as a formal component of the language. So, we often
    get-away with taking an easier course - but in doing-so, may forget that
    they serve specific purposes.


    There is a general idea that globals are harmful, a code-smell, etc; and therefore something to be avoided. However, the global namespace is a (built-in!) feature of Python, so why not use it?

    The problem comes when we try to re-use module A or B in some other application. It may not be relatively-obvious that some global, eg
    config, must be previously-defined and made-available. If you're
    prepared to accept that risk - and presumably combat the criticism by
    carefully (and prominently) documenting it, just as with any other
    docstring, where's the problem? (caveat emptor!)


    Considering the use-case, it is unlikely to be as trivial as the
    example-given (OP). A classic example would be set of credentials to
    access an RDBMS and specific table(s).

    A 'standard' solution is to collect all such configuration-data at the
    start of the application, into an object (or other data-structure) - I
    usually call it "env" (an instantiation of "Environment").

    Thereafter, when needing such data within a module, calling the
    particular function/class/method by name (moduleNM.function(...) ), and
    passing only that section of the env[ironment] required. Such achieved
    by passing some sub-structure of env, or by passing a retrieval/get method.
    (a module handling GUI, for example, has no business looking at
    RDBMS-creds - which it would be able to do if the whole env was passed!)


    but...

    the module's code will expect its data in a particular form (an
    interface!), which must be documented and understood by both the
    provider and consumer (people and software)

    - which sounds like the same 'solution' to the 'globals problem'...

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael F. Stemper@21:1/5 to Stefan Ram on Sat Nov 19 14:46:16 2022
    On 18/11/2022 04.53, Stefan Ram wrote:
    Can I use "sys.argv" to pass information between modules
    as follows?

    in module A:

    import sys
    sys.argv.append( "Hi there!" )

    in module B:

    import sys
    message = sys.argv[ -1 ]

    I just tried and it appears that one can append to sys.argv. However,
    it seems like an incredibly bad idea.

    --
    Michael F. Stemper
    The name of the story is "A Sound of Thunder".
    It was written by Ray Bradbury. You're welcome.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Thomas Passin on Sat Nov 19 16:35:15 2022
    On 11/19/2022 4:28 PM, Thomas Passin wrote:
    On 11/19/2022 3:46 PM, Michael F. Stemper wrote:
    On 18/11/2022 04.53, Stefan Ram wrote:
       Can I use "sys.argv" to pass information between modules
       as follows?

       in module A:

    import sys
    sys.argv.append( "Hi there!" )

       in module B:

    import sys
    message = sys.argv[ -1 ]

    I just tried and it appears that one can append to sys.argv. However,
    it seems like an incredibly bad idea.

    For that matter, you can just directly add attributes to the sys module,
    no need to use sys.argv:

    import sys
    sys._extra = 'spam'   # Not an exception
    print(sys._extra)
    spam

    Probably not the best idea, though.  Better to use some module that you control directly.

    This could be one of those things of which Raymond Chen (The Old New
    Thing) asks "what if everyone did this?". Imagine if every (non-standard-library) module misused sys or sys.argv like this. The
    result could be chaotic.

    Best to put all your own stuff into modules that you yourself control.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Michael F. Stemper on Sat Nov 19 16:28:43 2022
    On 11/19/2022 3:46 PM, Michael F. Stemper wrote:
    On 18/11/2022 04.53, Stefan Ram wrote:
       Can I use "sys.argv" to pass information between modules
       as follows?

       in module A:

    import sys
    sys.argv.append( "Hi there!" )

       in module B:

    import sys
    message = sys.argv[ -1 ]

    I just tried and it appears that one can append to sys.argv. However,
    it seems like an incredibly bad idea.

    For that matter, you can just directly add attributes to the sys module,
    no need to use sys.argv:

    import sys
    sys._extra = 'spam' # Not an exception
    print(sys._extra)
    spam

    Probably not the best idea, though. Better to use some module that you
    control directly.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cameron Simpson@21:1/5 to Stefan Ram on Sun Nov 20 09:36:41 2022
    On 18Nov2022 10:53, Stefan Ram <[email protected]> wrote:
    Can I use "sys.argv" to pass information between modules
    as follows? [...]

    Stefan, it looks like most of the replies take the form: yes you can do
    that but it is probably a bad idea.

    Could you outline the larger situation where you want to do this? Often
    this kind of response ("yes but don't!") can be a clue that you're
    chasing the wrong (sorry, "suboptimal/poor") solution to a problem which
    can be solved in another way.

    Cheers,
    Cameron Simpson <[email protected]>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dan Kolis@21:1/5 to All on Sat Nov 19 18:17:54 2022
    In a module mostly for this purpose; ( big program means many modules aka files ):
    ----------------------------------------------------------------------------------
    globalIdeas.py ----------------------------------------------------------------------------------
    # Empty object maker ( M T ) ... get it say it !
    class MT():
    pass

    # IO dot area readier
    def prepIO():

    # Prep for general IO use really
    dotObjOps.ioSupport = MT()
    dotObjOps.ioSupport.sequenceMacro = MT()


    -----------------------------------------------------------------
    In Every use module: -----------------------------------------------------------------
    import globalIdeas as gi

    so now without burdensome advanced planning, a swap area is not only segregated by function
    but doesn't overly pollute too much globalism everywhere.

    New Idea:
    gl.ioSupport.sequencesMacro.newStartupIdea = {} gl.ioSupport.sequencesMacro.thingToReuse = 14
    etc ...

    A method in globalIdeas is named like startEverything():
    prepIO()
    prepNext()
    prepSounds()
    etc...

    This seems to me amenable to management of large programs in which absolutely any shaped objects be created as needed and be RW sharable in orderly fashion, etc.

    Its important if you read write files to plan ahead and have MT() names in surplus before you need them.

    I cant see any drawback to this at all. Many program have very legit reasons to have universal ideas. This avoids the emotional burden of the' "global KW" ; entirely.

    Regards,
    Daniel B. Kolis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Cameron Simpson on Sun Nov 20 10:39:40 2022
    Cameron Simpson <[email protected]> writes:
    On 18Nov2022 10:53, Stefan Ram <[email protected]> wrote:
    Can I use "sys.argv" to pass information between modules
    as follows? [...]
    Stefan, it looks like most of the replies take the form: yes you can do
    that but it is probably a bad idea.

    It seems I have chosen the wrong verb when I wrote "Can".
    I already knew that it worked at my site, and I should have
    clarified right from the start that my question indeed was
    about whether this has some harmful effects I might not be
    aware of. So I should have asked whether it's a bad idea
    or whether it is good style. Thanks for all answers!

    Could you outline the larger situation where you want to do this? Often
    this kind of response ("yes but don't!") can be a clue that you're

    I can't remember the details now, but I know that I had this
    wish more than once. Then, recently, I got reminded of this
    when I happened to come across a web page where it was being
    discussed. So, unfortunately, I have to give an example now
    that is somewhat contreived.

    The idea is about parameterizing the behavior of a module.
    For example, the module "M" may contain functions that contain
    "input.read()" to get input and "output.write()" to write
    output. Then one would write code like (the following is
    not correct Python code, just pseudo code assuming a possible
    extended Python where one can assigned to a module before
    it's loaded):

    import sys

    M.input = sys.stdin
    M.output = sys.stdout
    import M

    . So now M would use sys.stdin for input and sys.stdout
    for output.

    If someone else would ask this, I'd tell him to use a class:

    import MM
    import sys

    M = MM.moduleclass( input=sys.stdin, output=sys.stdout )

    , but this is another layer of indirection, so it's a bit
    more complicated than the direct approach of parameterizing
    a module.

    BTW: In fact, today, one can do something like the pseudo
    Python from above:

    M.py:

    # I am module 'M'

    print( a )

    def f():
    print( f'f was called. {a=}' );

    , main.py:

    class prepare_module: # this could be hidden in a custom library

    slots = '___20221120111724_module'

    def __init__( self, M ):
    import importlib
    spec = importlib.util.find_spec( M )
    self.___20221120111724_module =\
    importlib.util.module_from_spec( spec )

    def load( self ):
    self.___20221120111724_module.__spec__.loader.exec_module\
    ( self.___20221120111724_module )
    return self.___20221120111724_module

    def __setattr__( self, name, value ):
    if name == "_prepare_module___20221120111724_module":
    object.__setattr__( self, name, value )
    else:
    object.__setattr__\
    ( self.___20221120111724_module, name, value )

    # actual application code

    M = prepare_module( 'M' )
    M.a = 20221120
    M = M.load()
    M.f()

    , output:

    20221120
    f was called. a=20221120

    .

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to [email protected] on Sun Nov 20 12:03:47 2022
    dn <[email protected]> writes:
    In some respects we have the (OP) problem because Python does not have >"interfaces" as a formal component of the language.

    What one can do today is,

    class my_interface( metaclass=abc.ABCMeta ):
    """This interface ..."""

    @abc.abstractmethod
    def method( __self__, *s, **x ):
    """This abstract method ..."""

    # ...

    my_interface.register( my_class )

    # ...

    .

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to [email protected] on Sun Nov 20 12:29:33 2022
    dn <[email protected]> writes:
    A 'standard' solution is to collect all such configuration-data at the
    start of the application, into an object (or other data-structure) - I >usually call it "env" (an instantiation of "Environment").

    Yeah, I had some functions of my library take such an "env",
    which in my library is called "context":

    def python_version_check( major=3, minor=9, context=x_default_context ):
    passed = _sys.version_info >=( major, minor )
    if not passed:
    requirements_info = "This program requires Python " + \
    str( major ) + "." + str( minor )+ "+.\n"
    version_info = "Currently running under Python {}.{}.\n". \
    format( *_sys.version_info[ :2 ] )
    context.warning( requirements_info + version_info )
    return passed

    . But so far I am using "context" only for logging, so I am
    now thinking about replacing with Pythons logging facility.

    One possible application of "context", however, would also be
    normal output, which has to be shown to the user, not only
    logging as in:

    def show_sum( x, y, context=x_default_context ):
    context.print( f'The sum is {x+y}.' )

    . For example, there could by a "GUI context" by which
    "context.print" would append the output to some GUI text
    field. Using the logging facility to output text that must
    be show to the user, would abuse logging somewhat.

    def show_sum( x, y, context=x_default_context ):
    logger.log\
    ( my_custom_level_for_output_to_user, f'The sum is {x+y}.' )

    Or one could "print patch" a module, via (using the class from
    a recent post of mine):

    M = prepare_module( 'M' )
    M.print = my_gui_print_function
    M = M.load()
    M.f()

    and "show_sum" would be simply:

    def show_sum( x, y, context=x_default_context ):
    print( f'The sum is {x+y}.').

    My original question probably was intended to be something
    like: "Today, we can add attributes to a module from the
    outside. How large is the risk that this will be forbidden
    one day, so that all code using this will stop working?".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sun Nov 20 14:37:02 2022
    [email protected] (Stefan Ram) writes:
    M = prepare_module( 'M' )
    M.a = 20221120
    M = M.load()
    M.f()

    PS: I missed than one can usually use the normal import statement
    and then set the parameters after the import:

    import M
    M.a = 20221120

    . Maybe it would be better to do this as follows with an explicit
    function in M1 for this:

    M1.py

    # module "M1"

    def accept_print_function( print_ ):
    global print
    print = print_

    def show_sum( x, y ):
    print( x + y )

    main.py

    import M1

    M1.show_sum( 2, 3 )

    def printer( *args, **kwargs ):
    print( "EXAMPLE PRINTER PRINTS: ", *args, **kwargs )

    M1.accept_print_function( printer )

    M1.show_sum( 2, 3 )

    output

    5
    EXAMPLE PRINTER PRINTS: 5

    So, when a module explicitly is written knowing that certain
    global module variables may be changed by its client, is there
    anything wrong with that?

    Is "M1.accept_print_function( printer )" better in some sense
    than a straight "M1.print = printer"?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dan Kolis@21:1/5 to All on Sun Nov 20 07:51:54 2022
    It's certainly not an "incredibly bad idea", it is a mildly bad idea however. Why be stuck with maybe's and just text strings ?

    Functions as "first class operators" and object oriented languages are a natural pair with a bit of heavy thinking.

    The problem is... there is nobody giving you a 3 line solution without thinking. Its a 7 line solution requiring understanding. One you do it right, then its a 2 line solution !

    Once you construct the bridges; then, in any module you can consider global sharables like so:

    First vague use of functionality
    gi.setAsideArea.NewIdea = 'ok'

    Next usages anywhere !
    gi.setAsideArea.NewIdea = "StateMachine Argon"

    There is no hangover of vague ideas bothering future executions of the code either. This is not some scary file buried in a directory system which needs calling and might be stale, using bad ideas, etc.

    How much easier can a solution be ?

    Regards,
    Daniel B. Kolis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Avi Gross@21:1/5 to [email protected] on Sun Nov 20 10:29:44 2022
    There is no guarantee that argv is consulted earlier in the program than
    other modules will use it for communication.

    Consider a case where a program does look at argv but later wants to call another program using some or all of the components of argv and now there
    are added components there. That could lead to all kinds of problems.

    Some languages have global objects available that you can add to, sort of
    like a dictionary object and as long as you add keys guaranteed to be
    unique, can be used carefully to coordinate between parts of your program.
    Of course, you may also need to use techniques that ensure atomic
    concurrency.

    Reusing argv is a hack that should not be needed.


    On Sat, Nov 19, 2022, 4:37 PM Thomas Passin <[email protected]> wrote:

    On 11/19/2022 4:28 PM, Thomas Passin wrote:
    On 11/19/2022 3:46 PM, Michael F. Stemper wrote:
    On 18/11/2022 04.53, Stefan Ram wrote:
    Can I use "sys.argv" to pass information between modules
    as follows?

    in module A:

    import sys
    sys.argv.append( "Hi there!" )

    in module B:

    import sys
    message = sys.argv[ -1 ]

    I just tried and it appears that one can append to sys.argv. However,
    it seems like an incredibly bad idea.

    For that matter, you can just directly add attributes to the sys module,
    no need to use sys.argv:

    import sys
    sys._extra = 'spam' # Not an exception
    print(sys._extra)
    spam

    Probably not the best idea, though. Better to use some module that you control directly.

    This could be one of those things of which Raymond Chen (The Old New
    Thing) asks "what if everyone did this?". Imagine if every (non-standard-library) module misused sys or sys.argv like this. The
    result could be chaotic.

    Best to put all your own stuff into modules that you yourself control.

    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Roel Schroeven@21:1/5 to Stefan Ram on Sun Nov 20 19:50:24 2022
    Stefan Ram schreef op 20/11/2022 om 11:39:
    The idea is about parameterizing the behavior of a module.
    For example, the module "M" may contain functions that contain
    "input.read()" to get input and "output.write()" to write
    output. Then one would write code like (the following is
    not correct Python code, just pseudo code assuming a possible
    extended Python where one can assigned to a module before
    it's loaded):

    import sys

    M.input = sys.stdin
    M.output = sys.stdout
    import M

    . So now M would use sys.stdin for input and sys.stdout
    for output.
    I feel this is a bad idea. This uses global state for customizing local behavior. Yes, maybe you want to customize behavior in one of your
    modules, or even only in some functions, or maybe in several or even all
    of your modules. But by changing module "M", you're changing it for
    *every* user of it, even for standard library modules or third party
    packages. You can't customize it in different ways in different parts of
    your code. And it's a kind of spooky action at a distance: the behavior
    of a module gets changed by another, possibly completely unrelated,
    module. This has the potential to grossly violate the principle of least surprise.
    If someone else would ask this, I'd tell him to use a class:

    import MM
    import sys

    M = MM.moduleclass( input=sys.stdin, output=sys.stdout )
    That is a *much* better solution, and I would even say it's the only
    acceptable solution.
    , but this is another layer of indirection, so it's a bit
    more complicated than the direct approach of parameterizing
    a module.
    I'm not even sure it's more complicated. It's more explicit, which I like.

    You could have a hybrid approach, like what the random module does. The functions in the random module are actually methods of a global hidden
    instance of class random.Random; if you want random generators with
    separate states you can create your own instance(s) of random.Random, or
    of random.SystemRandom.

    --
    "You can fool some of the people all the time, and all of the people some
    of the time, but you cannot fool all of the people all of the time."
    -- Abraham Lincoln
    "You can fool too many of the people too much of the time."
    -- James Thurber

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Stefan Ram on Mon Nov 21 08:11:30 2022
    On 21/11/2022 01.03, Stefan Ram wrote:
    dn <[email protected]> writes:
    In some respects we have the (OP) problem because Python does not have
    "interfaces" as a formal component of the language.

    What one can do today is,

    class my_interface( metaclass=abc.ABCMeta ):
    """This interface ..."""

    @abc.abstractmethod
    def method( __self__, *s, **x ):
    """This abstract method ..."""

    # ...

    my_interface.register( my_class )

    # ...


    Ugh!

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Roel Schroeven on Sun Nov 20 14:33:01 2022
    On 11/20/2022 1:50 PM, Roel Schroeven wrote:
    Stefan Ram schreef op 20/11/2022 om 11:39:
       The idea is about parameterizing the behavior of a module.
       For example, the module "M" may contain functions that contain
       "input.read()" to get input and "output.write()" to write
       output. Then one would write code like (the following is
       not correct Python code, just pseudo code assuming a possible
       extended Python where one can assigned to a module before
       it's loaded):

    import sys

    M.input = sys.stdin
    M.output = sys.stdout
    import M

       . So now M would use sys.stdin for input and sys.stdout
       for output.
    I feel this is a bad idea. This uses global state for customizing local behavior. Yes, maybe you want to customize behavior in one of your
    modules, or even only in some functions, or maybe in several or even all
    of your modules. But by changing module "M", you're changing it for
    *every* user of it, even for standard library modules or third party packages. You can't customize it in different ways in different parts of
    your code. And it's a kind of spooky action at a distance: the behavior
    of a module gets changed by another, possibly completely unrelated,
    module. This has the potential to grossly violate the principle of least surprise.
       If someone else would ask this, I'd tell him to use a class:

    import MM
    import sys

    M = MM.moduleclass( input=sys.stdin, output=sys.stdout )
    That is a *much* better solution, and I would even say it's the only acceptable solution.
       , but this is another layer of indirection, so it's a bit
       more complicated than the direct approach of parameterizing
       a module.
    I'm not even sure it's more complicated. It's more explicit, which I like.

    You could have a hybrid approach, like what the random module does. The functions in the random module are actually methods of a global hidden instance of class random.Random; if you want random generators with
    separate states you can create your own instance(s) of random.Random, or
    of random.SystemRandom.


    As I wrote, it's another case of "what if everyone did this". e.g.:

    https://devblogs.microsoft.com/oldnewthing/20050607-00/?p=35413 https://devblogs.microsoft.com/oldnewthing/20101125-00/?p=12203

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Roel Schroeven on Sun Nov 20 19:39:35 2022
    Roel Schroeven <[email protected]> writes:
    You could have a hybrid approach, like what the random module does. The >functions in the random module are actually methods of a global hidden >instance of class random.Random; if you want random generators with
    separate states you can create your own instance(s) of random.Random, or
    of random.SystemRandom.

    This seems to be similar to functions like "forward" of the
    module "turtle". I believe the global function "forward" is
    actually calling the method "forward" of a special turtle,
    but one still can create more turtles.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Sun Nov 20 19:56:35 2022
    [email protected] (Stefan Ram) writes:
    Roel Schroeven <[email protected]> writes:
    You could have a hybrid approach, like what the random module does. The >>functions in the random module are actually methods of a global hidden >>instance of class random.Random; if you want random generators with >>separate states you can create your own instance(s) of random.Random, or
    of random.SystemRandom.
    This seems to be similar to functions like "forward" of the
    module "turtle". I believe the global function "forward" is
    actually calling the method "forward" of a special turtle,
    but one still can create more turtles.

    "turtle.py" has a function "_make_global_funcs" that uses
    "exec" to create one globale function for each method of
    a class.

    "random.py" uses "_inst = Random(); seed = _inst.seed;
    random = _inst.random; ..." in the outer scope instead.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Roel Schroeven@21:1/5 to Thomas Passin on Sun Nov 20 22:07:05 2022
    Thomas Passin schreef op 20/11/2022 om 20:33:
    https://devblogs.microsoft.com/oldnewthing/20050607-00/?p=35413 https://devblogs.microsoft.com/oldnewthing/20101125-00/?p=12203

    Now that I think about it, The Old New Thing is also where I got the
    global vs local thing: "Don’t use global state to manage a local
    problem", https://devblogs.microsoft.com/oldnewthing/20081211-00/?p=19873

    --
    "In the old days, writers used to sit in front of a typewriter and stare out of the window. Nowadays, because of the marvels of convergent technology, the thing
    you type on and the window you stare out of are now the same thing.”
    -- Douglas Adams

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dan Kolis@21:1/5 to All on Sun Nov 20 13:16:18 2022
    Using sys.stdout / is simply nonsense. The more I think about it, the more I realise how bad it is.

    Going on about it endlessly seems pointless.

    If the even mini threading thing is turned on, now what ? some other module eats the message intended for a different module ? A state machine with its own matching code in sends and receives to reuse the unwanted singular value ?

    The precise rules for establishing a variable without the global keyword is not obvious, or catcat of anything by leaving a empty set dangling initially.

    *especially* if the program is fundamentally open ended, that is, there could be considerable new functions sharing ideas all over, planning ahead for as good 45 seconds is a lot better then endless hacking any old way.

    1) Make a variable in a module known to be a shared item. Named for that specifically.
    def Mt() {}
    IoDot = {} # Once before program does anything... in global. ref import global as gi later.

    2) Create highly generalised speculative named ideas init each variable once with a {}
    ioDot.weights = Mt{} ; ( I make it a local method so the method can stand alone for unit testing )

    3) Uniformly ref it with a import statement. in all 'other' modules

    4) When a shared idea is apparent concat a new named portion to the name for this purpose. Then use those fairly without fussing as required. If one scares you, set it to {} after some scary moment if you are feeling fussy.

    5) All 'ideas' will be at a 3rd or more subsid level in naming. ex:

    gi.IoDot.weights.trucks = whatever
    gi.IoDot.weights.cars = whatever

    gi.toastDot.warnings.tooHeavy
    gi.toastDot.warnings.isOk

    These can all be any kind of object. So easy

    I have a very sizable highly generalized program using this and have not found any defect in doing so.

    Regs
    Dan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dan Kolis@21:1/5 to All on Sun Nov 20 15:07:22 2022
    Its advice, I don't think the style issue is particularly important.

    If you understand its meaning, it achieves my purpose. If you don't I you're perhaps not a programmer...

    I like the abruptness of technical writing as a style, actually. If that is how machine learning ( aka 'A.I.' ) tends to compose messages, this seems mostly compatible with the sorts of written material I both make and consume.

    https://interestingliterature.com/2017/03/10-of-the-best-poems-about-forests-and-trees/

    The whisper of the aspens is not drowned,
    And over lightless pane and footless road,
    Empty as sky, with every other sound
    Not ceasing, calls their ghosts from their abode,

    there's one for you... a click will get you nine more. but none will help you write a better, more maintainable program.

    Regards,
    Dan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Dan Kolis on Mon Nov 21 09:40:45 2022
    On Mon, 21 Nov 2022 at 09:37, Dan Kolis <[email protected]> wrote:

    Using sys.stdout / is simply nonsense. The more I think about it, the more I realise how bad it is.

    Going on about it endlessly seems pointless.

    If the even mini threading thing is turned on, now what ? some other module eats the message intended for a different module ? A state machine with its own matching code in sends and receives to reuse the unwanted singular value ?

    The precise rules for establishing a variable without the global keyword is not obvious, or catcat of anything by leaving a empty set dangling initially.

    *especially* if the program is fundamentally open ended, that is, there could be considerable new functions sharing ideas all over, planning ahead for as good 45 seconds is a lot better then endless hacking any old way.

    You should print this out and get it on a t-shirt. It's a perfect
    example of AI-generated text.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Roel Schroeven on Sun Nov 20 22:01:40 2022
    On 11/20/2022 4:07 PM, Roel Schroeven wrote:
    Thomas Passin schreef op 20/11/2022 om 20:33:
    https://devblogs.microsoft.com/oldnewthing/20050607-00/?p=35413
    https://devblogs.microsoft.com/oldnewthing/20101125-00/?p=12203

    Now that I think about it, The Old New Thing is also where I got the
    global vs local thing: "Don’t use global state to manage a local
    problem", https://devblogs.microsoft.com/oldnewthing/20081211-00/?p=19873


    Bingo!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to All on Mon Nov 21 00:12:25 2022
    On 11/21/2022 12:01 AM, dn wrote:
    On 21/11/2022 12.07, Dan Kolis wrote:
    If you understand its meaning, it achieves my purpose. If you don't I
    you're perhaps not a programmer...

    Ouch!

    Does the first sentence imply who is the more important person in the interaction? Does the second further the idea that anyone/everyone who
    is not at your 'level' has no worth?


    Folks, this is getting into ad hominem territory. I suggest it's time
    to end the thread, since it's no longer productive.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Dan Kolis on Mon Nov 21 18:01:33 2022
    On 21/11/2022 12.07, Dan Kolis wrote:
    If you understand its meaning, it achieves my purpose. If you don't I you're perhaps not a programmer...

    Ouch!

    Does the first sentence imply who is the more important person in the interaction? Does the second further the idea that anyone/everyone who
    is not at your 'level' has no worth?

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Stefan Ram on Mon Nov 21 18:24:41 2022
    On 21/11/2022 01.29, Stefan Ram wrote:
    dn <[email protected]> writes:
    A 'standard' solution is to collect all such configuration-data at the
    start of the application, into an object (or other data-structure) - I
    usually call it "env" (an instantiation of "Environment").

    Yeah, I had some functions of my library take such an "env",
    which in my library is called "context":

    def python_version_check( major=3, minor=9, context=x_default_context ):
    passed = _sys.version_info >=( major, minor )
    if not passed:
    requirements_info = "This program requires Python " + \
    str( major ) + "." + str( minor )+ "+.\n"
    version_info = "Currently running under Python {}.{}.\n". \
    format( *_sys.version_info[ :2 ] )
    context.warning( requirements_info + version_info )
    return passed

    . But so far I am using "context" only for logging, so I am
    now thinking about replacing with Pythons logging facility.

    One possible application of "context", however, would also be
    normal output, which has to be shown to the user, not only
    logging as in:

    def show_sum( x, y, context=x_default_context ):
    context.print( f'The sum is {x+y}.' )

    . For example, there could by a "GUI context" by which
    "context.print" would append the output to some GUI text
    field. Using the logging facility to output text that must
    be show to the user, would abuse logging somewhat.

    def show_sum( x, y, context=x_default_context ):
    logger.log\
    ( my_custom_level_for_output_to_user, f'The sum is {x+y}.' )

    Or one could "print patch" a module, via (using the class from
    a recent post of mine):

    M = prepare_module( 'M' )
    M.print = my_gui_print_function
    M = M.load()
    M.f()

    and "show_sum" would be simply:

    def show_sum( x, y, context=x_default_context ):
    print( f'The sum is {x+y}.').

    My original question probably was intended to be something
    like: "Today, we can add attributes to a module from the
    outside. How large is the risk that this will be forbidden
    one day, so that all code using this will stop working?".


    Am put-off by the 'smell' of subverting/adapting names like print() = surprise/confusion factor - but I think I understand where you're going.

    What about an ABC which is inherited by two classes. One class handles
    all the detail of output to GUI. The other, similarly, output to the
    terminal, log, (whatever). The ABC should require an output() method,
    with suitable signature. The two classes will vary on the fine detail of
    the HOW, leaving the calling-routine to produce the WHAT.

    Now, at the config stage, take the instructions to define whichever the
    user prefers, and instantiate that class. Then the 'calling-routine' can
    use the instantiated object as an interface to whichever type of output.

    If the choices on-offer include not just either/or, but also 'both of
    the above'. The instantiation would need to be a class which called both class's output() method serially.


    Your use of the word "context" provoked some thought. (you don't know
    just how dangerous that could become!)

    In many ways, and as described, an Environment/context class could be
    very easily coded with formal __enter__() and __exit__() methods. The
    mainline might then become:

    with Environment() as env:
    # processing

    There would be no need to explicitly prevent any 'processing' if the
    set-up doesn't work, because that context manager class will handle it all!

    NB haven't had time to try this as a refactoring exercise.

    Is this how you implement?

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to [email protected] on Mon Nov 21 16:46:50 2022
    On Mon, 21 Nov 2022 at 16:26, dn <[email protected]> wrote:
    Am put-off by the 'smell' of subverting/adapting names like print() = surprise/confusion factor - but I think I understand where you're going.

    To be fair, redefining the "print" function IS one of the reasons that
    it's no longer a statement. Though I would generally recommend
    maintaining its signature and purpose.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to [email protected] on Mon Nov 21 09:03:12 2022
    dn <[email protected]> writes:
    Now, at the config stage, take the instructions to define whichever the
    user prefers, and instantiate that class. Then the 'calling-routine' can
    use the instantiated object as an interface to whichever type of output.

    I had many different functions that are supposed to take
    a "context" argument. If I would make them all methods of
    a class with a "context" field, that would be a huge class
    containing methods with many different purposes, which
    reminds of the "anti pattern" "God class".

    with Environment() as env:
    # processing
    There would be no need to explicitly prevent any 'processing' if the
    set-up doesn't work, because that context manager class will handle it all!

    Yes, but my problem was not so much with setting up the env,
    but with passing it to many library functions.

    Is this how you implement?

    I'm not sure whether I understand the meaning of this question.

    My library had a "console context" (before I started to use
    the Python logging facility instead). That console context was
    the default for output of progress and error messages.

    A client had the possibility to call functions with a custom
    context, and then the function would use this custom context
    for progress and error messages. The custom context could
    direct those message to a text field in a GUI, for example.

    Instead of passing this custom context to many library
    functions, it might be simpler to "pass it to the library
    once". This could be done via:

    import library
    library.context = my_GUI_context

    , but I wonder whether this "writing into another module"
    is really possible in every Python implementation and whether
    it will still be supported in the future. I do not see such
    a pattern being used with the standard packages and suppose
    that there might be a reason for this!

    The same question applies to the more advanced technique of
    using "importlib.util.find_spec", "importlib.util.module_from_spec",
    and ".__spec__.loader.exec_module" to even support having
    different instances of a single module with different globals.

    I can now formulate my question this way:

    Many functions of a library have in their source code calls
    like "PRINT( f'Done. Output was written to {filename}.' )".
    The library uses "print" as a default for "PRINT", but
    should explicitly support clients substituting a custom
    implementation to be used for "PRINT". What's the best way
    for the client to "pass" his custom implementation to the
    library (which is a package or a module)?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to All on Mon Nov 21 00:53:40 2022
    On 11/21/2022 12:24 AM, dn wrote:
    My original question probably was intended to be something
       like: "Today, we can add attributes to a module from the
       outside. How large is the risk that this will be forbidden
       one day, so that all code using this will stop working?".

    This can happen today if, for example, a class is changed to use slots
    for everything. Between slots and type checking, it can become
    impossible to add an arbitrary attribute. *You* may be able to avoid
    this, but if you use someone else's modules or classes it could happen
    at any time.

    I might regret the loss of being able to assign an arbitrary attribute
    wherever I like, but for complex libraries, it is probably a good idea
    in the long run.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Barry@21:1/5 to All on Mon Nov 21 22:17:45 2022
    On 21 Nov 2022, at 21:23, [email protected] wrote:

    dn <[email protected]> writes:
    Now, at the config stage, take the instructions to define whichever the
    user prefers, and instantiate that class. Then the 'calling-routine' can
    use the instantiated object as an interface to whichever type of output.

    I had many different functions that are supposed to take
    a "context" argument. If I would make them all methods of
    a class with a "context" field, that would be a huge class
    containing methods with many different purposes, which
    reminds of the "anti pattern" "God class".

    Do you haves lots of free standing functions? Are all these functions
    not part of classes?


    with Environment() as env:
    # processing
    There would be no need to explicitly prevent any 'processing' if the
    set-up doesn't work, because that context manager class will handle it all!

    Yes, but my problem was not so much with setting up the env,
    but with passing it to many library functions.

    Are you writing procedural code or object oriented? Why do you have so
    many functions outside of a small number of classes?


    Is this how you implement?

    I'm not sure whether I understand the meaning of this question.

    You appear not to be doing object oriented design.


    My library had a "console context" (before I started to use
    the Python logging facility instead). That console context was
    the default for output of progress and error messages.

    A client had the possibility to call functions with a custom
    context, and then the function would use this custom context
    for progress and error messages. The custom context could
    direct those message to a text field in a GUI, for example.

    Instead of passing this custom context to many library
    functions, it might be simpler to "pass it to the library
    once". This could be done via:

    import library
    library.context = my_GUI_context

    That is not oo design. I get the feeling that you need a better understanding of how to structure a non-trivia library.

    If you need the context object then you must pass it around.


    , but I wonder whether this "writing into another module"
    is really possible in every Python implementation and whether
    it will still be supported in the future. I do not see such
    a pattern being used with the standard packages and suppose
    that there might be a reason for this!

    The same question applies to the more advanced technique of
    using "importlib.util.find_spec", "importlib.util.module_from_spec",
    and ".__spec__.loader.exec_module" to even support having
    different instances of a single module with different globals.

    I can now formulate my question this way:

    Many functions of a library have in their source code calls
    like "PRINT( f'Done. Output was written to {filename}.' )".
    The library uses "print" as a default for "PRINT", but
    should explicitly support clients substituting a custom
    implementation to be used for "PRINT". What's the best way
    for the client to "pass" his custom implementation to the
    library (which is a package or a module)?

    Each place you have PRINT you need to have context.print calls.
    You said above that you have, or had, such an object - pass it around and use it.

    If passing it around is the problem then you need to look at why you code
    has that problem.

    Barry



    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)