A startup puzzle

Discussion in 'Python' started by Edward K. Ream, Sep 29, 2003.

  1. I've just about convinced myself there is no good, clean solution to the
    following puzzle. I wonder if you agree.

    1. My app has a module called leoGlobals that contains often-used global
    functions. All of Leo's source files start with:

    from leoGlobals import *

    I don't want to discuss whether this is good style: it is simple and it
    works well for me :)

    2. All code accesses the singleton application object using the app()
    method in leoGlobals.

    3. To make the code cleaner looking, I would really like the code to be
    able to access an app global instead of the app() function. This has
    nothing to do with speed: it's simply that there are lots of references to
    app() in the code, and there is soon going to be a lot more references to
    app.gui.x() and app.gui.y() etc.

    As a workaround, many methods and functions assign a = app(), but I would
    like to avoid this step.

    4. Alas, it does not seem possible to initialize an app global in
    leoGlobals. The reason is simple:

    from leoGlobals import *

    caches the value of app at the time the import is done. But the startup
    code that creates the app "global" (really an attribute of the leoGlobals
    module) must do _other_ imports.

    For example, doing the following at the top of leoGlobals doesn't work:

    import leoApp
    app = leoApp.leoApp() # construct the app instance.

    Indeed, the leoApp module will be imported before the assignment of app.
    Moreover, the leoApp module does other imports, and all the app variables in
    those modules will be uninitialized.

    It would be horrible style to place detailed constraints on the order in
    which modules get imported, and I'm not sure even that would work.

    Any ideas for a clean solution? Thanks.

    Edward

    P.S. The solution must work in 2.1, 2.2 and 2.3.

    EKR
    --------------------------------------------------------------------
    Edward K. Ream email:
    Leo: Literate Editor with Outlines
    Leo: http://webpages.charter.net/edreamleo/front.html
    --------------------------------------------------------------------
     
    Edward K. Ream, Sep 29, 2003
    #1
    1. Advertising

  2. Edward K. Ream

    Peter Otten Guest

    Edward K. Ream wrote:

    > I've just about convinced myself there is no good, clean solution to the
    > following puzzle. I wonder if you agree.


    If I understand you correctly, you do

    leoGlobals.py
    _app=None
    def app():
    global _app
    if not _app:
    # other code
    _app = Application()
    return _app

    leoMain.py
    from leoGlobals import *
    app = app()
    app.mainLoop()

    leoOther.py
    from leoGlobals import *

    app().doSomething()


    Does it happen that your program runs without ever creating the Application
    instance? If not, there's no point in lazy creation:

    leoGlobals.py
    app=None
    def createApp():
    global app
    assert not app
    app = Application()

    leoMain.py
    from leoGlobals import *
    createApp()
    app.mainLoop()

    leoOther.py
    from leoGlobals import *
    # this works iff you can ensure that leoMain.py is the
    # only "entry point" to your application
    app.doSomething()


    If I missed something, it would probably help if you post similar code
    fragments to show where the above scheme would fail to work.

    Peter
     
    Peter Otten, Sep 29, 2003
    #2
    1. Advertising

  3. On Mon, 29 Sep 2003 11:31:05 -0500, "Edward K. Ream"
    <> wrote:

    >Any ideas for a clean solution? Thanks.


    I am not sure that I understand what you are saying, but I'll make a
    quick suggestion...

    Perhaps 'app' can be a global variable within 'leoGlobals', but
    assigned the value 'None' when the module is imported. Your
    initialisation code can then reassign the variable at the appropriate
    time.

    If you refer to 'app.whatever' while 'app' is still 'None' you should
    get an exception.

    That's not what most people mean by 'singleton' of course, but if you
    can be sure of your initialisation sequence it can probably do the
    job.


    --
    Steve Horne

    steve at ninereeds dot fsnet dot co dot uk
     
    Stephen Horne, Sep 29, 2003
    #3
  4. Stephen Horne <$$$$$$$$$$$$$$$$$@$$$$$$$$$$$$$$$$$$$$.co.uk> writes:

    > On Mon, 29 Sep 2003 11:31:05 -0500, "Edward K. Ream"
    > <> wrote:
    >
    > >Any ideas for a clean solution? Thanks.

    >
    > I am not sure that I understand what you are saying, but I'll make a
    > quick suggestion...
    >
    > Perhaps 'app' can be a global variable within 'leoGlobals', but
    > assigned the value 'None' when the module is imported. Your
    > initialisation code can then reassign the variable at the appropriate
    > time.


    This wont work.

    --- a.py ---
    a = None
    --- b.py ---
    import a
    a.a = 1
    --- c.py ---
    from a import a
    import b
    print a

    running c.py will print "None". Names, objects and bindings, remember
    :)

    Cheers,
    mwh

    --
    Or if you happen to be resigned to the size of your trouser
    snake and would rather not be reminded of it, training a shared
    classifier to reject penis-enlargement spam stops Barry from
    getting the help he so desperately needs. -- Tim Peters, c.l.python
     
    Michael Hudson, Sep 29, 2003
    #4
  5. On Mon, 29 Sep 2003 18:40:47 GMT, Michael Hudson <>
    wrote:

    >Stephen Horne <$$$$$$$$$$$$$$$$$@$$$$$$$$$$$$$$$$$$$$.co.uk> writes:
    >
    >> On Mon, 29 Sep 2003 11:31:05 -0500, "Edward K. Ream"
    >> <> wrote:
    >>
    >> >Any ideas for a clean solution? Thanks.

    >>
    >> I am not sure that I understand what you are saying, but I'll make a
    >> quick suggestion...
    >>
    >> Perhaps 'app' can be a global variable within 'leoGlobals', but
    >> assigned the value 'None' when the module is imported. Your
    >> initialisation code can then reassign the variable at the appropriate
    >> time.

    >
    >This wont work.
    >
    >--- a.py ---
    >a = None
    >--- b.py ---
    >import a
    >a.a = 1
    >--- c.py ---
    >from a import a
    >import b
    >print a
    >
    >running c.py will print "None". Names, objects and bindings, remember
    >:)


    Oops - I didn't realise import worked like that.

    Thanks.


    --
    Steve Horne

    steve at ninereeds dot fsnet dot co dot uk
     
    Stephen Horne, Sep 29, 2003
    #5
  6. Edward K. Ream

    Peter Otten Guest

    Peter Otten wrote:

    Oops! My consideration does not work with
    from leoGlobals import *
    as the rebinding is not propagated. The following seems to work although I
    do not know if this is approved Python:

    leoGlobals.py, second try:
    from leoApp import Application

    class Dummy(object):
    pass

    app = Dummy()

    def createApp():
    app.__class__ = Application
    app.__dict__ = Application().__dict__


    Peter
     
    Peter Otten, Sep 29, 2003
    #6
  7. In article <>,
    "Edward K. Ream" <> wrote:

    > I've just about convinced myself there is no good, clean solution to the
    > following puzzle. I wonder if you agree.

    [snip]
    > For example, doing the following at the top of leoGlobals doesn't work:
    >
    > import leoApp
    > app = leoApp.leoApp() # construct the app instance.
    >
    > Indeed, the leoApp module will be imported before the assignment of app.
    > Moreover, the leoApp module does other imports, and all the app variables in
    > those modules will be uninitialized.
    >
    > It would be horrible style to place detailed constraints on the order in
    > which modules get imported, and I'm not sure even that would work.
    >
    > Any ideas for a clean solution? Thanks.


    Maybe I'm missing something, but it seems like you want some sort of
    lazy initialization thing here. Perhaps using a proxy object sort of
    like this might work:


    realApp = None
    class LeoProxy:
    def __getattr__(self,attr):
    if not realApp:
    import leoApp
    realApp = leoApp.leoApp()
    return getattr(realApp, attr)

    app = LeoProxy()


    Then you can import that module as often as you want, but the first time
    you do something with leoApp.app (i.e., "leoApp.app.doSomething()"), it
    will only then call the "real" function to create it (and then proxy it
    over as needed)
     
    Glenn Andreas, Sep 29, 2003
    #7
  8. Edward K. Ream wrote:

    >I've just about convinced myself there is no good, clean solution to the
    >following puzzle. I wonder if you agree.
    >
    >1. My app has a module called leoGlobals that contains often-used global
    >functions. All of Leo's source files start with:
    >
    >from leoGlobals import *
    >
    >I don't want to discuss whether this is good style: it is simple and it
    >works well for me :)
    >
    >

    Okay, we'll take that as a given then.

    >2. All code accesses the singleton application object using the app()
    >method in leoGlobals.
    >
    >

    Sure, implements late-binding via indirection.

    >3. To make the code cleaner looking, I would really like the code to be
    >able to access an app global instead of the app() function. This has
    >nothing to do with speed: it's simply that there are lots of references to
    >app() in the code, and there is soon going to be a lot more references to
    >app.gui.x() and app.gui.y() etc.
    >
    >As a workaround, many methods and functions assign a = app(), but I would
    >like to avoid this step.
    >
    >

    This can be done by creating a built-in variable e.g. APPLICATION, which
    is an application-wide variable, like so:

    def __install( self ):
    """Install self into the builtin module"""
    __builtin__.APPLICATION = self

    note that this *doesn't* help if there really are hidden dependencies in
    your modules on having the APPLICATION object defined, but given your
    description of the architecture, that doesn't appear to be the case.

    >4. Alas, it does not seem possible to initialize an app global in
    >leoGlobals. The reason is simple:
    >
    >from leoGlobals import *
    >
    >caches the value of app at the time the import is done. But the startup
    >code that creates the app "global" (really an attribute of the leoGlobals
    >module) must do _other_ imports.
    >
    >For example, doing the following at the top of leoGlobals doesn't work:
    >
    >import leoApp
    >app = leoApp.leoApp() # construct the app instance.
    >
    >Indeed, the leoApp module will be imported before the assignment of app.
    >Moreover, the leoApp module does other imports, and all the app variables in
    >those modules will be uninitialized.
    >
    >It would be horrible style to place detailed constraints on the order in
    >which modules get imported, and I'm not sure even that would work.
    >
    >

    Such constraints will exist. Any module which relies on the existence
    of an initialised APPLICATION variable must be imported after the
    creation of that variable. You construct the app so that the
    APPLICATION is created ASAP and that becomes a minimal restriction,
    since your code is working, it's already passed that level of
    restriction :) .

    The alternatives to such restrictions are pretty grotty; defered
    execution of suites of code that would likely require Stackless Python
    and a decent masters thesis working out the calculus of dependency
    resolution (what with needing to defer or speculatively execute each
    path in the code dependant on the app object's operation). Luckily
    that's all just academic for your project :) .

    >Any ideas for a clean solution? Thanks.
    >
    >

    Cleanliness is in the eye of the beholder. I don't really like the
    APPLICATION-object "pattern", but it is very convenient in many simple
    cases. Just about everything else I've seen either requires something
    exotic (e.g. proxy objects implementing the late-binding indirection by
    pretending to be the app object (raising errors if anything attempts to
    use the object before it's bound)), or the solution you started with,
    i.e. using function's built-in late-binding to implement it.

    HTH,
    Mike

    _______________________________________
    Mike C. Fletcher
    Designer, VR Plumber, Coder
    http://members.rogers.com/mcfletch/
     
    Mike C. Fletcher, Sep 29, 2003
    #8
  9. On Mon, 29 Sep 2003 11:31:05 -0500, "Edward K. Ream" <> wrote:

    >I've just about convinced myself there is no good, clean solution to the
    >following puzzle. I wonder if you agree.
    >
    >1. My app has a module called leoGlobals that contains often-used global
    >functions. All of Leo's source files start with:
    >
    >from leoGlobals import *
    >
    >I don't want to discuss whether this is good style: it is simple and it
    >works well for me :)
    >
    >2. All code accesses the singleton application object using the app()
    >method in leoGlobals.
    >
    >3. To make the code cleaner looking, I would really like the code to be
    >able to access an app global instead of the app() function. This has
    >nothing to do with speed: it's simply that there are lots of references to
    >app() in the code, and there is soon going to be a lot more references to
    >app.gui.x() and app.gui.y() etc.
    >
    >As a workaround, many methods and functions assign a = app(), but I would
    >like to avoid this step.
    >

    How about an app proxy object that just passes through attribute accesses later?
    That way you can immediately in leoGlobal create something that will have the
    app name binding that all importers of leoGlobal can copy the binding to, but
    which won't/shouldn't get used 'till the app behind it is initialized.

    (see code at end)

    >4. Alas, it does not seem possible to initialize an app global in
    >leoGlobals. The reason is simple:
    >
    >from leoGlobals import *
    >
    >caches the value of app at the time the import is done. But the startup
    >code that creates the app "global" (really an attribute of the leoGlobals
    >module) must do _other_ imports.
    >

    Ok, see code below

    >For example, doing the following at the top of leoGlobals doesn't work:
    >
    >import leoApp
    >app = leoApp.leoApp() # construct the app instance.


    Well, plain vanilla it works, but not if leoApp() wants to import leoGlobals and expect app
    to be already bound.

    But see code below.

    >
    >Indeed, the leoApp module will be imported before the assignment of app.

    Well, that's the order you wrote it ;-) I mean, no prob so far, right?

    >Moreover, the leoApp module does other imports, and all the app variables in
    >those modules will be uninitialized.

    Because _they_ do from leoGlobals import * and leoGlobals is not ready
    for that yet.
    >
    >It would be horrible style to place detailed constraints on the order in
    >which modules get imported, and I'm not sure even that would work.
    >
    >Any ideas for a clean solution? Thanks.


    Well, I'm just exploring your problem in its particular form right now, so
    I'm not sure what can be guaranteed, but it looks like when you import leoApp
    and it triggers a rash of "from leoGlobals import *", the leoGlobals in effect
    will be a snapshot of the leoGlobal module dict at that time, so what has been
    defined/bound will be visible, but whatever has not, won't, e.g., the appInvisible
    in leoGlobals is visible to my interactive from leoGlobals import *, but not
    via the app method that returns the global dict _it_ sees. The latter does have bindings
    for the other globals though.

    There may be more to it than that, but that's what I get from experimenting as below:

    ===< leoGlobals.py >======================
    class AppWrap(object):
    def setapp(self, theRealApp): self.theRealApp = theRealApp
    def __getattr__(self, name): return getattr(self.__dict__['theRealApp'], name)
    app = AppWrap()
    K1k = 1024
    whatever = 'whatever value'
    app.setapp(__import__('leoApp').leoApp())
    appInvisible = 'App import dependents do not see this in their leoGlobals'
    ==========================================

    ===< leoApp.py >==========================
    from leoGlobals import *
    class leoApp(object):
    def foometh(self): print 'foometh of %r called.'%self
    def getapp(self): return app # from leoGlobals import above
    def peek(self): return locals(), globals()
    ==========================================

    Experimental result:

    >>> from leoGlobals import *
    >>> dir()

    ['AppWrap', 'K1k', '__builtins__', '__doc__', '__name__', 'app', 'appInvisible', 'whatever']
    >>> app

    <leoGlobals.AppWrap object at 0x008F9FD0>
    >>> app.foometh()

    foometh of <leoApp.leoApp object at 0x008F9E70> called.
    >>> app.getapp

    <bound method leoApp.getapp of <leoApp.leoApp object at 0x008F9E70>>
    >>> app.getapp().foometh()

    foometh of <leoApp.leoApp object at 0x008F9E70> called.

    Now we'll peek at the globals in the leoApp module via the peek method

    >>> app.peek()[1]['whatever']

    'whatever value'
    >>> app.peek()[1]['K1k']

    1024

    Those were visible, but let's try that last one ;-)

    >>> app.peek()[1]['appInvisible']

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    KeyError: 'appInvisible'

    But here in the interactive environment, the import * got the final state of leoGlobals, so

    >>> appInvisible

    'App import dependents do not see this in their leoGlobals'

    And the app binding seen in other modules should be ok (though not ok to use until app.setapp
    has been called, so you will have to watch dependencies in the way you order things in leoGlobals --
    you want app=AppWrap() at the top, and presumably app.setapp(...) at the end, if it's going
    to trigger imports that want to see everything preceding).

    Here is an access to an app method via the global imported in another (leoApp) module,
    though of course this example is otherwise silly ;-)

    >>> app.peek()[1]['app']

    <leoGlobals.AppWrap object at 0x00902250>
    >>> app.peek()[1]['app'].foometh()

    foometh of <leoApp.leoApp object at 0x00902450> called.

    I guess you will lose a little speedwise by going through the wrapped app name, but
    does that let you spell things the way you wanted?

    HTH

    Regards,
    Bengt Richter
     
    Bengt Richter, Sep 29, 2003
    #9
  10. Edward K. Ream

    Hans Nowak Guest

    Edward K. Ream wrote:

    > I've just about convinced myself there is no good, clean solution to the
    > following puzzle. I wonder if you agree.
    >
    > 1. My app has a module called leoGlobals that contains often-used global
    > functions. All of Leo's source files start with:
    >
    > from leoGlobals import *
    >
    > I don't want to discuss whether this is good style: it is simple and it
    > works well for me :)


    Fair enough, but it's not just a matter of style... using something like

    import leoGlobals as g

    would probably have avoided this problem, since you can do:

    import leoGlobals as g

    # later...
    g.app = leoApp.leoApp()
    # every module that imported leoGlobals now knows g.app as well

    Cheers,

    --
    Hans ()
    http://zephyrfalcon.org/
     
    Hans Nowak, Sep 29, 2003
    #10
  11. > Perhaps using a proxy object...might work:

    Great idea! Some complications:

    1. Sometimes the test "if not realApp:" causes unbounded recursion. To
    avoid any possibility of this happening the startup code just creates the
    app object before any code actually uses the app proxies. This is easily
    done.

    2. A __call__ method in the proxy allows the code to use either app().x or
    app.x.

    In short, the following pattern appears like it will work in all my modules:

    from leoGlobals import *
    app = leoProxy() # leoProxy defined in leoGlobals
    # Now the code can reference either app.x or app().x.

    To do this, I use the following code:

    gApp = None # Set before any reference to proxy.
    class leoProxy:
    def __getattr__(self,attr):
    return getattr(gApp,attr)
    def __call__(self):
    return gApp

    Many thanks for this great idea.

    Edward
    --------------------------------------------------------------------
    Edward K. Ream email:
    Leo: Literate Editor with Outlines
    Leo: http://webpages.charter.net/edreamleo/front.html
    --------------------------------------------------------------------
     
    Edward K. Ream, Sep 29, 2003
    #11
  12. Edward K. Ream

    Aahz Guest

    In article <>,
    Edward K. Ream <> wrote:
    >
    >I've just about convinced myself there is no good, clean solution to the
    >following puzzle. I wonder if you agree.
    >
    >1. My app has a module called leoGlobals that contains often-used global
    >functions. All of Leo's source files start with:
    >
    >from leoGlobals import *
    >
    >I don't want to discuss whether this is good style: it is simple and it
    >works well for me :)


    Okay, I won't discuss, I'll just tell you that this is a recipe for
    giving yourself a headache. Have fun. ("Doctor, it hurts when I do
    this." "Well, stop doing that, then.")
    --
    Aahz () <*> http://www.pythoncraft.com/

    "It is easier to optimize correct code than to correct optimized code."
    --Bill Harlan
     
    Aahz, Sep 29, 2003
    #12
  13. On Mon, 29 Sep 2003 16:27:39 -0500, "Edward K. Ream" <> wrote:

    >> Perhaps using a proxy object...might work:

    >
    >Great idea! Some complications:
    >
    >1. Sometimes the test "if not realApp:" causes unbounded recursion. To
    >avoid any possibility of this happening the startup code just creates the
    >app object before any code actually uses the app proxies. This is easily
    >done.

    1a. I suspect Glenn's code would also need a global realApp in the __getattr__ method,
    or it would just keep seeing a global realApp==None and recreating the app instance
    to a local realApp that disappears after its desired attribute is returned.
    (BTW my version just let an exception happen if use was attempted before setting
    the real app reference).
    >
    >2. A __call__ method in the proxy allows the code to use either app().x or
    >app.x.
    >
    >In short, the following pattern appears like it will work in all my modules:
    >
    >from leoGlobals import *
    >app = leoProxy() # leoProxy defined in leoGlobals

    ISTM it would be safe to put the above line in leoGlobals at the top, after
    the class definition, and then app would just come in with the import *,
    so in general your modules will only need the one-line from leoGlobals import *.

    (see my post for more info. BTW, I didn't see Glenn's post 'til after, honest ;-)

    ># Now the code can reference either app.x or app().x.

    Cool. Gives you some backwards compatibility I guess.

    >
    >To do this, I use the following code:
    >

    Since the code is only executed once on import, I think you could put this
    at the top of leoGlobals

    >gApp = None # Set before any reference to proxy.
    >class leoProxy:
    > def __getattr__(self,attr):
    > return getattr(gApp,attr)
    > def __call__(self):
    > return gApp

    (Unlike Glenn's code, this doesn't need a global gApp declaration).

    and then at the bottom of leoGlobals you could do (untested)
    gApp = __import__('leoApp').leoApp()

    Or you could (untested) even do it later from somewhere else as
    leoGlobals.gApp = __import__('leoApp').leoApp()

    >
    >Many thanks for this great idea.


    I should've just blurted and not fooled with testing, I guess ;-)

    Actually, I wonder whether the snap-shot effect you seem to get in
    a secondary module's import of the module whose import code you are in
    the middle of executing is something one can depend on in detail not to change.
    (though I'm not sure what kind of change could be reasonable ;-)

    And what happens if there are side effects from the secondary activity
    that puts something in the module globals -- will that show up in subsequent
    imports immediately? I guess it comes down to whether import locks in a
    module instance and ties it to sys.modules immediately, so its state can
    be modified and viewed incrementally. It seems so. I guess the dict involved
    is the environment that the imported module code gets executed in.

    Further .02USD are in my other post ;-)

    Regards,
    Bengt Richter
     
    Bengt Richter, Sep 30, 2003
    #13
  14. Edward K. Ream

    Steve Holden Guest

    "Edward K. Ream" <> wrote in message
    news:...
    > > Perhaps using a proxy object...might work:

    >
    > Great idea! Some complications:
    >
    > 1. Sometimes the test "if not realApp:" causes unbounded recursion. To
    > avoid any possibility of this happening the startup code just creates the
    > app object before any code actually uses the app proxies. This is easily
    > done.
    >
    > 2. A __call__ method in the proxy allows the code to use either app().x or
    > app.x.
    >
    > In short, the following pattern appears like it will work in all my

    modules:
    >
    > from leoGlobals import *
    > app = leoProxy() # leoProxy defined in leoGlobals
    > # Now the code can reference either app.x or app().x.
    >
    > To do this, I use the following code:
    >
    > gApp = None # Set before any reference to proxy.
    > class leoProxy:
    > def __getattr__(self,attr):
    > return getattr(gApp,attr)
    > def __call__(self):
    > return gApp
    >
    > Many thanks for this great idea.
    >


    I've followed this thread, and I'm having trouble understanding why nobody's
    suggested using Alex martelli's "borg" pattern, which he originally called a
    "statel;ess proxy", where all objects of a given type share the same state
    information. Sounds to me that's what you really want, no?

    This would mean that in leo_global you would have something like this:

    leo_global.py:
    -------------
    class Borg(object):
    _state = {}
    def __new__(cls, *p, **k):
    self = object.__new__(cls, *p, **k)
    self.__dict__ = cls._state
    return self


    module1.py
    -------------
    from leo_global import Borg

    myborg = Borg()
    myborg.var1 = "This is var 1"

    import module2

    print "Module 1's borg has var1 =", myborg.var1, id(myborg.var1)
    print "Module 1's borg has var2 =", myborg.var2, id(myborg.var2)


    module2.py:
    -------------
    from leo_global import Borg

    myborg = Borg()
    myborg.var2 = "This is var 2"

    print "Module 2's borg has var1 =", myborg.var1, id(myborg.var1)
    print "Module 2's borg has var2 =", myborg.var2, id(myborg.var2)

    The result of all this appears to be what you want: a simple way of creating
    an easily-referenced shared state. Vide:

    C:\Steve\Projects\Python>python module1.py
    Module 2's borg has var1 = This is var 1 7766584
    Module 2's borg has var2 = This is var 2 8008928
    Module 1's borg has var1 = This is var 1 7766584
    Module 1's borg has var2 = This is var 2 8008928

    regards
    --
    Steve Holden http://www.holdenweb.com/
    Python Web Programming http://pydish.holdenweb.com/pwp/
     
    Steve Holden, Sep 30, 2003
    #14
  15. > Fair enough, but it's not just a matter of style... using something like
    >
    > import leoGlobals as g
    >
    > would probably have avoided this problem...


    True! However, I must then change every reference x to a function in
    leoGlobals to g.x. This is what I want to avoid. Being able to go from
    app().x to app.x is a very small improvement: I want to avoid a
    corresponding very small step backwards.

    Edward
    --------------------------------------------------------------------
    Edward K. Ream email:
    Leo: Literate Editor with Outlines
    Leo: http://webpages.charter.net/edreamleo/front.html
    --------------------------------------------------------------------
     
    Edward K. Ream, Sep 30, 2003
    #15
  16. > > I don't want to discuss whether this is good style: it is simple and it
    > > works well for me :)


    > Okay, I won't discuss, I'll just tell you that this is a recipe for
    > giving yourself a headache.


    I could agree with you if using "from leoGlobals import *" had ever caused
    me the slightest ache. Aside from this startup problem, now completely
    solved, it never has.

    As suggested in another reply, replacing every reference to x in leoGlobals
    by g.x might be considered better style, but this is precisely what I want
    to avoid. It is always perfectly obvious in the code that a reference to a
    "bare" function is a reference to a function in leoGlobals. What could be
    clearer?

    Edward
    --------------------------------------------------------------------
    Edward K. Ream email:
    Leo: Literate Editor with Outlines
    Leo: http://webpages.charter.net/edreamleo/front.html
    --------------------------------------------------------------------
     
    Edward K. Ream, Sep 30, 2003
    #16
  17. > In short, the following pattern appears like it will work in all my
    modules:
    >
    > from leoGlobals import *
    > app = leoProxy() # leoProxy defined in leoGlobals
    > # Now the code can reference either app.x or app().x.


    Actually, app = leoProxy() can be done in leoGlobals, so the pattern is
    just:

    from leoGlobals import *
    # Now the code can reference either app.x or app().x.

    I have installed the new code in leoGlobals.py and everything "just works".

    Edward
    --------------------------------------------------------------------
    Edward K. Ream email:
    Leo: Literate Editor with Outlines
    Leo: http://webpages.charter.net/edreamleo/front.html
    --------------------------------------------------------------------
     
    Edward K. Ream, Sep 30, 2003
    #17
  18. On Mon, 29 Sep 2003 23:24:51 GMT, "Steve Holden" <> wrote:
    [...]
    >
    >I've followed this thread, and I'm having trouble understanding why nobody's
    >suggested using Alex martelli's "borg" pattern, which he originally called a


    I think because (IIUC) the OP wants to import * to avoid naming a container,
    and he's willing to live read-only for the resulting bindings (though the
    bindings can of course be to mutable things).

    >"statel;ess proxy", where all objects of a given type share the same state
    >information. Sounds to me that's what you really want, no?
    >


    >This would mean that in leo_global you would have something like this:
    >
    >leo_global.py:
    >-------------
    >class Borg(object):
    > _state = {}
    > def __new__(cls, *p, **k):
    > self = object.__new__(cls, *p, **k)
    > self.__dict__ = cls._state
    > return self
    >
    >
    >module1.py
    >-------------
    >from leo_global import Borg
    >
    >myborg = Borg()
    >myborg.var1 = "This is var 1"
    >
    >import module2
    >
    >print "Module 1's borg has var1 =", myborg.var1, id(myborg.var1)
    >print "Module 1's borg has var2 =", myborg.var2, id(myborg.var2)
    >
    >
    > module2.py:
    >-------------
    >from leo_global import Borg
    >
    >myborg = Borg()
    >myborg.var2 = "This is var 2"
    >
    >print "Module 2's borg has var1 =", myborg.var1, id(myborg.var1)
    >print "Module 2's borg has var2 =", myborg.var2, id(myborg.var2)
    >
    >The result of all this appears to be what you want: a simple way of creating
    >an easily-referenced shared state. Vide:
    >
    >C:\Steve\Projects\Python>python module1.py
    >Module 2's borg has var1 = This is var 1 7766584
    >Module 2's borg has var2 = This is var 2 8008928
    >Module 1's borg has var1 = This is var 1 7766584
    >Module 1's borg has var2 = This is var 2 8008928
    >

    Yes, but UIAM [1]

    import leo_global as myborg # leo_global.py being an empty file for this example

    instead of

    from leo_global import Borg
    myborg = Borg()

    would let you do what you are showing in the above ;-)

    [1] Got a little nervous about that, so I tried it:

    ============================================================
    [ 6:43] C:\pywk\clp\leo\SteveHolden>dir leo_global.py
    Volume in drive C is System
    Volume Serial Number is 14CF-C4B9

    Directory of C:\pywk\clp\leo\SteveHolden

    03-09-30 06:35 0 leo_global.py
    1 File(s) 0 bytes
    56,197,120 bytes free

    [ 6:43] C:\pywk\clp\leo\SteveHolden>type module1.py
    #module1.py
    #-------------
    #from leo_global import Borg
    #
    #myborg = Borg()
    import leo_global as myborg
    myborg.var1 = "This is var 1"

    import module2

    print "Module 1's borg has var1 =", myborg.var1, id(myborg.var1)
    print "Module 1's borg has var2 =", myborg.var2, id(myborg.var2)




    [ 6:44] C:\pywk\clp\leo\SteveHolden>type module2.py
    # module2.py:
    #-------------
    #from leo_global import Borg
    #
    #myborg = Borg()
    import leo_global as myborg
    myborg.var2 = "This is var 2"

    print "Module 2's borg has var1 =", myborg.var1, id(myborg.var1)
    print "Module 2's borg has var2 =", myborg.var2, id(myborg.var2)


    [ 6:44] C:\pywk\clp\leo\SteveHolden>python module1.py
    Module 2's borg has var1 = This is var 1 9439256
    Module 2's borg has var2 = This is var 2 9439496
    Module 1's borg has var1 = This is var 1 9439256
    Module 1's borg has var2 = This is var 2 9439496

    =================================================================================
    Regards,
    Bengt Richter
     
    Bengt Richter, Sep 30, 2003
    #18
  19. > Okay, I won't discuss, I'll just tell you that this is a recipe for
    > giving yourself a headache.


    The more I think about this remark, the more I tend to agree with you. What
    I said about not having trouble with "from leoGlobals import *" is true, and
    yet...

    The problem isn't so much the present namespace pollution, the problem is
    that the technique doesn't extend well. There comes a point at which there
    are just too many names to keep track of. So if I were managing a group of
    programmers (thank goodness I'm not :) I would tend to disapprove of what I
    have done.

    Still, I don't see a perfect alternative. For sure I wouldn't like to put a
    g. in front of hundreds or thousands of function calls. I suppose that this
    is the kind of thing one would be forced to do in slightly larger
    projects...Any other ideas?

    Edward
    --------------------------------------------------------------------
    Edward K. Ream email:
    Leo: Literate Editor with Outlines
    Leo: http://webpages.charter.net/edreamleo/front.html
    --------------------------------------------------------------------
     
    Edward K. Ream, Oct 2, 2003
    #19
  20. Edward K. Ream

    Peter Hansen Guest

    "Edward K. Ream" wrote:
    >
    > > Okay, I won't discuss, I'll just tell you that this is a recipe for
    > > giving yourself a headache.

    >
    > The more I think about this remark, the more I tend to agree with you. What
    > I said about not having trouble with "from leoGlobals import *" is true, and
    > yet...
    >
    > The problem isn't so much the present namespace pollution, the problem is
    > that the technique doesn't extend well. There comes a point at which there
    > are just too many names to keep track of. So if I were managing a group of
    > programmers (thank goodness I'm not :) I would tend to disapprove of what I
    > have done.
    >
    > Still, I don't see a perfect alternative. For sure I wouldn't like to put a
    > g. in front of hundreds or thousands of function calls. I suppose that this
    > is the kind of thing one would be forced to do in slightly larger
    > projects...Any other ideas?


    The wxPython project recently switched from using "from wx.wxPython import *"
    to a nice simple "import wx" at the top. All calls and constants are now of
    course prefixed with "wx." where before they were unadorned.

    The change seems identical to what you are proposing, and we can probably
    assume it was done for very good reasons. The resulting code, after I've
    made changes to my own, already seems more readable. I encourage you to
    make the same switch.

    -Peter
     
    Peter Hansen, Oct 2, 2003
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Wally

    Startup key

    Wally, Oct 19, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    676
    Jeff Johnson [MVP: VB]
    Oct 19, 2004
  2. Martin Altemark
    Replies:
    1
    Views:
    311
    Natty Gur
    Aug 21, 2003
  3. VB Programmer

    Startup Kit

    VB Programmer, Mar 1, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    524
    Curt_C [MVP]
    Mar 1, 2004
  4. =?Utf-8?B?SXVsaWFuIElvbmVzY3U=?=

    Startup page problem on local

    =?Utf-8?B?SXVsaWFuIElvbmVzY3U=?=, May 23, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    519
    Torrent
    May 23, 2004
  5. tfs
    Replies:
    5
    Views:
    511
    Holly
    Jun 28, 2004
Loading...

Share This Page