我刚开始使用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将不会同时更新,对吧?
答案 0 :(得分:1)
如果我在创建Image.BandN之后更新Image.Meta中的某些信息,那么Image.BandN.Meta将不会同时更新,对吧?
这取决于您如何进行更新。创建Image
实例(我将调用img
)后,img.Meta
和img.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)
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):
...