Items inheriting attributes from its container?

Jan Kaliszewski zuo at chopin.edu.pl
Sat Aug 22 20:56:08 EDT 2009


23-08-2009 Kreso <kkumerNOTTHIS at thatfamoussearchenginesmail.com> wrote:

> I would like to create a list-like container class so that, additionally
> to usual list methods, I could attach attributes to the container  
> instances.
> However, I would like it so that the items contained in the particular
> instance of container somehow 'inherit' those attributes i.e.
>
> cont = Container()
> cont.color = 'blue'
> cont.append(item)
> print item.color
> 'blue'

[snip]

> class Player:
>     """Class for items"""
>
>     def __init__(self, playerdata, team):
>         self.data = playerdata
>         for key in team.__dict__:
>             setattr(self, key, team.__dict__[key])
>         return
>
>
> class Team(list):
>     """Class for containers"""
>    def __init__(self, teamdata, playerdata):
>         for key in teamdata:
>             setattr(self, key, teamdata[key])
>         for item in playerdata:
>             self.append(Player(item, self))
>         return
>
> lakersdata = {'name' : 'Lakers', 'kitcolor' : 'yellow'}
> lakersplayers = [['Kobe', 'PG', 12, 123], ['Kareem', 'FW', 23, 345]]
>
> lakers = Team(lakersdata, lakersplayers)

[snip]

> p1 = lakers[1]
> print p1.kitcolor

[snip]

> lakers.kitcolor = 'blue'
> print p1.kitcolor

[Not tested. I believe that the idea is clear]


   class RecruitmentError(ValueError):
       """Raised when a player cannot be recruited."""


   class Player(object):
       """A potential item of a Team() instance."""

       def __init__(self, playerdata, team=None):
           self.data = playerdata
           self.team = None
           if team:
               team.append(self)

       # (called when the usual attribute lookup didn't succeed)
       def __getattr__(self, name):
           return getattr(self.team, name)

       # ^ the last method may not be necessary -- you can always
       #   access to team data via 'team' attribute
       #   (and 'explicit is better than implicit')


   class Team(list):
       """A container for Player() instances."""

       def __init__(self, teamdata, playerdata=None):
           for key in teamdata:
               setattr(self, key, teamdata[key])
           for data in playerdata:
               self.append(Player(data))

       def _validate_and_get(self, index=None, player=None):
           if player is not None and not isinstance(player, Player):
               raise TypeError('A Player instance is required')
           if index is not None:
               if isinstance(index, slice):
                   raise TypeError('Slicing is not allowed')
               return self[index]  # (raise IndexError for bad index)

       _validate = _validate_and_get

       def _recruit(self, player):
           if player.team is None:
               player.team = self
           else:
               raise RecruitmentError('Player %s has already recruited')

       def _dismiss(self, player):
           player.team = None

       def __setitem__(self, index, player):
           current = self._validate_and_get(index, player)
           if player is not current:
               self._recruit(player)
               self._dismiss(current)
               list.__setitem__(self, index, player)

       def __delitem__(self, index):
           player = self._validate_and_get(index)
           self._dismiss(player)
           list.__delitem__(self, index)

       def append(self, player):
           self._validate(player=player)
           self._recruit(player)
           list.append(self, player)

       # and similarly:
       # * def extend...
       # * def insert...
       # * def pop...
       # * def remove...

...if you really need ordered container (reflecting functions/hierarchy
of players in a team?).

Otherwise, as Stephen noted, you should subclass set rather than list.

Cheers,
*j

-- 
Jan Kaliszewski (zuo) <zuo at chopin.edu.pl>



More information about the Python-list mailing list