简体   繁体   中英

Problems with deepcopying sys.stdout in python

I have the following problem with copy.deepcopy. It is to do with deepcopying sys.stdout

import sys, copy

class Example:
  def __init__(self, value, outa=sys.stdout):
    self.value = value
    self.outa = outa
  def saying_hello_world(self):
    print>>self.outa, "Hello world! My value is ", self.value

example_1 = Example(3)
example_1.saying_hello_world()

example_2 = copy.deepcopy(example_1)
example_2.value = 5
example_2.saying_hello_world()

Leads to error

Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<stdin>", line 6, in saying_hello_world
ValueError: I/O operation on closed file

For various reasons I need to deepcopy (as I change example_2 in various ways in my more complex situation, and so need a deepcopy). However, when it deepcopies sys.stdout , it transfers it from outputting into thee screen and instead outputs it to a closed file, which then gets the error above. An obvious solution to this is

example_2 = copy.deepcopy(example_1)
example_2.outa = example_1.outa

Is there a better way around this? Or a better way of deepcopying? Thank you!

You can write your own mechanism for deepcoping object using magicmethod __deepcopy__

Here is working example for your code:

import sys, copy

class Example:
  def __init__(self, value, outa=sys.stdout):
    self.value = value
    self.outa = outa

  def saying_hello_world(self):
    print>>self.outa, "Hello world! My value is ", self.value

  def __deepcopy__(self, memo):
      # deepcopy self.value, but pass just a reference of self.outa
      return Example(copy.deepcopy(self.value, memo), self.outa)


example_1 = Example(3)
example_1.saying_hello_world()

example_2 = copy.deepcopy(example_1)
example_2.value = 5
example_2.saying_hello_world()

It is not ideal (you'll need care if subclassing this, as deepcopy of child will return instance of parent!) but should give you an idea how to implement this in your real life application.

You can customise how your instances are copied, and just share the output if it is sys.stdout , using the __deepcopy__ method:

class Example:
    def __init__(self, value, outa=sys.stdout):
        self.value = value
        self.outa = outa
    def saying_hello_world(self):
        print >> self.outa, "Hello world! My value is ", self.value
    def __deepcopy__(self, memo):
        outa = self.outa if self.outa is sys.stdout else deepcopy(self.outa, memo)
        return Example(deepcopy(self.value, memo), outa)

You can adjust the logic for when to copy the outa attribute; perhaps not copying anything that is an open file object is a good idea, for example, or never copying that attribute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM