2016-09-27 12 views
3

サブクラスndarraythisプライマーによれば、__array_finalize__メソッドは、サブクラスが直接インスタンス化されていても、ビューとしてキャストされていても、テンプレートから作成されていても保証されます。サブクラスnumpy.ndarray - ここで__array_finalize__が2回呼び出されないのはなぜですか?

特に、コンストラクタを明示的に呼び出す場合、呼び出されるメソッドの順序は__new__ - >__array_finalize__ - >__init__です。

私はndarrayの次の簡単なサブクラスを持っており、これにより追加のtitle属性が可能です。次の出力を生成

class Frame(np.ndarray):  
    def __new__(cls, input_array, title='unnamed'): 
     print 'calling Frame.__new__ with title {}'.format(title) 
     self = input_array.view(Frame) # does not call __new__ or __init__ 
     print 'creation of self done, setting self.title...' 
     self.title = title 
     return self 

    def __array_finalize__(self, viewed): 
     # if viewed is None, the Frame instance is being created by an explicit 
     # call to the constructor, hence Frame.__new__ has been called and the 
     # title attribute is already set 
     # 
     # if viewed is not None, the frame is either being created by view 
     # casting or from template, in which case the title of the viewed object 
     # needs to be forwarded to the new instance 
     print '''calling Frame.__array_finalize__ with type(self) == {} and 
     type(viewed) == {}'''.format(type(self), type(viewed)) 

     if viewed is not None: 
      self.title = getattr(viewed, 'title', 'unnamed') 

     print self.title 

__array_finalize__が呼び出されていない理由:あなたが見ることができるように

>>> f = Frame(np.arange(3), 'hallo') 
calling Frame.__new__ with title hallo 
calling Frame.__array_finalize__ with type(self) == <class '__main__.Frame'> and 
     type(viewed) == <type 'numpy.ndarray'> 
unnamed 
creation of self done, setting self.title... 
>>> f.title 
'hallo' 

__array_finalize__質問が

self = input_array.view(Frame) 

ラインの結果として呼び出されています再び__new__ - >__array_finalize__ - >__init__チェーンの一部として

+0

これは、 '__array_finalize__'がオブジェクトごとに1回しか呼び出されないためと思われます。 numpyはあなたの 'self'がすでに' __array_finalize__'を呼び出していたことを知っていますので、もう一度呼び出されません。あなたが参照している例は正確ではありませんが、 'print'呼び出しをそのページのRealisticInfoArrayの例に入れると、' __array_finalize__'は一度しか呼び出されません。また、あなたが言及した新しい - > finalize - > initの順序、またはfinalizerを2回呼び出すと思われる理由を、そのページのどこに表示していないのでしょうか。 – BrenBarn

+0

@BrenBarn私は、メソッドが[this](http://docs.scipy.org/doc/numpy/user/basics.subclassing.html#the-role-of)の出力からこの順番で呼び出されるという考えを得ました。 -array-finalize)セクションには3つのメソッドがすべてあり、 "ndarray .__ new__"には新しいオブジェクト "__array_finalize__"が渡されていると記述しています。なぜ私の '__new__'メソッドがこれをやっていないのか不思議です。私の例は[this](http://docs.scipy.org/doc/numpy/user/basics.subclassing.html#slightly-more-realistic-example-attribute-added-to-existing-array)セクションからです。 – timgeb

答えて

1

あなたがリンクしているドキュメントでは、ndarray.__new__がどのように構築する配列に__array_finalize__を呼び出すかについて説明しています。そして、あなたのクラスの__new__メソッドは、既存の配列のviewとしてインスタンスを作成するときにそれを引き起こしています。配列引数のviewメソッドはndarray.__new__を呼び出していて、インスタンスが返される前に__array_finalize__メソッドを呼び出しています。

ndarray.__new__をもう一度呼び出さないため、__array_finalize__が2回呼び出されることはありません。 メソッドにviewコールに加えてsuper().__new__のコールが含まれていた場合は、おそらく__array_finalized__が2回呼び出されます。そのような振る舞いはおそらくバグかもしれません(少なくとも必要以上に遅くなります)ので、あなたがそれをやっていないのは驚くことではありません!

オーバーライドするサブクラスのメソッドが呼び出されたときに、Pythonは自動的にオーバーライドされたメソッドを呼び出すことはありません。オーバーライドされたバージョン(直接super、またはこの場合は別のオブジェクトのviewメソッドを介して間接的に呼び出す)は、オーバーライドするメソッドに従います。

+0

私はどうにかして、 'ndarray'の' __new__'メソッドが '__array_finalize__'の犯人であり、何らかの魔法のせいでそれが起こらなかったということを処理しませんでした。ありがとう。 – timgeb

関連する問題