Today i was reading someone written code and trying to understand it, but I have encountered so many times that programmers override builtin methods or set new properties , the code below is from a tutorial i came accross , I hope some one can help me out how code implementation like this is helpful, both the classes shown below are part of the same py module...

class Asset(dict):
    """
    Asset (dict)

        Container object representing an Asset somewhere on
        the filesystem. Used before for defining a new Asset
        for import, and for an Asset currently in the system.
    """    

    def __init__(self):

        super(Asset, self).__init__()

        for val in ('name', 'show', 'scene', 'image'):
            self[val] = ''


    def __repr__(self):
        """
        __repr__()

            Specifies the formatted representation of the class,
            when printing.
        """

        # Since Asset subclasses a dictionary, we can use self as a string formatter

        return "\nName: %(name)s \n\t Show: %(show)s \n\tScene: %(scene)s \n\tImage: %(image)s" % self


    # a getter property
    @property
    def name(self):
        return self.get('name', '')

    # a setter property - this make Asset.name read AND write capable.
    @name.setter
    def name(self, val):
        self['name'] = val

    @property
    def show(self):
        return self.get('show', '')

    @show.setter
    def show(self, val):
        self['show'] = val

    @property
    def scene(self):
        return self.get('scene', '')

    @scene.setter
    def scene(self, val):
        self['scene'] = val

    @property
    def image(self):
        return self.get('image', '')

    @image.setter
    def image(self, val):
        self['image'] = val  

the class above is instantiated from the method below like asset=Asset() and then dictionary keys such as scene,name, show, image are assigned values respectively from the method below.
My question is why do we need to build or why the programmer built it in such a way when he could have put the dictionary in the same method below? why does he need to set properties in the class above ?
how is it useful?

      class AssetImporter(object):
        def list(self, name='', allShows=False):
            """
            list(string name='', bool allShows=False)  ->  list(Asset,...)

            Returns a list of Asset objects currently found
            under the current show.
            If allShows == True, return matching assets in all shows.

            Specifying a name returns only Assets whose asset.name contains
            the given name. i.e.
            name = 'Asset' can return:
                MyAsset1, Asset, Asset50, OldAsset

        """

        dirs = []

        if allShows:
            for item in os.listdir(self._rootDir):
                full = os.path.join(self._rootDir, item)
                if os.path.isdir(full):
                    dirs.append(full)

        else:
            dirs.append( self._getShowDir() )



        assets = []

        for d in dirs:

            show = os.path.basename(d)

            for item in os.listdir(d):

                if item.startswith("."):
                    continue

                full = os.path.join(d, item)

                if os.path.isfile(full):

                    aName = os.path.splitext(item)[0]
                    # if a specific asset name was given, and
                    # this one isnt it.. move on
                    if name and not name in item:
                        continue

                    imgExt  = os.path.splitext(self.DEFAULT_IMAGE)[1]
                    imgFile = '%s%s' % (aName, imgExt)

                    asset = Asset()
                    asset['scene']  = full
                    asset['name']   = aName
                    asset['show']   = show 
                    asset['image']  = os.path.join(d, 'images', imgFile)    

                    assets.append(asset)


        return assets

A reason could be that the programmer wants the Asset to be a dictionary, and at the same time he/she wants to add asset-specific behavior to this dictionary. To do so, he/she subclasses the built-in dict class.

I don't think adding the properties name, scene, show, image is a very good idea: it gives 2 ways to access data, namely asset['name'] and asset.name. This could be confusing in code that uses the asset class.

This is not a typical python class, but there may be good reasons to want an object to be an instance of dict. For example, the programmer can use asset instances in functions that expect a dictionary.

Notice that the creation of properties could be factored like this

def create_asset_property(name):
    name = str(name)
    def func(self):
        return self.get(name, '')
    def func_setter(self, val):
        self[name] = val    
    func.__name__ = name
    func = property(func, func_setter)
    return func

class Asset(dict):
    """
    Asset (dict)

        Container object representing an Asset somewhere on
        the filesystem. Used before for defining a new Asset
        for import, and for an Asset currently in the system.
    """    

    def __init__(self):

        super(Asset, self).__init__()

        for val in ('name', 'show', 'scene', 'image'):
            self[val] = ''


    def __repr__(self):
        """
        __repr__()

            Specifies the formatted representation of the class,
            when printing.
        """

        # Since Asset subclasses a dictionary, we can use self as a string formatter

        return "\nName: %(name)s \n\t Show: %(show)s \n\tScene: %(scene)s \n\tImage: %(image)s" % self


    for _name in ('name', 'show', 'scene', 'image'):
        locals()[_name] = create_asset_property(_name)
    del _name

Edited 4 Years Ago by Gribouillis

a question about super..

why did he choose to do

def __init__(self):
           super(Asset, self).__init__()

in the Asset(dict) class above ?

if super is initializing parent class(dict) before initialize Asset()" by calling its default constructor

why cant he just use dict.__init__(self) ?

Edited 4 Years Ago by krystosan

He can. In python 2 it is more natural to write dict.__init__(self), and super is not very useful. In python 3, one can write super().__init__(), and this is useful because there is no explicit reference to the class.

In python 2, there is a difference only in the case of multiple ancestor classes

>>> class A(object):
...  pass
... 
>>> class B(object):
...  def __init__(self):
...   print "B.__init__() called"
... 
>>> class C(A, B):
...  def __init__(self):
...   super(C, self).__init__()
... 
>>> c = C()
B.__init__() called
>>> from inspect import getmro
>>> getmro(C)
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)

here, super(C, self).__init__() calls B.__init__() because there is no __init__() method in class A, and the method is searched in C's mro (but C itself).

Edited 4 Years Ago by Gribouillis

ok so now i understand super, and it doesnt seem real benefit of using it if its not multiple inheritence.. if we can superclass.__init__(self)... thank you Griboullis...

This article has been dead for over six months. Start a new discussion instead.