Turn of globals in a function?

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

    #1

    Turn of globals in a function?


    Is there a way to hide global names from a function or class?

    I want to be sure that a function doesn't use any global variables by
    mistake. So hiding them would force a name error in the case that I
    omit an initialization step. This might be a good way to quickly
    catch some hard to find, but easy to fix, errors in large code blocks.

    Examples:

    def a(x):
    # ...
    x = y # x is assigned to global y unintentionally .
    # ...
    return x

    def b(x):
    # hide globals somehow
    # ...
    x = y # Cause a name error
    # ...
    return x


    y = True
    [color=blue][color=green][color=darkred]
    >>>a(False):[/color][/color][/color]
    True
    [color=blue][color=green][color=darkred]
    >>>b(False):[/color][/color][/color]
    *** name error here ***


    Ron_Adam


  • Michael Spencer

    #2
    Re: Turn of globals in a function?

    Ron_Adam wrote:[color=blue]
    > Is there a way to hide global names from a function or class?
    >
    > I want to be sure that a function doesn't use any global variables by
    > mistake. So hiding them would force a name error in the case that I
    > omit an initialization step. This might be a good way to quickly
    > catch some hard to find, but easy to fix, errors in large code blocks.
    >
    > Examples:
    >
    > def a(x):
    > # ...
    > x = y # x is assigned to global y unintentionally .
    > # ...
    > return x
    >
    > def b(x):
    > # hide globals somehow
    > # ...
    > x = y # Cause a name error
    > # ...
    > return x
    >
    >
    > y = True
    >
    >[color=green][color=darkred]
    >>>>a(False):[/color][/color]
    >
    > True
    >
    >[color=green][color=darkred]
    >>>>b(False):[/color][/color]
    >
    > *** name error here ***
    >
    >
    > Ron_Adam
    >
    >[/color]
    For testing, you could simply execute the function in an empty dict:
    [color=blue][color=green][color=darkred]
    >>> a = "I'm a"
    >>> def test():[/color][/color][/color]
    ... print a
    ...[color=blue][color=green][color=darkred]
    >>> test()[/color][/color][/color]
    I'm a[color=blue][color=green][color=darkred]
    >>> exec test.func_code in {}[/color][/color][/color]
    Traceback (most recent call last):
    File "<input>", line 1, in ?
    File "<input>", line 2, in test
    NameError: global name 'a' is not defined[color=blue][color=green][color=darkred]
    >>>[/color][/color][/color]

    This would get more complicated when you wanted to test calling with parameters,
    so with a little more effort, you can create a new function where the globals
    binding is to an empty dict:
    [color=blue][color=green][color=darkred]
    >>> from types import FunctionType as function
    >>> testtest = function(test.f unc_code, {})
    >>> testtest()[/color][/color][/color]
    Traceback (most recent call last):
    File "<input>", line 1, in ?
    File "<input>", line 2, in test
    NameError: global name 'a' is not defined[color=blue][color=green][color=darkred]
    >>>[/color][/color][/color]

    HTH

    Michael

    Comment

    • Bengt Richter

      #3
      Re: Turn of globals in a function?

      On Sat, 26 Mar 2005 20:01:28 GMT, Ron_Adam <radam2@tampaba y.rr.com> wrote:
      [color=blue]
      >
      >Is there a way to hide global names from a function or class?
      >
      >I want to be sure that a function doesn't use any global variables by
      >mistake. So hiding them would force a name error in the case that I
      >omit an initialization step. This might be a good way to quickly
      >catch some hard to find, but easy to fix, errors in large code blocks.
      >
      >Examples:
      >
      >def a(x):
      > # ...
      > x = y # x is assigned to global y unintentionally .
      > # ...
      > return x
      >
      >def b(x):
      > # hide globals somehow
      > # ...
      > x = y # Cause a name error
      > # ...
      > return x
      >
      >[/color]
      If you put the above def b in e.g. a_module.py,
      and do a (untested ;-)

      from a_module import b

      instead of defining it locally, then the global references
      from b (and whatever else you import from a_module)
      should be to the global dict defined for a_module (i.e., its
      outermost scope), not to the globals where you do the import.
      [color=blue]
      >y = True
      >[color=green][color=darkred]
      >>>>a(False):[/color][/color]
      >True[/color]
      Should work if you define a in place having same scope as the y assignment[color=blue]
      >[color=green][color=darkred]
      >>>>b(False):[/color][/color]
      >*** name error here ***
      >[/color]
      UIAM it should do this if you import b as above.

      Regards,
      Bengt Richter

      Comment

      • Ron_Adam

        #4
        Re: Turn of globals in a function?

        On Sat, 26 Mar 2005 12:18:39 -0800, Michael Spencer
        <mahs@telcopart ners.com> wrote:
        [color=blue]
        >Ron_Adam wrote:[color=green]
        >> Is there a way to hide global names from a function or class?
        >>
        >> I want to be sure that a function doesn't use any global variables by
        >> mistake. So hiding them would force a name error in the case that I
        >> omit an initialization step. This might be a good way to quickly
        >> catch some hard to find, but easy to fix, errors in large code blocks.
        >>
        >> Examples:
        >>
        >> def a(x):
        >> # ...
        >> x = y # x is assigned to global y unintentionally .
        >> # ...
        >> return x
        >>
        >> def b(x):
        >> # hide globals somehow
        >> # ...
        >> x = y # Cause a name error
        >> # ...
        >> return x
        >>
        >>
        >> y = True
        >>
        >>[color=darkred]
        >>>>>a(False) :[/color]
        >>
        >> True
        >>
        >>[color=darkred]
        >>>>>b(False) :[/color]
        >>
        >> *** name error here ***
        >>
        >>
        >> Ron_Adam
        >>
        >>[/color]
        >For testing, you could simply execute the function in an empty dict:
        >[color=green][color=darkred]
        > >>> a = "I'm a"
        > >>> def test():[/color][/color]
        > ... print a
        > ...[color=green][color=darkred]
        > >>> test()[/color][/color]
        > I'm a[color=green][color=darkred]
        > >>> exec test.func_code in {}[/color][/color]
        > Traceback (most recent call last):
        > File "<input>", line 1, in ?
        > File "<input>", line 2, in test
        > NameError: global name 'a' is not defined[color=green][color=darkred]
        > >>>[/color][/color][/color]

        I didn't know you could do that. Interesting. :)

        I was hoping for something in line that could use with an assert
        statement. But this is good too, I'll have to play around with it a
        bit. Thanks.

        Ron

        [color=blue]
        >This would get more complicated when you wanted to test calling with parameters,
        >so with a little more effort, you can create a new function where the globals
        >binding is to an empty dict:
        >[color=green][color=darkred]
        > >>> from types import FunctionType as function
        > >>> testtest = function(test.f unc_code, {})
        > >>> testtest()[/color][/color]
        > Traceback (most recent call last):
        > File "<input>", line 1, in ?
        > File "<input>", line 2, in test
        > NameError: global name 'a' is not defined[color=green][color=darkred]
        > >>>[/color][/color]
        >
        >HTH
        >
        >Michael[/color]


        Comment

        • Ron_Adam

          #5
          Re: Turn off globals in a function?

          [color=blue]
          >If you put the above def b in e.g. a_module.py,
          >and do a (untested ;-)
          >
          > from a_module import b
          >
          >instead of defining it locally, then the global references
          >from b (and whatever else you import from a_module)
          >should be to the global dict defined for a_module (i.e., its
          >outermost scope), not to the globals where you do the import.
          >[color=green]
          >>y = True
          >>[color=darkred]
          >>>>>a(False) :[/color]
          >>True[/color]
          >Should work if you define a in place having same scope as the y assignment[color=green]
          >>[color=darkred]
          >>>>>b(False) :[/color]
          >>*** name error here ***
          >>[/color]
          >UIAM it should do this if you import b as above.
          >
          >Regards,
          >Bengt Richter[/color]

          Good suggestion. Thanks. I was somewhat aware of the modular scope,
          but was looking for way to apply it on a more local level. Michael's
          suggestion looks interesting for that.

          Ron_Adam



          Comment

          • Oren Tirosh

            #6
            Re: Turn of globals in a function?

            Ron_Adam <radam2@tampaba y.rr.com> wrote in message news:<6qeb415iq qsor4biebk6rqj9 g6jv3lpt55@4ax. com>...[color=blue]
            > Is there a way to hide global names from a function or class?
            >
            > I want to be sure that a function doesn't use any global variables by
            > mistake. So hiding them would force a name error in the case that I
            > omit an initialization step. This might be a good way to quickly
            > catch some hard to find, but easy to fix, errors in large code blocks.[/color]

            def noglobals(f):
            .. import new
            .. return new.function(
            .. f.func_code,
            .. {'__builtins__' :__builtins__},
            .. f.func_name,
            .. f.func_defaults ,
            .. f.func_closure
            .. )

            You can use it with the Python 2.4 @decorator syntax:

            @noglobals
            def a(...):
            .. # code here

            Doing this for a class is a little more work. You will need dig inside
            to perform this treatment on each method separately and handle new and
            old-style classes a bit differently.

            Note that this kind of function may declare globals. They will be
            persistent but private to the function.

            Oren

            Comment

            • Ron_Adam

              #7
              Re: Turn of globals in a function?

              On 26 Mar 2005 22:51:14 -0800, oren@REMOVETHIS 1.hishome.net (Oren
              Tirosh) wrote:
              [color=blue]
              >Ron_Adam <radam2@tampaba y.rr.com> wrote in message news:<6qeb415iq qsor4biebk6rqj9 g6jv3lpt55@4ax. com>...[color=green]
              >> Is there a way to hide global names from a function or class?
              >>
              >> I want to be sure that a function doesn't use any global variables by
              >> mistake. So hiding them would force a name error in the case that I
              >> omit an initialization step. This might be a good way to quickly
              >> catch some hard to find, but easy to fix, errors in large code blocks.[/color]
              >
              >def noglobals(f):
              >. import new
              >. return new.function(
              >. f.func_code,
              >. {'__builtins__' :__builtins__},
              >. f.func_name,
              >. f.func_defaults ,
              >. f.func_closure
              >. )
              >
              >You can use it with the Python 2.4 @decorator syntax:
              >
              >@noglobals
              >def a(...):
              >. # code here[/color]

              Cool! I haven't played with decorators yet. :)

              I noticed the 'new' module is depreciated. It referred me to call the
              object type directly instead. So this is probably the better way.

              def noglobals(f):
              return type(f)(
              f.func_code,
              {'__builtins__' :__builtins__},
              f.func_name,
              f.func_defaults ,
              f.func_closure )

              @noglobals
              def a():
              global x
              try: x
              except: x=0
              x += 1
              return x

              x = 5
              for n in range(10):
              print a()
              print x # x is still 5


              So this is another, but longer, way to do a generator.

              [color=blue][color=green][color=darkred]
              >>> print type(a).__doc__[/color][/color][/color]
              function(code, globals[, name[, argdefs[, closure]]])

              Create a function object from a code object and a dictionary.
              The optional name string overrides the name from the code object.
              The optional argdefs tuple specifies the default argument values.
              The optional closure tuple supplies the bindings for free variables.[color=blue][color=green][color=darkred]
              >>>[/color][/color][/color]

              What are 'free variables'?

              And is there a way to directly read what names in a function are set
              with the global statement? (Other than looking at the monitor. ;)

              Ron_Adam





              Comment

              • Greg Ewing

                #8
                Re: Turn of globals in a function?

                Oren Tirosh wrote:[color=blue]
                > def noglobals(f):
                > . import new
                > . return new.function(
                > . f.func_code,
                > . {'__builtins__' :__builtins__},
                > . f.func_name,
                > . f.func_defaults ,
                > . f.func_closure
                > . )[/color]

                Be aware that this will render the function incapable
                of seeing *any* globals at all, including other
                functions and classes defined in the same module --
                which you may find rather inconvenient!

                --
                Greg Ewing, Computer Science Dept,
                University of Canterbury,
                Christchurch, New Zealand

                Comment

                • Ron_Adam

                  #9
                  Re: Turn of globals in a function?

                  On Thu, 31 Mar 2005 16:28:15 +1200, Greg Ewing
                  <greg@cosc.cant erbury.ac.nz> wrote:
                  [color=blue]
                  >Oren Tirosh wrote:[color=green]
                  >> def noglobals(f):
                  >> . import new
                  >> . return new.function(
                  >> . f.func_code,
                  >> . {'__builtins__' :__builtins__},
                  >> . f.func_name,
                  >> . f.func_defaults ,
                  >> . f.func_closure
                  >> . )[/color]
                  >
                  >Be aware that this will render the function incapable
                  >of seeing *any* globals at all, including other
                  >functions and classes defined in the same module --
                  >which you may find rather inconvenient![/color]


                  Developing this idea further...

                  This allows a programmer to specify what globals to allow read and or
                  writes.


                  Cheers,
                  Ron


                  #---start---
                  # useglobals.py

                  """
                  A function to specify what globals and builtins
                  a function may access.
                  Author: Ronald Adam
                  """

                  def useglobals(rw_g lobals=None, r_globals=None, builtins=True):
                  #import dis
                  import sys
                  write_list = []
                  read_list = []
                  if rw_globals != None:
                  rw_globals = rw_globals.repl ace(' ','')
                  write_list = rw_globals.spli t(',')
                  if r_globals != None:
                  r_globals = r_globals.repla ce(' ','')
                  read_list = r_globals.split (',')
                  if builtins == True:
                  read_list.exten d(dir(__builtin s__))
                  elif builtins != None:
                  builtins = builtins.replac e(' ','')
                  read_list.exten d(builtins.spli t(','))
                  # Add own name to read list.
                  read_list.appen d(sys._getframe (0).f_code.co_n ame)
                  read_list.exten d(write_list)
                  #print read_list, write_list
                  names = sys._getframe(1 ).f_code.co_nam es
                  code = sys._getframe(1 ).f_code.co_cod e
                  #print dis.disassemble (sys._getframe( 1).f_code)
                  i = 0
                  while i < len(code):
                  #print ord(code[i])
                  op = ord(code[i])
                  if op == 116: # dis.opmap['LOAD_GLOBAL']
                  oparg = ord(code[i+1]) + ord(code[i+2]) * 256
                  if str(names[oparg]) not in read_list:
                  raise NameError, "read from global name %s, detected"
                  % names[oparg]
                  elif op == 97: # dis.opmap['STORE_GLOBAL']
                  oparg = ord(code[i+1]) + ord(code[i+2]) * 256
                  if names[oparg] not in write_list:
                  raise NameError, "write to global name %s, detected" %
                  names[oparg]
                  if op >= 90: # dis.HAVE_ARGUME NT
                  i += 3 # Not sure if this is always the same?
                  else:
                  i += 1


                  if __name__ == '__main__':
                  """
                  Test useglobals() function. Change values to test
                  for error catching.
                  """

                  def a():
                  useglobals(rw_g lobals='x', r_globals='y,b' )
                  # This function can read or write 'x',
                  # Can read 'y', and function 'b',
                  # and can access all builtins.
                  global x
                  y = 5
                  x += y
                  x = b(x)
                  return x

                  def b(g):
                  useglobals('',' y,c','int')
                  # This function can only read 'y' and
                  # function 'c' in globals, and can
                  # only access 'int' in builtins.
                  g = g+y
                  c(int(g))
                  return g

                  def c(w):
                  useglobals(buil tins=None)
                  # This function has no builtins or globals.
                  w = w**2
                  return w

                  y = 4
                  x = 5
                  z = 6
                  print a(),x,y,z

                  #---end---

                  Comment

                  Working...