Cole
Cole

Reputation: 2509

Python: showing attributes assigned to a class object in the class code

One of my classes does a lot of aggregate calculating on a collection of objects, then assigns an attribute and value appropriate to the specific object: I.e.

class Team(object):
    def __init__(self, name): # updated for typo in code, added self
        self.name = name

class LeagueDetails(object):
    def __init__(self): # added for clarity, corrected another typo
        self.team_list = [Team('name'), ...]
        self.calculate_league_standings() # added for clarity


    def calculate_league_standings(self):
        # calculate standings as a team_place_dict
        for team in self.team_list:
            team.place = team_place_dict[team.name] # a new team attribute

I know, as long as the calculate_league_standings has been run, every team has team.place. What I would like to be able to do is to scan the code for class Team(object) and read all the attributes, both created by class methods and also created by external methods which operate on class objects. I am getting a little sick of typing for p in dir(team): print p just to see what the attribute names are. I could define a bunch of blank attributes in the Team __init__. E.g.

class Team(object):
    def __init__(self, name): # updated for typo in code, added self
        self.name = name
        self.place = None # dummy attribute, but recognizable when the code is scanned

It seems redundant to have calculate_league_standings return team._place and then add

@property
def place(self): return self._place

I know I could comment a list of attributes at the top class Team, which is the obvious solution, but I feel like there has to be a best practice here, something pythonic and elegant here.

Upvotes: 0

Views: 161

Answers (2)

Hyperboreus
Hyperboreus

Reputation: 32429

If I half understand your question, you want to keep track of which attributes of an instance have been added after initialization. If this is the case, you could use something like this:

#! /usr/bin/python3.2

def trackable (cls):
    cls._tracked = {}

    oSetter = cls.__setattr__
    def setter (self, k, v):
        try: self.initialized
        except: return oSetter (self, k, v)
        try: self.k
        except:
            if not self in self.__class__._tracked:
                self.__class__._tracked [self] = []
            self.__class__._tracked [self].append (k)
        return oSetter (self, k, v)
    cls.__setattr__ = setter

    oInit = cls.__init__
    def init (self, *args, **kwargs):
        o = oInit (self, *args, **kwargs)
        self.initialized = 42
        return o
    cls.__init__ = init

    oGetter = cls.__getattribute__
    def getter (self, k):
        if k == 'tracked': return self.__class__._tracked [self]
        return oGetter (self, k)
    cls.__getattribute__ = getter

    return cls

@trackable
class Team:
    def __init__ (self, name, region):
        self.name = name
        self.region = region

#set name and region during initialization
t = Team ('A', 'EU')

#set rank and ELO outside (hence trackable)
#in your "aggregate" functions
t.rank = 4 # a new team attribute
t.ELO = 14 # a new team attribute

#see witch attributes have been created after initialization
print (t.tracked)

If I did not understand the question, please do specify which part I got wrong.

Upvotes: 1

Anton I. Sipos
Anton I. Sipos

Reputation: 3613

Due to Python's dynamic nature, I don't believe there is a general answer to your question. An attribute of an instance can be set in many ways, including pure assignment, setattr(), and writes to __dict__ . Writing a tool to statically analyze Python code and correctly determine all possible attributes of an class by analyzing all these methods would be very difficult.

In your specific case, as the programmer you know that class Team will have a place attribute in many instances, so you can decide to be explicit and write its constructor like so:

class Team(object):
def __init__(name ,place=None):
    self.name = name
    self.place = place

I would say there is no need to define a property of a simple attribute, unless you wanted side effects or derivations to happen at read or write time.

Upvotes: 1

Related Questions