question about scope

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Salerno

    #1

    question about scope

    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_men ubar()
    # notebook = wx.Notebook(pan el)

    # sizer = wx.BoxSizer()
    # sizer.Add(noteb ook, 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?
  • Steve Holden

    #2
    Re: question about scope

    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_men ubar()
    # notebook = wx.Notebook(pan el)
    >
    # sizer = wx.BoxSizer()
    # sizer.Add(noteb ook, 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

    Comment

    • John Salerno

      #3
      Re: question about scope

      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?

      Comment

      • James Stroud

        #4
        Re: question about scope

        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:

        pyclass C(object):
        .... value = 42
        .... def separate_from_p ack(self, some_value):
        .... self.value = some_value
        ....
        pyC.value
        42
        pyc1 = C()
        pyc1.value
        42
        pyc2 = C()
        pyc2.value
        42
        pyc2.separate_f rom_pack(88)
        pyc2.value
        88
        pyC.value
        42
        pyc3 = C()
        pyc3.value
        42


        James

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


        Comment

        • Steve Holden

          #5
          Re: question about scope

          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.__cla ss__).method(in stance, 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

          Comment

          • John Salerno

            #6
            Re: question about scope

            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?

            Comment

            • Steve Holden

              #7
              Re: question about scope

              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

              Comment

              • John Salerno

                #8
                Re: question about scope

                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!

                Comment

                Working...