print doesn't respect file inheritance?

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

    print doesn't respect file inheritance?

    I was trying to change the behaviour of print (tee all output to a
    temp file) by inheriting from file and overwriting sys.stdout, but it
    looks like print uses C-level stuff to do its writes which bypasses
    the python object/inhertiance system. It looks like I need to use
    composition instead of inheritance, but thought this was strange
    enough to note.

    $python -V
    Python 2.5

    """A short demo script"""
    class notafile(file):
    def __init__(self, *args, **kwargs):
    readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
    'newlines', 'softspace']
    file.__init__(s elf, *args, **kwargs)
    for attr in dir(file):
    if attr in readonly: continue
    setattr(self, attr, None)


    def main():
    n = notafile('/dev/stdout', "w")
    print vars(n)

    import sys
    sys.stdout = n
    print "Testing: 1, 2, 3..."


    output:
    {'__str__': None, 'xreadlines': None, 'readlines': None, 'flush':
    None, 'close': None, 'seek': None, '__init__': None, '__setattr__':
    None, '__reduce_ex__' : None, '__new__': None, 'readinto': None,
    'next': None, 'write': None, '__doc__': None, 'isatty': None,
    'truncate': None, 'read': None, '__reduce__': None,
    '__getattribute __': None, '__iter__': None, 'readline': None,
    'fileno': None, 'writelines': None, 'tell': None, '__delattr__': None,
    '__repr__': None, '__hash__': None}
    Testing: 1, 2, 3...
  • Ben Finney

    #2
    binding names doesn't affect the bound objects (was: print doesn't respect file inheritance?)

    bukzor <workitharder@g mail.comwrites:
    I was trying to change the behaviour of print (tee all output to a
    temp file) by inheriting from file and overwriting sys.stdout
    That's not what your code does, though.
    def main():
    n = notafile('/dev/stdout', "w")
    Creates a new instance of the 'notafile' class; the '=' operator then
    binds that instance to the name 'n'.
    import sys
    Imports a module, and binds the module to the name 'sys'. This
    includes, usually, the module attribute named by 'sys.stdout'.
    sys.stdout = n
    Re-binds the name 'sys.stdout' to the object already referenced by the
    name 'n'. No objects are changed by this; only bindings of names to
    objects.
    print "Testing: 1, 2, 3..."
    Doesn't rely at all on the name 'sys.stdout', so isn't affected by all
    the binding of names above.


    In other words, you can't change the object used by the 'print'
    statement only by re-binding names (which is *all* that is done by the
    '=' operator).

    You can, however, specify which file 'print' should use
    <URL:http://www.python.org/doc/ref/print.html>.

    --
    \ “When I wake up in the morning, I just can't get started until |
    `\ I've had that first, piping hot pot of coffee. Oh, I've tried |
    _o__) other enemas...” —Emo Philips |
    Ben Finney

    Comment

    • Terry Reedy

      #3
      Re: print doesn't respect file inheritance?



      bukzor wrote:
      I was trying to change the behaviour of print (tee all output to a
      temp file) by inheriting from file and overwriting sys.stdout, but it
      looks like print uses C-level stuff to do its writes which bypasses
      the python object/inhertiance system. It looks like I need to use
      composition instead of inheritance, but thought this was strange
      enough to note.
      >
      $python -V
      Python 2.5
      >
      """A short demo script"""
      class notafile(file):
      def __init__(self, *args, **kwargs):
      readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
      'newlines', 'softspace']
      file.__init__(s elf, *args, **kwargs)
      for attr in dir(file):
      if attr in readonly: continue
      setattr(self, attr, None)
      Drop the __init__ and give notafile a .write method.
      Composition version inheritance is not the the real issue.
      >>class nf(object):
      def write(s):
      print(s)
      print(s)
      >>print >>nf(), 'testing'
      testing
      testing

      Now change nf.write to put the copy where you want it.

      tjr



      Comment

      • D'Arcy J.M. Cain

        #4
        Re: binding names doesn't affect the bound objects (was: printdoesn't respect file inheritance?)

        On Sat, 26 Jul 2008 14:07:52 +1000
        Ben Finney <bignose+hate s-spam@benfinney. id.auwrote:
        sys.stdout = n
        >
        Re-binds the name 'sys.stdout' to the object already referenced by the
        name 'n'. No objects are changed by this; only bindings of names to
        objects.
        I do agree that the object formerly known as sys.stdout hasn't changed.
        print "Testing: 1, 2, 3..."
        >
        Doesn't rely at all on the name 'sys.stdout', so isn't affected by all
        the binding of names above.
        Hmm. Are you saying that the following doesn't work?

        $ python
        >>f = open("test", "w")
        >>import sys
        >>sys.stdout = f
        >>print "test message"
        >>sys.exit(0)
        $ cat test
        test message
        In other words, you can't change the object used by the 'print'
        statement only by re-binding names (which is *all* that is done by the
        '=' operator).
        Apparently I can.
        You can, however, specify which file 'print' should use
        <URL:http://www.python.org/doc/ref/print.html>.
        Which contains this statement.

        "Standard output is defined as the file object named stdout in the
        built-in module sys."

        I suppose that there might be some ambiguity there but the proof, as
        they say, is in the pudding.

        --
        D'Arcy J.M. Cain <darcy@druid.ne t | Democracy is three wolves
        http://www.druid.net/darcy/ | and a sheep voting on
        +1 416 425 1212 (DoD#0082) (eNTP) | what's for dinner.

        Comment

        • Lie

          #5
          Re: print doesn't respect file inheritance?

          On Jul 26, 8:50 am, bukzor <workithar...@g mail.comwrote:
          I was trying to change the behaviour of print (tee all output to a
          temp file) by inheriting from file and overwriting sys.stdout, but it
          looks like print uses C-level stuff  to do its writes which bypasses
          the python object/inhertiance system. It looks like I need to use
          composition instead of inheritance, but thought this was strange
          enough to note.
          >
          $python -V
          Python 2.5
          >
          """A short demo script"""
          class notafile(file):
              def __init__(self, *args, **kwargs):
                  readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
          'newlines', 'softspace']
                  file.__init__(s elf, *args, **kwargs)
                  for attr in dir(file):
                      if attr in readonly: continue
                      setattr(self, attr, None)
          >
          def main():
              n = notafile('/dev/stdout', "w")
              print vars(n)
          >
              import sys
              sys.stdout = n
              print "Testing: 1, 2, 3..."
          >
          output:
          {'__str__': None, 'xreadlines': None, 'readlines': None, 'flush':
          None, 'close': None, 'seek': None, '__init__': None, '__setattr__':
          None, '__reduce_ex__' : None, '__new__': None, 'readinto': None,
          'next': None, 'write': None, '__doc__': None, 'isatty': None,
          'truncate': None, 'read': None, '__reduce__': None,
          '__getattribute __': None, '__iter__': None, 'readline': None,
          'fileno': None, 'writelines': None, 'tell': None, '__delattr__': None,
          '__repr__': None, '__hash__': None}
          Testing: 1, 2, 3...
          Use this:

          class fakefile(object ):
          def __init__(self, writeto, transformer):
          self.target = writeto
          self.transform = transformer
          def write(self, s):
          s = self.transform( s)
          self.target.wri te(s)
          sys.stdout = fakefile(sys.st dout, lambda s: '"' + s + '"')

          Inheriting from file is not the best way to do it since there is a
          requirement that child class' interface must be compatible with the
          parent class' interface, since the file-like object you're creating
          must have extremely different interface than regular file, the best
          way is to use Duck Typing, i.e. write a class that have .write()
          method.

          Comment

          • Ben Finney

            #6
            Re: binding names doesn't affect the bound objects

            "D'Arcy J.M. Cain" <darcy@druid.ne twrites:
            Hmm. Are you saying that the following doesn't work?
            >
            $ python
            >f = open("test", "w")
            >import sys
            >sys.stdout = f
            >print "test message"
            >sys.exit(0)
            $ cat test
            test message
            >
            In other words, you can't change the object used by the 'print'
            statement only by re-binding names (which is *all* that is done by
            the '=' operator).
            >
            Apparently I can.
            I admit to not trying any of the above. I was explaining the behaviour
            reported by the original poster, without experimenting to see if I
            could reproduce the behaviour.

            Thanks for being more diligent.

            --
            \ “All persons, living and dead, are purely coincidental.† |
            `\ —_Timequake_, Kurt Vonnegut |
            _o__) |
            Ben Finney

            Comment

            • bukzor

              #7
              Re: binding names doesn't affect the bound objects (was: printdoesn't respect file inheritance?)

              On Jul 26, 7:08 am, "D'Arcy J.M. Cain" <da...@druid.ne twrote:
              On Sat, 26 Jul 2008 14:07:52 +1000
              >
              Ben Finney <bignose+hate s-s...@benfinney. id.auwrote:
                  sys.stdout = n
              >
              Re-binds the name 'sys.stdout' to the object already referenced by the
              name 'n'. No objects are changed by this; only bindings of names to
              objects.
              >
              I do agree that the object formerly known as sys.stdout hasn't changed.
              >
                  print "Testing: 1, 2, 3..."
              >
              Doesn't rely at all on the name 'sys.stdout', so isn't affected by all
              the binding of names above.
              >
              Hmm.  Are you saying that the following doesn't work?
              >
              $ python>>f = open("test", "w")
              >import sys
              >sys.stdout = f
              >print "test message"
              >sys.exit(0)
              >
              $ cat test
              test message
              >
              In other words, you can't change the object used by the 'print'
              statement only by re-binding names (which is *all* that is done by the
              '=' operator).
              >
              Apparently I can.
              >
              You can, however, specify which file 'print' should use
              <URL:http://www.python.org/doc/ref/print.html>.
              >
              Which contains this statement.
              >
              "Standard output is defined as the file object named stdout in the
              built-in module sys."
              >
              I suppose that there might be some ambiguity there but the proof, as
              they say, is in the pudding.
              >
              --
              D'Arcy J.M. Cain <da...@druid.ne t        |  Democracy is three wolveshttp://www.druid.net/darcy/               |  and a sheep voting on
              +1 416 425 1212     (DoD#0082)    (eNTP)   |  what's for dinner.
              Thanks for backing me up.

              Nobody here thinks it's strange that print uses *none* of the
              attributes or methods of sys.stdout to do its job? The implementation
              seems to bypass the whole python system and use C-level FILE* pointers
              directly instead.

              Comment

              • Ethan Furman

                #8
                Re: print doesn't respect file inheritance?

                bukzor wrote:
                I was trying to change the behaviour of print (tee all output to a
                temp file) by inheriting from file and overwriting sys.stdout, but it
                looks like print uses C-level stuff to do its writes which bypasses
                the python object/inhertiance system. It looks like I need to use
                composition instead of inheritance, but thought this was strange
                enough to note.
                >
                $python -V
                Python 2.5
                >
                """A short demo script"""
                class notafile(file):
                def __init__(self, *args, **kwargs):
                readonly = ['closed', '__class__', 'encoding', 'mode', 'name',
                'newlines', 'softspace']
                file.__init__(s elf, *args, **kwargs)
                for attr in dir(file):
                if attr in readonly: continue
                setattr(self, attr, None)
                >
                >
                def main():
                n = notafile('/dev/stdout', "w")
                print vars(n)
                >
                import sys
                sys.stdout = n
                print "Testing: 1, 2, 3..."
                >
                >
                output:
                {'__str__': None, 'xreadlines': None, 'readlines': None, 'flush':
                None, 'close': None, 'seek': None, '__init__': None, '__setattr__':
                None, '__reduce_ex__' : None, '__new__': None, 'readinto': None,
                'next': None, 'write': None, '__doc__': None, 'isatty': None,
                'truncate': None, 'read': None, '__reduce__': None,
                '__getattribute __': None, '__iter__': None, 'readline': None,
                'fileno': None, 'writelines': None, 'tell': None, '__delattr__': None,
                '__repr__': None, '__hash__': None}
                Testing: 1, 2, 3...
                I tried the code (on Windows, so had to change /dev/stdout to
                /temp/notafile.txt) and it worked just fine. Perhaps the issue is that
                n is being set to /dev/stdout instead of some other file so no
                difference is apparent?

                In other words, you're assigning stdout to stdout.

                ~Ethan~

                Comment

                Working...