属性可以访问另一个属性吗?

时间:2013-02-15 23:07:40

标签: python class attributes

我刚开始使用Python,这是关于类的逻辑和实现的一个非常普遍的问题。我为问题的基本层面道歉,但希望它对其他人也有用。以下是一些更清晰的背景:

上下文

  • 我想创建一个代表图像的类。此图像包括3个波段(R,G,B,与3个不同文件相关联)和一些元数据(一个文件,其中包含3个波段文件的文件路径以及其他信息,如相机,地理位置等)。

  • 对于我的思考问题,类Image应包含元数据类型的属性和Band类型的三个属性。

  • 类元数据应该有读取和返回各种信息的方法

  • Class Band应该有分析和处理每个栅格波段的方法。但是,这些方法可能需要访问元数据中包含的信息

我的代码

所以我会这样做:

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. 以动态方式将元数据属性传递给Band对象的最智能方法是什么?

5 个答案:

答案 0 :(得分:1)

  

如果我在创建Image.BandN之后更新Image.Meta中的某些信息,那么Image.BandN.Meta将不会同时更新,对吧?

这取决于您如何进行更新。创建Image实例(我将调用img)后,img.Metaimg.BandN.Meta是同一个对象。

如果您为img.Meta分配新值,则img.BandN.Meta将不会更新,因为img.Meta现在是新对象,而img.BandN.Meta仍然是原始对象。

但是,如果您修改img.Meta,例如img.Meta.some_attribute = new_value,那么img.BandN.Meta也会更新,因为它们仍然是同一个对象。

只要您修改img.Meta而不是为其赋予新值,您的代码就会很好。

答案 1 :(得分: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

  

我的方式对我来说似乎有点多余,更重要的是它似乎是“静态的”。

嗯,它有点冗余和静态,因为它只处理三个波段,如果你想使用相同的代码,比如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')}

答案 2 :(得分:1)

这一切似乎都合理。

Band的任何方法,如果需要查阅元数据,都可以通过self.Meta引用来实现。

另外,请考虑采用Python样式指南中的命名约定,即仅为类名保留CapitalizedWords;将lower_case_with_underscores用于参数,属性,方法和变量。 (Metadata的{​​{1}}参数会影响Band.__init__类。)

答案 3 :(得分:1)

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...

答案 4 :(得分:1)

你已经将图像分解为三个类,但是Band和MetaData是紧密耦合的,而Image并没有做太多。可能Band更简单地表示为一组整数或浮点数。

我没有尝试设计对象和类层次结构,而是从最简单的实现开始。如果类太大或代码变得笨拙,那么你可以开始分离类。一旦你需要清理它,你会发现简单,扁平的代码比高度精心设计的对象层次结构更容易重塑。

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):
        ...