question about scope

Discussion in 'Python' started by John Salerno, Oct 1, 2006.

  1. John Salerno

    John Salerno Guest

    I have the following code:



    class DataAccessFrame(wx.Frame):

    menu_items = [('File', 'New Database', 'New Record', 'Open
    Database...',
    'Open Record...', 'Save Record', 'Save All Records',
    'Close Record', 'Close Database'),
    ('Edit', 'Undo', 'Redo', 'Cut', 'Copy', 'Paste'),
    ('Help',)]

    def __init__(self):
    wx.Frame.__init__(self, None, title='Database Access Panel')
    panel = wx.Panel(self)
    self.create_menubar()
    # notebook = wx.Notebook(panel)

    # sizer = wx.BoxSizer()
    # sizer.Add(notebook, 1, wx.EXPAND)
    # panel.SetSizer(sizer)

    def create_menubar(self):
    menubar = wx.MenuBar()
    for item in self.menu_items:
    menu = wx.Menu()
    menubar.Append(menu, item[0])
    for subitem in item[1:]:
    menu.Append(-1, subitem)
    self.SetMenuBar(menubar)

    In the create_menubar method, I got an error about the global name
    "menu_items" not being defined, and this was fixed by putting "self." in
    front of the variable name.

    But why is this necessary? Doesn't a method look in its enclosing class,
    or is that not one of the levels of scope?
     
    John Salerno, Oct 1, 2006
    #1
    1. Advertising

  2. John Salerno

    Steve Holden Guest

    John Salerno wrote:
    > I have the following code:
    >
    >
    >
    > class DataAccessFrame(wx.Frame):
    >
    > menu_items = [('File', 'New Database', 'New Record', 'Open
    > Database...',
    > 'Open Record...', 'Save Record', 'Save All Records',
    > 'Close Record', 'Close Database'),
    > ('Edit', 'Undo', 'Redo', 'Cut', 'Copy', 'Paste'),
    > ('Help',)]
    >
    > def __init__(self):
    > wx.Frame.__init__(self, None, title='Database Access Panel')
    > panel = wx.Panel(self)
    > self.create_menubar()
    > # notebook = wx.Notebook(panel)
    >
    > # sizer = wx.BoxSizer()
    > # sizer.Add(notebook, 1, wx.EXPAND)
    > # panel.SetSizer(sizer)
    >
    > def create_menubar(self):
    > menubar = wx.MenuBar()
    > for item in self.menu_items:
    > menu = wx.Menu()
    > menubar.Append(menu, item[0])
    > for subitem in item[1:]:
    > menu.Append(-1, subitem)
    > self.SetMenuBar(menubar)
    >
    > In the create_menubar method, I got an error about the global name
    > "menu_items" not being defined, and this was fixed by putting "self." in
    > front of the variable name.
    >
    > But why is this necessary? Doesn't a method look in its enclosing class,
    > or is that not one of the levels of scope?


    The methods do indeed look in their enclosing class, but only for
    self-relative references. These are sought first in the instance, then
    in the instance's class, then in the instance's class's superclass, and
    so on up to the ultimate superclass. In other words, all attribute
    lookup uses the method resolution order ...

    You can also reference class variables relative to the class name (i.e.
    you could have used DataAccessFrame.menu_items) but that loses a lot of
    flexibility.

    Also note that when you bind a value to a self-relative name, that
    binding *always* occurs in the instance's namespace. Some people don't
    like that, but it's a fact of life that others use to provide instance
    defaults in class variables that are shadowed by an instance variable
    after a first assignment.

    regards
    Steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC/Ltd http://www.holdenweb.com
    Skype: holdenweb http://holdenweb.blogspot.com
    Recent Ramblings http://del.icio.us/steve.holden
     
    Steve Holden, Oct 1, 2006
    #2
    1. Advertising

  3. John Salerno

    John Salerno Guest

    Steve Holden wrote:

    > The methods do indeed look in their enclosing class, but only for
    > self-relative references. These are sought first in the instance, then
    > in the instance's class, then in the instance's class's superclass, and
    > so on up to the ultimate superclass. In other words, all attribute
    > lookup uses the method resolution order ...


    So what I did is correct? It does work, but why don't I have to define
    the list as self.menu_items as well?
     
    John Salerno, Oct 1, 2006
    #3
  4. John Salerno

    James Stroud Guest

    John Salerno wrote:
    > Steve Holden wrote:
    >
    >> The methods do indeed look in their enclosing class, but only for
    >> self-relative references. These are sought first in the instance, then
    >> in the instance's class, then in the instance's class's superclass,
    >> and so on up to the ultimate superclass. In other words, all attribute
    >> lookup uses the method resolution order ...

    >
    >
    > So what I did is correct? It does work, but why don't I have to define
    > the list as self.menu_items as well?


    This is because that list is an attribute of the class. Instances have a
    reference of this class attribute, but it can be replaced by an
    attribute of the instance with self (self is a reference to the instance
    and not the class. This example might help:

    py> class C(object):
    .... value = 42
    .... def separate_from_pack(self, some_value):
    .... self.value = some_value
    ....
    py> C.value
    42
    py> c1 = C()
    py> c1.value
    42
    py> c2 = C()
    py> c2.value
    42
    py> c2.separate_from_pack(88)
    py> c2.value
    88
    py> C.value
    42
    py> c3 = C()
    py> c3.value
    42


    James

    --
    James Stroud
    UCLA-DOE Institute for Genomics and Proteomics
    Box 951570
    Los Angeles, CA 90095

    http://www.jamesstroud.com/
     
    James Stroud, Oct 1, 2006
    #4
  5. John Salerno

    Steve Holden Guest

    John Salerno wrote:
    > Steve Holden wrote:
    >
    >
    >>The methods do indeed look in their enclosing class, but only for
    >>self-relative references. These are sought first in the instance, then
    >>in the instance's class, then in the instance's class's superclass, and
    >>so on up to the ultimate superclass. In other words, all attribute
    >>lookup uses the method resolution order ...

    >
    >
    > So what I did is correct? It does work, but why don't I have to define
    > the list as self.menu_items as well?


    The first point is that the name "self" isn't in scope at the point you
    make the assignment: it's a local variable (strictly, it's a parameter,
    but they are treated the same as locals) to each method, and when the
    method is called it's a reference to the specific instance whose method
    was called (technically, the instance o which the method is bound).

    You could assign self.menu_items in the __init__() method, but it
    wouldn't really have any advantages given that names in class scope are
    reachable via the name resolution mechanism.

    Note that the def statement is also executed in class scope, which is
    why the method names are class-relative. Python has a special method
    binding feature that changes a call like

    instance.method(a1, a2)

    into

    (instance.__class__).method(instance, a1, a2)

    This is where the reference to self "magically" appears from in method
    calls.

    regards
    Steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC/Ltd http://www.holdenweb.com
    Skype: holdenweb http://holdenweb.blogspot.com
    Recent Ramblings http://del.icio.us/steve.holden
     
    Steve Holden, Oct 1, 2006
    #5
  6. John Salerno

    John Salerno Guest

    James Stroud wrote:

    > This is because that list is an attribute of the class. Instances have a
    > reference of this class attribute, but it can be replaced by an
    > attribute of the instance with self (self is a reference to the instance
    > and not the class. This example might help:


    Ah, I see! So within my create_menubar() method, would it better to
    refer to menu_items as DataAccessFrame.menu_items? Or does it not matter
    in this case, since I'm not reassigning it per instance?
     
    John Salerno, Oct 1, 2006
    #6
  7. John Salerno

    Steve Holden Guest

    John Salerno wrote:
    > James Stroud wrote:
    >
    >
    >>This is because that list is an attribute of the class. Instances have a
    >>reference of this class attribute, but it can be replaced by an
    >>attribute of the instance with self (self is a reference to the instance
    >>and not the class. This example might help:

    >
    >
    > Ah, I see! So within my create_menubar() method, would it better to
    > refer to menu_items as DataAccessFrame.menu_items? Or does it not matter
    > in this case, since I'm not reassigning it per instance?


    I'd prefer to use a self-relative reference, though either works in your
    example. That way the code will work for subclasses with different menus
    too. Perhaps not relevant in your case, but a general point.

    regards
    Steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC/Ltd http://www.holdenweb.com
    Skype: holdenweb http://holdenweb.blogspot.com
    Recent Ramblings http://del.icio.us/steve.holden
     
    Steve Holden, Oct 1, 2006
    #7
  8. John Salerno

    John Salerno Guest

    Steve Holden wrote:
    > John Salerno wrote:
    >> James Stroud wrote:
    >>
    >>
    >>> This is because that list is an attribute of the class. Instances have a
    >>> reference of this class attribute, but it can be replaced by an
    >>> attribute of the instance with self (self is a reference to the instance
    >>> and not the class. This example might help:

    >>
    >> Ah, I see! So within my create_menubar() method, would it better to
    >> refer to menu_items as DataAccessFrame.menu_items? Or does it not matter
    >> in this case, since I'm not reassigning it per instance?

    >
    > I'd prefer to use a self-relative reference, though either works in your
    > example. That way the code will work for subclasses with different menus
    > too. Perhaps not relevant in your case, but a general point.
    >
    > regards
    > Steve


    Thanks!
     
    John Salerno, Oct 1, 2006
    #8
    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. Paul Opal
    Replies:
    12
    Views:
    1,009
    Paul Opal
    Oct 11, 2004
  2. ann
    Replies:
    13
    Views:
    698
    Patricia Shanahan
    Sep 13, 2005
  3. Steven T. Hatton
    Replies:
    9
    Views:
    522
  4. Xah Lee
    Replies:
    0
    Views:
    2,286
    Xah Lee
    Feb 26, 2009
  5. Replies:
    0
    Views:
    184
Loading...

Share This Page