scalar references

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

    scalar references


    I have some (potentially mutable) scalar values that I want to share
    among many class instances. Changes in one instance should be
    reflected across the many instances. A classic Borg is not
    appropriate because I have more than one instance.

    Use case: in a plotting library I have several figures. Each figure
    has a DPI parameter, possibly different between figures, which I want
    to share with all the figure components (Axes, Ticks, etc...). I want
    to update the DPI in one place and have it shared across all the
    relevant components of the figure.

    My current approach (which works) is

    class RRef:
    'A read only ref'
    def __init__(self, val):
    self._val = val

    def get(self):
    return self._val

    class RWRef(RRef):
    'A readable and writable ref'
    def set(self, val):
    self._val = val

    Then I can instantiate a DPI instance as

    dpi = RWRef(72)

    and __init__ all the figure components with it, which store

    self.dpi = dpi

    When a figure changes it's DPI via the set method, all the components
    have a reference to the mutated value.

    I don't really have a problem with this approach, but am wondering if
    this is the best (most pythonic!) way to share a mutable scalar value
    among several objects.

    In addition, I want to do basic binary op arithmetic on read only
    references, eg

    def bintimes(x,y): return x*y
    def binadd(x,y): return x+y
    def binsub(x,y): return x-y

    class RRef:
    'A read only ref'
    def __init__(self, val):
    self._val = val

    def get(self):
    return self._val

    def __add__(self, other):
    return BinOp(self, other, binadd)

    def __mul__(self, other):
    return BinOp(self, other, bintimes)

    def __sub__(self, other):
    return BinOp(self, other, binsub)

    class BinOp(RRef):
    'A read only ref that handles binary ops of refs'
    def __init__(self, ref1, ref2, func=binadd):
    self.ref1 = ref1
    self.ref2 = ref2
    self.func = func

    def get(self):
    return self.func(self. ref1.get(), self.ref2.get() )



    Thanks for any suggestions!
    John Hunter

  • Erik Max Francis

    #2
    Re: scalar references

    John Hunter wrote:
    [color=blue]
    > My current approach (which works) is
    >
    > class RRef:
    > 'A read only ref'
    > def __init__(self, val):
    > self._val = val
    >
    > def get(self):
    > return self._val
    >
    > class RWRef(RRef):
    > 'A readable and writable ref'
    > def set(self, val):
    > self._val = val[/color]

    Yep, this is the kind of thing I usually do. If you'd like to write
    shorter, but less self-documenting code, you can just use a one-element
    list.

    --
    Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
    __ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
    / \
    \__/ Perfect situations must go wrong
    -- Florence, _Chess_

    Comment

    • Peter Otten

      #3
      Re: scalar references

      John Hunter wrote:
      [color=blue]
      > I have some (potentially mutable) scalar values that I want to share
      > among many class instances. Changes in one instance should be
      > reflected across the many instances. A classic Borg is not
      > appropriate because I have more than one instance.[/color]

      Below is a slight variation of your approach. I think both the beauty and
      the danger is that, for read access, attributes defined in the client
      instance are indistinguishab le from attributes defined in the template
      object. I've separated them here, but you could even use a UseTemplate
      instance as the template for another instance.

      class Template:
      def __init__(self, **kwd):
      self.__dict__.u pdate(kwd)


      german = Template(color= "blue", language="germa n")
      french = Template(color= "yellow", language="frenc h")

      class UseTemplate:
      def __init__(self, name, template=german ):
      self.name = name
      self.template = template
      def __getattr__(sel f, name):
      "Attributes not found in UseTemplate are looked up in the template"
      return getattr(self.te mplate, name)

      def printit(u):
      print "name=%s, color=%s, language=%s" % (u.name, u.color, u.language)

      first = UseTemplate("fi rst", german)
      second = UseTemplate("se cond", french)
      special = UseTemplate("sp ecial", french)

      def printThem():
      for u in [first, second, special]:
      printit(u)
      print

      printThem()

      # instance attributes shade template attributes
      special.color = "black"

      # changes in template affect all instances using it
      french.color = "red"

      printThem()

      del special.color # the template attr will reappear
      printThem()

      Peter

      Comment

      Working...