10

この小さなスニペットが「なぜこれが機能しないのですか?」と印刷されることを期待していました。 誰かが私がこれが私が期待するように機能しない理由を理解するのを手伝ってもらえますか?これが問題になる場合は、Python2.6を使用しています。

class WhyDoesntThisWork(object):
  def outer(self):
    acc = ''
    def inner(msg):
      global acc
      acc = acc + msg
    inner("Why doesn't")
    inner(" this work?")
    print acc
WhyDoesntThisWork().outer()
  • globalステートメントを含めると、が得られますNameError: global name 'acc' is not defined
  • globalステートメントを含めないと、が表示されUnboundLocalError: local variable 'acc' referenced before assignmentます。
4

2 に答える 2

9

上記のコメントの多くに正解が含まれている理由がわからないので、あえて実際の答えを書く人はいないので、ここで書きます。

class ThisWorksNow(object):
  def outer(self):
    acc = []
    def inner(msg):
      acc.append(msg)
    inner("Why doesn't")
    inner(" this work?")
    print "".join(acc)
ThisWorksNow().outer()

違いはなんですか?

クロージャー内にあるオブジェクトに名前を割り当てることは、Py3キーワードnonlocalが欠落しているため、Python 2.xでは機能しません。そのため、回避策を見つける必要があります。

名前とオブジェクトの結合定数を一定に保つ必要がある場合は、別の変更を行う必要があります。この場合、追加するコンテンツを追加するのはオブジェクトです。

printラインはあまりエレガントではありません。おそらく、その内容を連結して印刷するオブジェクトの方が適しているかもしれません。

class StringBuilder(list): # class name stolen from Java
    def __str__(self):
        """this makes the object printable in a way which represents the concatenated string"""
        return "".join(self)
    @property
    def string(self):
        """this gives us a property which represents the concatenated string"""
        return "".join(self)
 # use whatever suits you better, one or both

これにより、次のことが可能になります。

class ThisWorksNow(object):
  def outer(self):
    acc = StringBuilder()
    def inner(msg):
      acc.append(msg)
    inner("Why doesn't")
    inner(" this work?")
    print acc
    print acc.string # depending on what you take above
ThisWorksNow().outer()

編集(追加):なぜ機能しglobalないのですか?

これはglobal、2つの欠点もあります。

  1. acc私たちが使用する両方の場所でグローバルにする必要があります

    class WhyDoesntThisWork(object):
      def outer(self):
        global acc
        acc = ''
        def inner(msg):
          global acc
          acc = acc + msg
    

    accこれにより、両方のオカレンスを「global」レベルに「持ち上げ」ます。

  2. acc外部から変更される可能性があります。

    他の場所で行う場合global acc、またはaccモジュールレベルで使用する場合、プロセスが改ざんされる可能性があります。これは避けるべきです。

于 2012-06-22T22:19:20.583 に答える
0

以下のようなヘルパークロージャークラスを作成して、変数をクロージャーとして明示的にマークすることができます。そのようなユーティリティがすでに存在するかどうかはわかりません。

class closure:
    def __init__(self, val = None):
        self.val = val
    def __call__(self, val = None):
      if val:
        self.val = val
      return self.val
class WhyDoesntThisWork(object):
  def outer(self):
    acc = closure('')
    def inner(msg):
      acc(acc() + msg)
    inner("Why doesn't")
    inner(" this work?")
    print acc
WhyDoesntThisWork().outer()
于 2013-05-14T15:32:54.690 に答える