Can an attribute access another attribute?

I'm at the very beginning with Python, and this is a very general question about the logic and implementation of classes. I apologize for the basic level of the question, but hopefully it will be useful for others as well. Here are some contexts to make them clearer:

Context

  • I want to create a class that represents an image. This image includes 3 stripes (R, G, B associated with 3 different files) and some metadata (one file that contains the 3 stripes file path and other information like camera, geolocation, etc. etc.).

  • For my way of thinking, the Image class problem should include an attribute of type Metadata and three attributes of type Band.

  • Class metadata must have methods for reading and returning various information

  • The Band class should have methods for analyzing and processing each raster range. However, these methods may need to access the information contained in the metadata .

My code

So, here's what I would do:

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

      

My problem

My way seems a little overkill to me, and more importantly, it seems "static". It looks like if I update some information in Image.Meta after the Image.BandN is created, then Image.BandN.Meta won't update at the same time, right?

  • Am I setting and implementing the problem correctly?
  • What would be the smartest way to dynamically pass the Metadata attribute for a Band object?
+3


source to share


5 answers


It looks like if I update some information in Image.Meta after the Image.BandN is created, then the Image.BandN.Meta won't update at the same time, right?

No, it's not a problem; my_image.Band1.Meta

will be a reference to the same object as my_image.Meta

.

It's only if you reassign my_mage.Meta

to refer to a different object (as opposed to the mutating object it calls) that you will have a problem.

But you can check it yourself by printing id(my_image.Meta)

and id(my_image.Band1.Meta)

, or checking my_image.Meta is my_image.Band1.Meta

.

My way seems a little overkill to me, and more importantly, it seems "static".

Well, this is a bit redundant and static as it handles exactly three ranges and would require changes all over the place if you want to use the same code for, say, CMYK. If you want to do something, you might think:



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

      

Or:

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

      

Alternatively, if RGB is an integral and permanent part of, you can use names instead of numbers (just 'R'

' 'G'

, 'B'

). And then you can still put them in a collection instead of separate variables:

self.Bands = {name: Band(self.Meta, name) for name in ('R', 'G', 'B')}

      

+1


source


It looks like if I update some information in Image.Meta after the Image.BandN is created, then the Image.BandN.Meta won't update at the same time, right?

It depends on how you are performing the update. After creating your instance Image

(which I will call img

), img.Meta

and img.BandN.Meta

will be the same object.

If you assign a new value img.Meta

, it img.BandN.Meta

will not be updated as img.Meta

it is now a new object and img.BandN.Meta

is still the original.



However, if you change img.Meta

, for example img.Meta.some_attribute = new_value

, then img.BandN.Meta

it will update as well since they are still the same object.

Your code looks great as soon as you change img.Meta

instead of giving it a new value.

+1


source


This all seems reasonable.

Any method Band

, if it needs to consult the metadata, can do it with a link self.Meta

.

As an aside, consider adopting the naming convention from the Python Style Guide, that is, reserve CapitalizedWords for class names only; use lower_case_with_underscores for parameters, attributes, methods and variables. (Option Metadata

to Band.__init__

obscure the class Metadata

.)

+1


source


The OP asked: 1: Am I setting and implementing the problem correctly?
I would like to suggest an alternative (less redundant)
for implementing your class using inheritance.
The code below is written in 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...

      

+1


source


You've split the image into three classes, but Band and MetaData are tightly coupled, and Image doesn't do much. Perhaps Band is more simply represented as an array of int or floats.

Instead of trying to create a hierarchy of objects and classes, I would start with the simplest implementation. If the class gets too large or the code becomes unwieldy, you can start to separate the classes. You will find that simple, flat code is easier to change than hierarchical object hierarchies once you get to the point of cleaning it up.

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

      

+1


source







All Articles