【问题标题】:Python: How do I create a reference to a reference?Python:如何创建对引用的引用?
【发布时间】:2010-05-17 02:14:40
【问题描述】:

我传统上是一名 Perl 和 C++ 程序员,所以如果我对 Python 的一些琐碎的事情有误解,请提前道歉!

我想创建对引用的引用。 嗯?好的。 Python 中的所有对象实际上都是对真实对象的引用。 那么,如何创建对此引用的引用?

为什么我需要/想要这个?我重写 sys.stdout 和 sys.stderr 来创建一个日志库。我想要对 sys.stdout 的(二级)引用。

如果我可以创建对引用的引用,那么我可以创建一个通用记录器类,其中 init 函数接收对将被覆盖的文件句柄引用的引用,例如 sys.stdout或 sys.stderr。目前,我必须对这两个值进行硬编码。

干杯, 凯文

【问题讨论】:

    标签: python reference stdout


    【解决方案1】:

    做起来容易:

    ostream = sys.stdout
    print >> ostream, 'hi mom!'
    ostream = sys.stderr
    print >> ostream, 'hi mom!'
    ostream = open('mylog.txt', 'a')
    ...
    

    当你有更多的 Python 时,看看标准的 logging module

    这个答案是基于假设,从问题的层面,真正需要什么。 Python中不需要引用引用的概念,如果需要,您可以通过列表或字典进行多路复用:

    outputs = [sys.stderr, my_open_file_object_which_is_really_a_reference]
    print >> outputs[0], 'hi dad!'
    outputs = {'terminal': sys.stderr, 'logfile': file_object}
    print >> outputs['logfile'], 'goodbye world!'
    

    等等。

    【讨论】:

      【解决方案2】:

      您不能在 python 中创建对引用的引用。但是,您可以使用 write 等方法使用自定义类覆盖 stderrstdout 文件,以允许您自己的日志记录系统:

      import sys
      
      class MyLogger:
          def __init__(self, f):
              self.f = f
      
          def __getattr__(self, name):
              # forward e.g. flush() calls to the original file
              return getattr(self.f, name)
      
          def write(self, data):
              # log the data here!
              # ...
      
              # And write to the original file
              self.f.write(data)
      
      sys.stdout = MyLogger(sys.stdout)
      sys.stderr = MyLogger(sys.stderr)
      

      【讨论】:

      • 无法将 [sys.stdout = MyLogger(sys.stdout)] 设为通用的面孔证明 Python 缺少某些东西。不过,我喜欢我看到的其他一切。幸运的是,只有两个文件句柄可以覆盖。我可以“负担”重复两次 =) 感谢您的建议。这个解决方案最符合我最初的需求。
      • 哦,还有。 _getattr_ 的好建议。我会补充的。
      • 我已经覆盖了stdoutstderr,但是可以将它们替换为具有write 方法的任何对象/类(例如替代文件,所以@987654329 @ 会起作用。)我认为它根本没有限制——它只是一种不同的语言,背后有不同的哲学——我认为对对象的引用违背了 python 哲学(python.org/dev/peps/pep-0020),尽管我确信它适合使用 perl 的“表达”模型,它有自己的优点和缺点:-P
      【解决方案3】:

      正如其他答案所说,python 中没有真正的“引用的引用”,但有一些方法可以获得几乎相同的效果:

      >>> reference1 = "Some Data"
      >>> reference2 = (reference1,)
      >>> def f(data):
          print data
      
      >>> f(reference2)
      ('Some Data',)
      >>> f(*reference2)
      Some Data
      

      【讨论】:

        【解决方案4】:

        这是不可能的。将所需属性作为字符串传递并使用getattr()setattr()

        【讨论】:

          【解决方案5】:

          首先,已经有一个logging 模块,所以你可能应该使用它。其次,虽然不存在对引用的引用,但您可以通过包装器或函数来实现该间接。例如,如果您要创建一个 getter 和 setter 函数来分配对象,例如:

           class StdOutWrapper(object):
                def __init__(self):
                    self.original = sys.stdout
          
                @property
                def value(self):
                    return sys.stdout
          
                @value.setter
                def value(self,val):
                    sys.stdout = val
          

          然后您可以将此对象的实例传递给您的记录器以分配/取消引用 sys.stdout。

          【讨论】:

          • 这个解决方案的问题是我必须硬编码 sys.stdout。这个类不能通用创建。
          • @KCArpe,是的,这是正确的。我试图为使用包装器的任何东西保存编码......包装器本身必须同时为 sys.stdout 和 sys.stdin 编写。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-06-28
          • 2013-06-26
          • 1970-01-01
          • 1970-01-01
          • 2016-06-04
          • 1970-01-01
          相关资源
          最近更新 更多