FAQ
I'm not a fan of OO but I decided to give it a try. After all, Python
makes it elegant.

So I wrote a program usuing classes, methods etc. All nice. Then it
grew up and I decided to split it in several files - one class into
each class as Guido asked us to do.

And then, I came across my first problem: I had had a global variable
(just one!) and it wouldn't work anymore. At all. Any 'global'
declarations wouldn't help, and without it I'm lost.

So, I thought I might be smarter than it. I would pass this
variable to where I need it, but... it stil obstinately refuses to
work. But then, my ex-global is a list of instances of a class,
and methods in instances of another class won't accept it as
an argument.

So, any ideas how I should cope with that and be able to use my
global variable in different clases in different files?

Regards,
Artur
--
http://www.wolneprogramy.org

"Jakos nie kusi mnie perspektywa zostania wsiowym glupkiem
znajacym sie tylko na komputerach i zarabiajacym mnostwo kasy" -- lcamtuf

Search Discussions

  • Roman Suzi at Jun 10, 2001 at 1:21 pm

    On 10 Jun 2001, Artur Skura wrote:
    I'm not a fan of OO but I decided to give it a try. After all, Python
    makes it elegant.

    So I wrote a program usuing classes, methods etc. All nice. Then it
    grew up and I decided to split it in several files - one class into
    each class as Guido asked us to do.

    And then, I came across my first problem: I had had a global variable
    (just one!) and it wouldn't work anymore. At all. Any 'global'
    declarations wouldn't help, and without it I'm lost.
    Probably, you have 3 different globals: one per module.
    So, I thought I might be smarter than it. I would pass this
    variable to where I need it, but... it stil obstinately refuses to
    work. But then, my ex-global is a list of instances of a class,
    and methods in instances of another class won't accept it as
    an argument.
    Why do you need global variable in the OOP design anyway?
    Maybe, it belongs to os.environ or some container class?

    I blame myself each time I maintain code with global variables:
    the code can't be easily reconfigured, creates other problems.
    Globals are allright only in short scripts which has no chance
    to grow larger.
    So, any ideas how I should cope with that and be able to use my
    global variable in different clases in different files?

    Regards,
    Artur
    Sincerely yours, Roman Suzi
    --
    _/ Russia _/ Karelia _/ Petrozavodsk _/ rnd at onego.ru _/
    _/ Sunday, June 10, 2001 _/ Powered by Linux RedHat 6.2 _/
    _/ "Computers make very fast, very accurate mistakes." _/
  • Artur Skura at Jun 10, 2001 at 2:58 pm

    On Sun, 10 Jun 2001 17:21:18 +0400 (MSD), Roman Suzi wrote:
    So, I thought I might be smarter than it. I would pass this
    variable to where I need it, but... it stil obstinately refuses to
    work. But then, my ex-global is a list of instances of a class,
    and methods in instances of another class won't accept it as
    an argument.
    Why do you need global variable in the OOP design anyway?
    I knew you would say that! ;)
    The source code is at http://arturs.iidea.pl/server.py
    and you can get 'live demo' by
    $ telnet arturs.iidea.pl 2211
    It's based on simple chat code.

    I just want to keep this one little global, userlist, in order
    not to do some strange acrobatics later. It's clean, simple,
    keeps the number of arguments to pass to ther functions small etc.
    I blame myself each time I maintain code with global variables:
    the code can't be easily reconfigured, creates other problems.
    Globals are allright only in short scripts which has no chance
    to grow larger.
    In this case it fits perfectly. I need to acces userlist from any place,
    any moment.

    OK, suppose I want to do away with global userlist.
    I want to pass it to TS_Command instance. Will it work? No. Why?
    I have no idea... You see, I don't want to stick fanatically to my
    global, any solution is fine, provided that I can split my code
    and see it working as before, when it was all in one file.
    This 'userlist' is my last obstacle.

    Regards,
    Artur
    --
    http://www.wolneprogramy.org

    "Jakos nie kusi mnie perspektywa zostania wsiowym glupkiem
    znajacym sie tylko na komputerach i zarabiajacym mnostwo kasy" -- lcamtuf
  • Roman Suzi at Jun 10, 2001 at 5:55 pm

    On 10 Jun 2001, Artur Skura wrote:

    Why do you need global variable in the OOP design anyway?
    I knew you would say that! ;)
    Yes, of course. Because in True Object Design there is no place for
    anything global. You have to make some class instance of which will manage
    userlist.
    The source code is at http://arturs.iidea.pl/server.py
    and you can get 'live demo' by
    $ telnet arturs.iidea.pl 2211
    It's based on simple chat code.

    I just want to keep this one little global, userlist, in order
    not to do some strange acrobatics later. It's clean, simple,
    keeps the number of arguments to pass to ther functions small etc.
    After seven years of trial and error I could say that I begin to
    understand OOP ;-)

    I thought that way about arguments too. It only says that your object
    design is not done right way. (It usually happens when it's first try
    anyway).
    I blame myself each time I maintain code with global variables:
    the code can't be easily reconfigured, creates other problems.
    Globals are allright only in short scripts which has no chance
    to grow larger.
    In this case it fits perfectly. I need to acces userlist from any place,
    any moment.
    Maybe some object could be used to represent the functionality with a
    proper method. For example, AuthoriseUser(). It's a singleton in your
    situation. But if later you decide to have more userlists, you could add
    it to authorisation chain.
    OK, suppose I want to do away with global userlist.
    I want to pass it to TS_Command instance. Will it work? No. Why?
    You still think in terms of structural design. Even modular design already
    has some precautions against globals. Objects are here to completely
    eliminate the problem.
    I have no idea... You see, I don't want to stick fanatically to my
    global, any solution is fine, provided that I can split my code
    and see it working as before, when it was all in one file.
    This 'userlist' is my last obstacle.
    It's not. It's just first iteration of object analysis/design/programming
    you did. (In fact, your classes has hard-coded many things. Probably you
    will want to change this in the future.)

    It's real fun to return to the same design after some time
    and look at it critically.

    Thus, I do not critisize you here. I am trying to express what I myself
    felt when I tried to reimplement something with objects. At first try
    you have objects wrong. (This is seen from the amount of cross-usages).

    It's a painful process which decreeses quality of the code at first. But
    then it starts to pay off. Bad object design is worse than bad structural
    one, someone said, but good OD is better than good structural.

    Try to rethink your design. Maybe your code will have other
    classes than you have now, and will be less lines.
    Regards,
    Artur

    Sincerely yours, Roman Suzi
    --
    _/ Russia _/ Karelia _/ Petrozavodsk _/ rnd at onego.ru _/
    _/ Sunday, June 10, 2001 _/ Powered by Linux RedHat 6.2 _/
    _/ "Computers make very fast, very accurate mistakes." _/
  • James Logajan at Jun 10, 2001 at 6:14 pm

    Artur Skura wrote:
    So, any ideas how I should cope with that and be able to use my
    global variable in different clases in different files?
    Create a separate module, say globalVar.py, and put your globals into that
    (it should set their initial values. E.g. myList = [ ]; myStuff = None).
    Then use:

    import globalVar

    at the top of all your modules that need to access/update the globals. In
    your code you then just reference as, say, globalVar.myList.append('some
    value'), globalVar.myStuff = 3, etc. All your modules can now access and
    update the global variables as needed and their global nature is also self
    documented.

    Hope this helps!
  • Rainer Deyke at Jun 10, 2001 at 8:01 pm
    "Roman Suzi" <rnd at onego.ru> wrote in message
    news:mailman.992195796.5861.python-list at python.org...
    On 10 Jun 2001, Artur Skura wrote:

    Why do you need global variable in the OOP design anyway?
    I knew you would say that! ;)
    Yes, of course. Because in True Object Design there is no place for
    anything global.
    That's a silly philosophy. Classes are objects; are they allowed to be
    global? What about objects that provide a higher level of abstraction than
    classes?


    --
    Rainer Deyke (root at rainerdeyke.com)
    Shareware computer games - http://rainerdeyke.com
    "In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor
  • Roman Suzi at Jun 11, 2001 at 2:51 am

    On Sun, 10 Jun 2001, Rainer Deyke wrote:
    "Roman Suzi" <rnd at onego.ru> wrote in message
    news:mailman.992195796.5861.python-list at python.org...
    On 10 Jun 2001, Artur Skura wrote:

    Why do you need global variable in the OOP design anyway?
    I knew you would say that! ;)
    Yes, of course. Because in True Object Design there is no place for
    anything global.
    That's a silly philosophy.
    That was said with irony. There is always TheUniverse object.
    It is global, depending on philosophy and religion ;-)
    Classes are objects; are they allowed to be global?
    Classes belong to meta-system, which serves the purpose
    of description of the system. That's why classes are
    usually global. At least at the module level.
    What about objects that provide a higher level of abstraction than
    classes? The same.
    --
    Rainer Deyke (root at rainerdeyke.com)
    Shareware computer games - http://rainerdeyke.com
    "In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor
    Sincerely yours, Roman Suzi
    --
    _/ Russia _/ Karelia _/ Petrozavodsk _/ rnd at onego.ru _/
    _/ Monday, June 11, 2001 _/ Powered by Linux RedHat 6.2 _/
    _/ "Useless Invention: Fur sink." _/
  • Artur Skura at Jun 10, 2001 at 8:12 pm

    On Sun, 10 Jun 2001 21:55:17 +0400 (MSD), Roman Suzi wrote:
    On 10 Jun 2001, Artur Skura wrote:

    Why do you need global variable in the OOP design anyway?
    I knew you would say that! ;)
    Yes, of course. Because in True Object Design there is no place for
    anything global. You have to make some class instance of which will manage
    userlist.
    Mhm. It seems a little too much overhed for a simple list of users.
    The problem is I need it in many places. So even if I create class
    ManageUsers, set userlist=ManageUsers(), then userlist.add(user),
    it will not solve my problem - it might solve for one class only,
    so probably I need to rearange everything.

    I just want to keep this one little global, userlist, in order
    not to do some strange acrobatics later. It's clean, simple,
    keeps the number of arguments to pass to ther functions small etc.
    After seven years of trial and error I could say that I begin to
    understand OOP ;-)

    I thought that way about arguments too. It only says that your object
    design is not done right way. (It usually happens when it's first try
    anyway).
    The problem is how to do it in this case? It seems this is not
    exactly within the scope of this group. But the necessity of
    having userlist available from (almost) everywhere seems still
    obvious to me.
    I blame myself each time I maintain code with global variables:
    the code can't be easily reconfigured, creates other problems.
    Globals are allright only in short scripts which has no chance
    to grow larger.
    In this case it fits perfectly. I need to acces userlist from any place,
    any moment.
    Maybe some object could be used to represent the functionality with a
    proper method. For example, AuthoriseUser(). It's a singleton in your
    situation. But if later you decide to have more userlists, you could add
    it to authorisation chain.
    No, that part of the code (authorisation etc.) is not important now.
    It all will be rewritten, anyway. But I need to be able to know
    the value of userlist from within instances of TS_Command.Handle(),
    also from my main module, and - because the project is a little
    specific - from TS_System and maybe some other classes.
    So some solution would be to pass userlist as an argument of TS_Command
    instance, but somehow it won't work.

    OK, suppose I want to do away with global userlist.
    I want to pass it to TS_Command instance. Will it work? No. Why?
    You still think in terms of structural design. Even modular design already
    has some precautions against globals. Objects are here to completely
    eliminate the problem.
    Tell me how :) I think maybe I', stuck against some exception
    - I really need this list everywhere...
    I have no idea... You see, I don't want to stick fanatically to my
    global, any solution is fine, provided that I can split my code
    and see it working as before, when it was all in one file.
    This 'userlist' is my last obstacle.
    It's not. It's just first iteration of object analysis/design/programming
    you did. (In fact, your classes has hard-coded many things. Probably you
    will want to change this in the future.)
    For sure - I'm jus experimeting, it will al be rewritten, maybe
    in another language, I just want to check out different ways
    (Ruby seems elegant, also I spare some finger-gimnastics when
    I have to change indentation of a whole function only because I
    added one condition etc.)
    It's real fun to return to the same design after some time
    and look at it critically.

    Thus, I do not critisize you here. I am trying to express what I myself
    felt when I tried to reimplement something with objects. At first try
    you have objects wrong. (This is seen from the amount of cross-usages).

    It's a painful process which decreeses quality of the code at first. But
    then it starts to pay off. Bad object design is worse than bad structural
    one, someone said, but good OD is better than good structural.

    Try to rethink your design. Maybe your code will have other
    classes than you have now, and will be less lines.
    Could you suggest some good books about OO?
    I want to make things easy for someone who might want to add
    functionality to that code, so it must not be ugly.

    (BTW I would like to thank other people for pointing out the
    possibility of having global.py module etc. Yes, it solves my
    problem for now, but maybe I should really redesign it as Roman
    suggest to eliminate the need. No, I still don't know how :))

    Regards,
    Artur
    --
    http://www.wolneprogramy.org

    "Jakos nie kusi mnie perspektywa zostania wsiowym glupkiem
    znajacym sie tylko na komputerach i zarabiajacym mnostwo kasy" -- lcamtuf
  • James Logajan at Jun 10, 2001 at 9:34 pm

    Artur Skura wrote:
    (BTW I would like to thank other people for pointing out the
    possibility of having global.py module etc. Yes, it solves my
    problem for now, but maybe I should really redesign it as Roman
    suggest to eliminate the need. No, I still don't know how :))
    I would advise against putting any effort into removing a single global; it
    is not be worth your while. In fact there is nothing "wrong" with globals
    per se (speaking from ~26 years of programming experience). Don't worry
    about removing globals, concentrate instead on containment relationships.
    Some "top level" objects and relationships properly belong in the global
    name space.

    P.S. The main execution frame must start from some name space, normally
    called the "global" namespace. So at least one (and usually more) object
    references must be contained in it. You can't get around that basic
    requirement no matter how much object oriented analysis you care to do.

    P.P.S. I've never been able to figure out why people insist on keeping the
    global name space as free of objects as possible while not applying that
    obsession to other name spaces. True, beginners tend to put everything in
    the global name space, but no insight on how to organize relationships is
    going to be imparted by telling them not to put things in the global name
    space. There is a point when that kind of 30-second "wisdom" becomes unwise.
  • Roman Suzi at Jun 11, 2001 at 2:45 am

    On 10 Jun 2001, Artur Skura wrote:
    On Sun, 10 Jun 2001 21:55:17 +0400 (MSD), Roman Suzi wrote:
    On 10 Jun 2001, Artur Skura wrote:

    Why do you need global variable in the OOP design anyway?
    I knew you would say that! ;)
    Yes, of course. Because in True Object Design there is no place for
    anything global.
    that was an irony...
    You have to make some class instance of which will manage
    userlist.
    Mhm. It seems a little too much overhed for a simple list of users.
    What if one day you decide to use threads and userlist is to be shared.
    How do you manage your list without breaking it then? But if some object
    will be in charge of this resource, it will be much-much easier. You will
    need blocking written only once.
    The problem is I need it in many places. So even if I create class
    ManageUsers, set userlist=ManageUsers(), then userlist.add(user),
    it will not solve my problem - it might solve for one class only,
    Why? You can have userlist static, if you want to:

    --- user_manager.py
    class UserManager:
    userlist = []
    def __init__(): ...
    def add(): ...
    def poll(self, func ...):
    def get(self): ...
    def iterate(self): ...


    --- other module

    import user_manager

    class TS:
    userlist = user_manager.UserManager()
    ...
    so probably I need to rearange everything.
    Not much. As a bonus you will get proper defined operations on
    userlist.
    I just want to keep this one little global, userlist, in order
    not to do some strange acrobatics later. It's clean, simple,
    keeps the number of arguments to pass to ther functions small etc.
    After seven years of trial and error I could say that I begin to
    understand OOP ;-)

    I thought that way about arguments too. It only says that your object
    design is not done right way. (It usually happens when it's first try
    anyway).
    The problem is how to do it in this case? It seems this is not
    exactly within the scope of this group. But the necessity of
    having userlist available from (almost) everywhere seems still
    obvious to me.
    Then let every class to have it (as I show above, for example).

    It is also probably that places it is used "everywhere"
    are natural to be included in UserManager class.

    OOP is about regrouping code according to entities.

    For example, userlist is IMHO natural container for
    TS_User's. But it seems you need more than
    just contain list of users: you do other operations
    on the list: poll users, add users (more complex than
    just list.append()).
    In this case it fits perfectly. I need to acces userlist from any place,
    any moment.
    Maybe some object could be used to represent the functionality with a
    proper method. For example, AuthoriseUser(). It's a singleton in your
    situation. But if later you decide to have more userlists, you could add
    it to authorisation chain.
    No, that part of the code (authorisation etc.) is not important now.
    It all will be rewritten, anyway. But I need to be able to know
    the value of userlist from within instances of TS_Command.Handle(),
    also from my main module, and - because the project is a little
    specific - from TS_System and maybe some other classes.
    So some solution would be to pass userlist as an argument of TS_Command
    instance, but somehow it won't work.
    OK, suppose I want to do away with global userlist.
    I want to pass it to TS_Command instance. Will it work? No. Why?
    You still think in terms of structural design. Even modular design already
    has some precautions against globals. Objects are here to completely
    eliminate the problem.
    Only environment (may also be seen as special object) could be
    global. Everything else under the sun isn't ;-)
    Tell me how :) I think maybe I', stuck against some exception
    - I really need this list everywhere...
    It's interesting, that everywhere could suffer some
    drastical rearrangements if you do it in objects.

    Small script could bloat. OOP is a code-compressor only when the
    complexity is large enough. just like file compressors necessary enlarge
    little files (and most of other files too), to be able to compress some of
    the files.
    I have no idea... You see, I don't want to stick fanatically to my
    global, any solution is fine, provided that I can split my code
    and see it working as before, when it was all in one file.
    This 'userlist' is my last obstacle.
    It's not. It's just first iteration of object analysis/design/programming
    you did. (In fact, your classes has hard-coded many things. Probably you
    will want to change this in the future.)
    For sure - I'm jus experimeting, it will al be rewritten, maybe
    in another language, I just want to check out different ways
    (Ruby seems elegant, also I spare some finger-gimnastics when
    I have to change indentation of a whole function only because I
    added one condition etc.)
    It's not a problem: you can use Python-aware text editor
    or editor with python mode. For code to be readable
    indentation is usually a must. So, you indent anyway.
    It's real fun to return to the same design after some time
    and look at it critically.

    Thus, I do not critisize you here. I am trying to express what I myself
    felt when I tried to reimplement something with objects. At first try
    you have objects wrong. (This is seen from the amount of cross-usages).

    It's a painful process which decreeses quality of the code at first. But
    then it starts to pay off. Bad object design is worse than bad structural
    one, someone said, but good OD is better than good structural.

    Try to rethink your design. Maybe your code will have other
    classes than you have now, and will be less lines.
    Could you suggest some good books about OO?
    I want to make things easy for someone who might want to add
    functionality to that code, so it must not be ugly.
    Try "OOP tutorial" on google.com
    (BTW I would like to thank other people for pointing out the
    possibility of having global.py module etc. Yes, it solves my
    problem for now, but maybe I should really redesign it as Roman
    suggest to eliminate the need. No, I still don't know how :))
    Some hints:


    TS_Command could be rearranged to provide generic way to
    add new commands. For example,

    class TS_Command:
    ...

    class TS_ls(TS_Command):
    name = "ls"
    def __init__(self...):
    def do(self, args):
    # ls implementation

    class TS_pwd(TS_Command):
    name = "pwd"
    def __init__(self...):
    def do(self, args):
    # ls implementation

    ...

    Or at least make

    if cond1:
    ...
    elif cond2:
    ...

    to make your code more effective.

    I have not understood what for do you have TS_fs class.
    It's just two utilities which could be fine in separate module,
    without making a class.

    *

    I think that probably it's simpler to start from
    structural version again.

    Your example is not large enough to bother with classes/
    objects unless you plan to make it a module for many developers
    or plan to grow it into more elaborate system. Of course,
    this is good as exercise in OOA/D/P.

    I hope my hints help to refine the code.
    Regards,
    Artur
    Sincerely yours, Roman Suzi
    --
    _/ Russia _/ Karelia _/ Petrozavodsk _/ rnd at onego.ru _/
    _/ Monday, June 11, 2001 _/ Powered by Linux RedHat 6.2 _/
    _/ "Useless Invention: Fur sink." _/
  • Chris Barker at Jun 12, 2001 at 12:05 am

    (Ruby seems elegant, also I spare some finger-gimnastics when
    I have to change indentation of a whole function only because I
    added one condition etc.)
    get yourself an editor that is Python-aware (Emacs, PythonWin, Scite,
    etc.). It will let you increase or decrease the indentation of a block
    of code easily. Then you will be spared the finger gymnastics of typing
    all those darn braces and semicolons!
    (BTW I would like to thank other people for pointing out the
    possibility of having global.py module etc. Yes, it solves my
    problem for now, but maybe I should really redesign it as Roman
    suggest to eliminate the need. No, I still don't know how :))
    Maybe, but the idea of a module as a storage place for an assortment of
    data that you want to access from lots of places is a good one. Those
    FORTRAN common blocks were good for something, you know! Just be careful
    about over-using it. I tend to reserve it for things that are only set
    once, and then only read by various other modules later, if a piece of
    data is being changed by a lot of different modules, it may not belong
    there.

    As far a OO design is concerned, a module used in this way is very much
    like a class with only one instance. It's just a little less code. IN
    fact, it may make sense to put accessor functions in your globals
    module, like:

    globals.getUserList()

    rather than explicity accessing the global value itself.

    -Chris







    --
    Christopher Barker,
    Ph.D.
    ChrisHBarker at home.net --- --- ---
    http://members.home.net/barkerlohmann ---@@ -----@@ -----@@
    ------@@@ ------@@@ ------@@@
    Oil Spill Modeling ------ @ ------ @ ------ @
    Water Resources Engineering ------- --------- --------
    Coastal and Fluvial Hydrodynamics --------------------------------------
    ------------------------------------------------------------------------
  • James Logajan at Jun 12, 2001 at 12:48 am
    Chris Barker wrote:
    ...
    Artur Skura wrote:
    ...
    (BTW I would like to thank other people for pointing out the
    possibility of having global.py module etc.
    ...
    In fact, it may make sense to put accessor functions in your globals
    module, like:

    globals.getUserList()
    ...

    Warning! Do not name such a module "globals.py" because "globals" is already
    a function in the global namespace. That is why I suggested "globalVars.py".
    The singular, "global" shouldn't collide with any existing names, but may be
    prone to confusion with the plural. You could always emulate Fortran and
    call it "common.py"....

    Just a word to the wise.
  • Alex Martelli at Jun 12, 2001 at 7:55 am
    "Chris Barker" <chrishbarker at home.net> wrote in message
    news:3B255CAC.E373C5B7 at home.net...
    ...
    As far a OO design is concerned, a module used in this way is very much
    like a class with only one instance. It's just a little less code. IN
    fact, it may make sense to put accessor functions in your globals
    module, like:

    globals.getUserList()

    rather than explicity accessing the global value itself.
    Actually, and at least in Python 2.1, if one is willing to
    get a LITTLE bit tricky:-), there's an alternative...

    Suppose we want to obtain this effect:

    D:\py21>python
    Python 2.1 (#15, Apr 16 2001, 18:25:49) [MSC 32 bit (Intel)] on win32
    Type "copyright", "credits" or "license" for more information.
    Alternative ReadLine 1.4 -- Copyright 2001, Chris Gonnerman
    import fakemod
    fakemod.goodies.extend("batman robin superman".split())
    fakemod.baddies.extend("luthor penguin iceman".split())
    fakemod.allofem
    ['batman', 'robin', 'superman', 'luthor', 'penguin', 'iceman']
    >>>

    i.e., fakemod exposes "plain lists" -- but appends & other
    mods to lists goodies and baddies of module fakemod also
    become available for access through attribute allofem -- no
    "accessor functions" to complicate the life of client-code
    programmers. How could we achieve this? Well, we COULD
    have in fakemod.py something like...:

    class _fakemod:
    def __init__(self):
    self.goodies = []
    self.baddies = []
    def __getattr__(self, name):
    if name=='allofem':
    return self.goodies+self.baddies
    raise AttributeError, name

    import sys
    sys.modules[__name__] = _fakemod()

    And, indeed, when this is fakemod.py we can see in the
    above-copy&pasted-interactive session that:
    fakemod
    <fakemod._fakemod instance at 007F88BC>
    >>>

    The trick is that an entry in sys.modules need not be a
    module-object... an instance-object will do, AND if it's
    a module object then we can play all of the usual tricks
    with __getattr__, etc, etc. This is just a "proof of
    concept", of course, and we'd really need to expose a
    UserList derivative as 'allofem', in order to catch any
    attempts to modify it directly and either disallow them
    or translate them appropriately into modifications to
    the real underlying lists, etc, etc. But, it's a start.

    Whatever special-method trickery we want to do on an
    object that client-code obtains with an import, just
    like a module, we can (mostly, I guess, in __getattr__
    __setattr__ and __delattr__), by using an instance as
    the "fake module" in this way.


    Is this "obfuscated Python" and not to be mentioned in
    polite company? I don't know. I have not yet had any
    occasion to use this in anger -- AFAIK it wasn't in 2.0,
    it's a 2.1 innovation -- so I have no direct personal
    experience on what effect this has on maintenance and
    similar chores. Offhand, however, this does NOT strike
    me as horrid, to-be-avoided black magic. Sanity checks
    on module attributes, ease of access to them, avoidance
    of cumbersome accessor-function syntax, etc -- all of
    these seem to be applicable to 'modules' (or objects
    accessed as such) just as much as they do to instances.

    Rather than giving __setattr__, etc, to module objects
    directly, the same power (or more) has been obtained by
    relaxing the check that used to ensure that any entry
    in sys.modules had to be a module-object (a check which
    one could see as a violation of signature polymorphism
    in favour of strict typechecks -- the less typechecks
    we have lying around, the more the simplicity and power
    of signature polymorphism will be available to us!).

    I guess the main danger might be with *C* code in a
    Python extension accessing "module" (ha:-) objects
    with PyImport_ImportModule or thereabouts, and then
    accessing the returned object directly with concrete
    PyModule_* calls rather than polymorphically with
    PyObject_* calls. A danger specifically for older
    existing Python extensions, I guess -- and how many
    of those use PyImport_* etc, after all? Once one is
    aware of the possibility that PyImport_* yields a
    non-module object (polymorphic with a module -- no
    doubt an instance object in most such cases), it
    should be easy enough to account for this possibility
    (no personal experience yet...).


    Alex
  • Alex Martelli at Jun 11, 2001 at 8:55 am
    "Roman Suzi" <rnd at onego.ru> wrote in message
    news:mailman.992228330.22368.python-list at python.org...
    ...
    Mhm. It seems a little too much overhed for a simple list of users.
    What if one day you decide to use threads and userlist is to be shared.
    How do you manage your list without breaking it then? But if some object
    will be in charge of this resource, it will be much-much easier. You will
    need blocking written only once.
    There is a serious risk in over-designing systems "because
    one day it might be handy". Yeah, right, but meanwhile you're
    paying the price of complexity *RIGHT NOW*!-)

    "Do the simplest thing that could possibly work", because
    "you ain't gonna need it" (where "it" is the rich, complex,
    over-engineered, over-designed very general solution:-).

    See http://c2.com/cgi/wiki?YouArentGonnaNeedIt ...


    Alex
  • Roman Suzi at Jun 11, 2001 at 1:39 pm

    On Mon, 11 Jun 2001, Alex Martelli wrote:
    "Roman Suzi" <rnd at onego.ru> wrote in message
    news:mailman.992228330.22368.python-list at python.org...
    ...
    Mhm. It seems a little too much overhed for a simple list of users.
    What if one day you decide to use threads and userlist is to be shared.
    How do you manage your list without breaking it then? But if some object
    will be in charge of this resource, it will be much-much easier. You will
    need blocking written only once.
    There is a serious risk in over-designing systems "because
    one day it might be handy". Yeah, right, but meanwhile you're
    paying the price of complexity *RIGHT NOW*!-)
    I always try to choose more flexible way as long as
    it doesn't add to complexity. When it is style of
    thinking, it doesn't require much overhead to always
    code more generally than is required "right now".
    I have too much work "right now" to mend things
    which were somebody's "right yesterday".

    Somehow, more general solutions do not always require
    more work or mean more complexity, but are of better
    quality.
    "Do the simplest thing that could possibly work", because
    "you ain't gonna need it" (where "it" is the rich, complex,
    over-engineered, over-designed very general solution:-).
    That is why Microsoft systems still have those funny
    A:, B:, C: letters before file paths ;-)
    Because "right yesterday" 640K was enough for everything.
    Sincerely yours, Roman Suzi
    --
    _/ Russia _/ Karelia _/ Petrozavodsk _/ rnd at onego.ru _/
    _/ Monday, June 11, 2001 _/ Powered by Linux RedHat 6.2 _/
    _/ "Useless Invention: Fur sink." _/
  • Alex Martelli at Jun 11, 2001 at 2:27 pm
    "Roman Suzi" <rnd at onego.ru> writes:
    ...
    There is a serious risk in over-designing systems "because
    one day it might be handy". Yeah, right, but meanwhile you're
    paying the price of complexity *RIGHT NOW*!-)
    I always try to choose more flexible way as long as
    it doesn't add to complexity. When it is style of
    If it adds NO complexity, why, sure. It just
    doesn't work that way _most often_, though. The
    natural temptation of the battle-scarred designer
    is to overdesign "just in case" -- because the
    hundred times where simple design had to be extended
    later apparently burn themselves in our neural
    circuits more than the thousand times where rich
    and complex design just didn't pull its weight
    and never really provided any added value.

    "Do the simplest thing that could possibly work", because
    "you ain't gonna need it" (where "it" is the rich, complex,
    over-engineered, over-designed very general solution:-).
    That is why Microsoft systems still have those funny
    A:, B:, C: letters before file paths ;-)
    Nope, this has absolutely nothing to do with it. Backwards
    compatibility with externally-visible interfaces to previous
    releases of your software (and older software you choose
    to be similar/compatible to: CP/M, in Microsoft's case) are
    (as should be obvious -- I'm amazed I have to point this out)
    a completely different issue.

    Want to see Microsoft-based examples of over-design versus
    simplicity? Just look at the sheer amount of "reserved,
    must be 0" parameters in their Win32 API's. By far most
    of those parameters have been mandatory zeros for close
    to ten years now -- and meanwhile the places that would
    have needed extra options didn't have them, so we have a
    zillion cases of UglyMultiWordNameEx2. Unix syscalls are
    spare and functional, and have withstood the test of time
    much more effectively than kernel-Win32 API's (despite
    the notorious "I should have spelled 'creat' with an e"
    admission of a design error by Thompson:-).

    But, again, the issue of externally-exposed interfaces
    is quite different from that of implementation architecture.
    When you publish an interface, if your program meets with
    any success, that interface has to stay forever. When
    you make a design choice regarding your implementation,
    you're NOT etching anything into stone -- and that is
    what we're talking about here: whether to use a simple
    global list, to do the job of a simple global list, OR
    overdesign and overarchitect a whole subsystem to take
    the place of the simple, obvious approach.

    Want more examples? Of course they'll again be from
    the real of externally-exposed interfaces, because that
    is where it's easier to share them:-), but that's OK,
    since if some simple architecture works well in a
    relatively unfavourable case (externally exposed itf)
    it will work even better in favourable ones (internal
    implementation choices). How does Python let you know
    what built-in modules it has? A simple global list,
    sys.builtin_module_names. How does it let you know
    what arguments your program was called with? A simple
    global list, sys.argv. How does it let you know AND
    AFFECT where modules will be imported from? A simple
    global list, sys.path. How does it let you know what
    modules have been imported os far? A simple global
    _dictionary_ (aha, a variant!-), sys.modules.

    Simplicity WORKS WELL. Simplicity is the backbone of
    Python, what really makes it great -- wonderful to
    use, powerful AND easy, peerless. Want to learn to
    design programs really well? You could do worse than
    to study what Guido and friends did in Python. You
    will find the small errors and debatable decisions,
    you will find the huge numbers of "just right" design
    choices, large and small. Notice how many times those
    "just right" choices end up delivering *SIMPLICITY*
    over and over again...!-)

    Because "right yesterday" 640K was enough for everything.
    Furthermore, the choice of drive-letters for file paths,
    and the issue of amount of addressable memory, are also
    quite obviously independent. As, again, this is utterly
    obvious, I do not understand why you appear to assert
    causal dependency between these design choices ('Because'?!).
    I reiterate this advice... the Wiki is really a good
    place to see these issues discussed -- as open to all
    sides as a newsgroup, but building up to more permanent
    documents... but not so permanent that you can't always
    enhance them (be it only with your questions and open
    issues).


    Alex
  • Bengt Richter at Jun 12, 2001 at 3:47 am

    On Mon, 11 Jun 2001 16:27:34 +0200, "Alex Martelli" wrote:

    "Roman Suzi" <rnd at onego.ru> writes:
    [...]
    [unattributed quote, sorry]
    "Do the simplest thing that could possibly work", because
    "you ain't gonna need it" (where "it" is the rich, complex,
    over-engineered, over-designed very general solution:-).
    That is why Microsoft systems still have those funny
    A:, B:, C: letters before file paths ;-)
    Nope, this has absolutely nothing to do with it. Backwards
    compatibility with externally-visible interfaces to previous
    releases of your software (and older software you choose
    to be similar/compatible to: CP/M, in Microsoft's case) are
    (as should be obvious -- I'm amazed I have to point this out)
    a completely different issue.
    "A:, ..." accidentally poked one of my hot buttons ;-)

    IMHO "A:, B:, C:" prefixes for file paths are evidence of
    a serious problem with name spaces: Applications have to
    handle symbols that should really only be the business of
    the OS and special utilities. You will note that Unix has
    a mount function to keep '/dev/hdc0' and such out of path
    strings like '/home' etc.

    The conventions of using container names (file names and extensions)
    to identify and carry type information about the content is
    also dangerous IMHO, however convenient. Magic numbers and
    special prefixes embedded in the data at least survive a simple
    renaming of the container. (I'm tempted to ramble about what
    we could do with one or two sectors as data prefix instead of
    a few bytes, but I'll restrain myself ;-)

    Python name spaces seem to be a product of thoughtful design,
    so I wonder if it has succeeded in avoiding the pitfalls of
    misaggregating symbols from different kinds of namespaces in
    what should be abstract path representations.
  • Don Dwiggins at Jun 11, 2001 at 5:26 pm

    Alex Martelli writes:
    There is a serious risk in over-designing systems "because
    one day it might be handy". Yeah, right, but meanwhile you're
    paying the price of complexity *RIGHT NOW*!-)
    "Do the simplest thing that could possibly work", because
    "you ain't gonna need it" (where "it" is the rich, complex,
    over-engineered, over-designed very general solution:-).
    See http://c2.com/cgi/wiki?YouArentGonnaNeedIt ...
    I agree. And while you're there, check out the other Extreme Programming
    principles. To me, the thing that makes this principle "work" is its
    combination with the other principles (most directly "Refactor
    Mercilessly").

    Also, remember that "simplest thing" doesn't mean "the first thing that
    comes to mind". It can take some serious contemplation to come up with the
    simplest thing. Einstein's advice is also useful here: "make things as
    simple as possible, but no simpler".

    --
    Don Dwiggins "'Tis a gift to be simple,
    Advanced MP Technology 'tis a gift to be free..."
    dwig at advancedmp.net -- Shaker hymn
  • Alex Martelli at Jun 11, 2001 at 7:00 pm
    "Don Dwiggins" <dwig at advancedmp.net> writes:
    ...
    There is a serious risk in over-designing systems "because
    one day it might be handy". Yeah, right, but meanwhile you're
    paying the price of complexity *RIGHT NOW*!-)
    "Do the simplest thing that could possibly work", because
    "you ain't gonna need it" (where "it" is the rich, complex,
    over-engineered, over-designed very general solution:-).
    See http://c2.com/cgi/wiki?YouArentGonnaNeedIt ...
    I agree. And while you're there, check out the other Extreme Programming
    principles. To me, the thing that makes this principle "work" is its
    combination with the other principles (most directly "Refactor
    Mercilessly").
    The synergy between the various XP principles and practices is
    one of its most interesting aspects. Pairwise programming feeds
    into simplicity-seeking, exhaustive testing secures refactoring
    isn't breaking things, etc.

    But the risk of over-ambitious, over-general design is not one
    that XP "invented" (or even "discovered":-) -- it's there all the
    time. Simplicity and refactoring are XP's recipes against this
    risk, but the risk is there no matter what (indeed, it's surely
    higher the heavier and more invasive your process... in any
    sort of design-it-all-up-front "waterfall", it's _ruinous_:-).

    Also, remember that "simplest thing" doesn't mean "the first thing that
    comes to mind". It can take some serious contemplation to come up with the
    simplest thing. Einstein's advice is also useful here: "make things as
    simple as possible, but no simpler".
    No doubt. Some are born to simplicity, some have simplicity
    thrust upon them... and some *achieve* simplicity with much
    toil. But remember the specifics of what we're talking about:
    taking a simple list and overgeneralizing it into an ambitious
    "user-administration subsystem" (and this, *WITHOUT* solving
    the issue that the original poster had asked about...!-).


    Alex



    _________________________________________________________
    Do You Yahoo!?
    Get your free @yahoo.com address at http://mail.yahoo.com
  • Laurent Pointal at Jun 12, 2001 at 7:45 pm
    [posted and mailed]

    arturs at iidea.pl (Artur Skura) wrote in
    news:slrn9i6mb8.1vb.arturs at aph.waw.pdi.net:
    I'm not a fan of OO but I decided to give it a try. After all, Python
    makes it elegant.

    So I wrote a program usuing classes, methods etc. All nice. Then it
    grew up and I decided to split it in several files - one class into
    each class as Guido asked us to do.

    And then, I came across my first problem: I had had a global variable
    (just one!) and it wouldn't work anymore. At all. Any 'global'
    declarations wouldn't help, and without it I'm lost.

    So, I thought I might be smarter than it. I would pass this
    variable to where I need it, but... it stil obstinately refuses to
    work. But then, my ex-global is a list of instances of a class,
    and methods in instances of another class won't accept it as
    an argument.
    If you split class AClass in module A and class BClass in module B, and need
    to access a global globlist:
    You can:
    --------
    Put globlist in A as a global.
    In A access globlist directly as a global.
    In B do an "import A".
    In B access globlist via "A.globlist".

    Or you can:
    -----------
    Put globlist in a tierce G module.
    In A and B do n "import G"
    In A and B access globlist via "G.globlist"

    (second solution can solve cross reference between several modules by moving
    shared references into one common place, and it has the advantage to use the
    same access method for everybody)

    The use of module.name syntax ensure that everybody will use the same
    global, even if it the referenced object is changed. To enforce this rule
    you can prefix the global by an _ so that it cannot be imported directly.

    Finally you can:
    ----------------
    Define a module with accessor functions (or accessor classe methods), which
    will be used to manipulate the global.

    A+

    Laurent.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJun 10, '01 at 11:21a
activeJun 12, '01 at 7:45p
posts20
users9
websitepython.org

People

Translate

site design / logo © 2022 Grokbase