3

私は Python を使い始めたばかりで、これはクラスのロジックと実装に関する非常に一般的な質問です。質問の基本的なレベルで申し訳ありませんが、他の人にも役立つことを願っています。より明確にするために、いくつかのコンテキストを次に示します。

環境

  • 画像を表すクラスを作成したい。この画像には、3 つのバンド (3 つの異なるファイルに関連付けられた R、G、B) といくつかのメタデータ (3 つのバンド ファイルのファイル パスと、カメラ、地理的位置などのその他の情報を含む 1 つのファイル) が含まれています。

  • 問題の私の考え方では、Image クラスには Metadata 型の属性と Band 型の 3 つの属性を含める必要があります。

  • クラス メタデータには、さまざまな情報を読み取って返すメソッドが必要です

  • クラス Band には、各ラスター バンドの分析と処理のためのメソッドが必要です。ただし、これらのメソッドは Metadata に含まれる情報にアクセスする必要がある場合があります

私のコード

だからここに私がすることがあります:

class Metadata:
    def __init__(self, meta_file_path):
        self.Path = meta_file_path
    def ReadBandPath(self,band_number):
        [...]
    def ReadLocation(self):
        [...]
    def ReadCameraInfo(self):
        [...]
    def GetSomeOtherInfo(self):
        [...]

class Band:
    def __init__(self,Metadata, band_number):
        self.Meta = Metadata
        self.Number = band_number
        self.Path = self.Meta.ReadBandPath(self.Number)
    def DoSomething(self):
        self.Meta.GetSomeOtherInfo()
        [...]

class Image:  
    def __init__(self, meta_file_path)
        self.Meta = Metadata(meta_file_path)
        self.Band1 = Band(self.Meta, 1)
        self.Band2 = Band(self.Meta, 2)
        self.Band3 = Band(self.Meta, 3)
    def SaveAsPng(dest_file):
        [...]  

私の問題

私のやり方は少し冗長に思えます。さらに重要なことに、それは「静的」に見えます。Image.BandN を作成した後で Image.Meta の一部の情報を更新すると、Image.BandN.Meta が同時に更新されないように見えますよね?

  1. 問題を正しく設定および実装していますか?
  2. Metadata 属性を Band オブジェクトに動的に渡す最もスマートな方法は何でしょうか?
4

5 に答える 5

2

OP の質問: 1: 問題を正しく設定して実装していますか? 継承を使用して、クラスの実装に
代替 (冗長性の少ない) を提供したいと思います。 以下のコードは Python 2.7.3 で書かれています。

class Metadata(object):
    def __init__(self, meta_file_path):
        self.Path= meta_file_path
    def ReadBandPath(self,band_number):
        print 'ReadBandPath: ', str(band_number)
    def ReadLocation(self):
        print 'ReadLocation'
    def ReadCameraInfo(self):
        print 'ReadCameraInfo'
    def GetSomeOtherInfo(self):
        print 'GetSomeOtherInfo'

class Band(Metadata):
    def __init__(self, file_path, band_number):
        Metadata.__init__(self, file_path )
        self.number= band_number
        self.Path= self.ReadBandPath(self.number)
    def DoSomething(self):
        self.GetSomeOtherInfo()

class Image(Band):  
    def __init__(self, file_path, band_number, destfile):
        Band.__init__(self, file_path, band_number)
        self.pngfile= destfile
    def SaveAsPng(self):
        print 'Saved as png : ', self.pngfile  

# Now you can create instances of Image like this:
Band1= Image('samplepath1',1,'file4.png')
Band2= Image('samplepath2',2,'filex.png')
Band3= Image('samplepath3',3,'afile.png')
# Methods and attributes from Metadata , Band and Image  : 
Band3.SaveAsPng()
Band2.DoSomething()
Band1.ReadCameraInfo()
print 'Band1: ',Band1.number
print 'Band2: ',Band2.number
print 'Band3: ',Band3.number  
# etc...
于 2013-02-16T01:35:09.390 に答える
1

画像を3つのクラスに分類しましたが、BandとMetaDataは緊密に結合されており、Imageはあまり機能しません。おそらくバンドは、intまたはfloatの配列としてより単純に表されます。

オブジェクトとクラスの階層を設計するのではなく、可能な限り単純な実装から始めます。クラスが大きくなりすぎたり、コードが扱いにくくなったりした場合は、クラスを分離し始めることができます。単純でフラットなコードは、クリーンアップが必要になるまで、高度に細工されたオブジェクト階層よりも簡単に再形成できることがわかります。

class Image(object):
    def __init__(self, meta_file_path):
        self.meta_file_path = meta_file_path
        self.bands = {}
        for b in 'RGB':
            self.bands[b] = self.load_band(b)

    def read_location(self):
        ...

    def process_band(self, b):
        ...
于 2013-02-16T09:44:25.687 に答える
1

Image.BandNを作成した後にImage.Metaの情報を更新すると、Image.BandN.Metaが同時に更新されないようです。

いいえ、これは問題ではありません。my_image.Band1.Metaと同じオブジェクトへの参照になりますmy_image.Meta

問題が発生するのは、(名前を付けるオブジェクトを変更するのではなく)別のオブジェクトmy_mage.Metaに名前を付けるために再割り当てした場合のみです。

ただし、これを自分でテストするには、を印刷するかid(my_image.Meta)id(my_image.Band1.Meta)をチェックしmy_image.Meta is my_image.Band1.Metaます。

私のやり方は私には少し冗長に思えます、そしてもっと重要なことに、それは「静的」に見えます。

まあ、それは正確に3つのバンドを処理するという点で少し冗長で静的であり、たとえばCMYKに同じコードを使用したい場合は、至る所で変更が必要になります。それがあなたがしたいと思うかもしれない何かであるならば、あなたは考慮したいかもしれません:

self.Bands = []
self.Bands.append(Band(self.Meta, 1))
self.Bands.append(Band(self.Meta, 2))
self.Bands.append(Band(self.Meta, 3))

または:

self.Bands = [Band(self.Meta, i) for i in range(3)]

または、RGBが固有の変更できない部分である場合は、数字の代わりに名前を使用することをお勧めします('R'' 'G'、、'B')。そして、個別の変数ではなく、コレクションに入れたい場合もあります。

self.Bands = {name: Band(self.Meta, name) for name in ('R', 'G', 'B')}
于 2013-02-15T23:17:36.727 に答える
1

それはすべて合理的なようです。

Bandメタデータを参照する必要がある場合は、どの方法でも参照を介してself.Meta参照できます。

余談ですが、Pythonスタイルガイドの命名規則を採用することを検討してください。つまり、CapitalizedWordsをクラス名のみに予約します。パラメータ、属性、メソッド、および変数には、lower_case_with_underscoresを使用します。(MetadataへのパラメーターはクラスBand.__init__をシャドウイングしていMetadataます。)

于 2013-02-15T23:18:22.840 に答える
1

Image.BandN を作成した後で Image.Meta の一部の情報を更新すると、Image.BandN.Meta が同時に更新されないように見えますよね?

これは、更新の方法によって異なります。Imageインスタンスを作成した後(これをと呼びますimg)、同じオブジェクトです。img.Metaimg.BandN.Meta

に新しい値を割り当てた場合、img.Metaは新しいオブジェクトで元のままであるimg.BandN.Metaため、更新されません。img.Metaimg.BandN.Meta

ただしimg.Meta、たとえばimg.Meta.some_attribute = new_valueを変更するとimg.BandN.Meta、それらは同じオブジェクトであるため、 も更新されます。

img.Metaコードに新しい値を与えるのではなく、変更している限り、コードはそのままで問題ないように見えます。

于 2013-02-15T23:13:32.223 に答える