TimGJ
TimGJ

Reputation: 1654

How do I refer indirectly to a method defined in a class when I have multiple ojects

Sorry for the clumsy title of the question but I can't think of a suitable way to express it. I am working on a calendar-type application in Python 2.7. I have a class Day which has a constructor of the form

def __init__(self, d):
    # Date in datetime.date format
    self.date = d

    # Julian date
    self.julian = date_utils.calendar_util.gregorian_to_jd(d.year, d.month, d.day)

    # Sun and moon rise and set times
    self.sun = RiseSet()
    self.moon = RiseSet()

...

def SetSunRise(self, t):
    assert type(t) is datetime.time
    self.sun.rise = t

def SetSunSet(self, t):
    assert type(t) is datetime.time
    self.sun.set = t

where RiseSet is a simple class:

def __init__(self, r=None, s=None):
# rise (r) and set (s) times should normally be datetime.time types
# but it is possible for there to 
# be no sun/moon rise/set on a particular day so None is also valid.

    if r is not None:
        assert type(r) is datetime.time
    if s is not None:
        assert type(s) is datetime.time
    if r is not None and s is not None:
        assert r < s

    self.rise = r
    self.set = s

Obviously there is a Day object for each day in a particular calendar. These are contained in a dictionary (keyed on datetime.date) called days. Now I have four lists containing the sun/moon rise/set times for the period in question: sunrises, sunsets, moonrises, moonsets and want to set the sun/moon rise/set times for each Day in days.

Now I could just have four separate loops going through each of the four lists. But what I really want to do is effectively use something like a pointer to a function so I could have something like:

for (func, obj) in zip([Day.SetSunRise, Day.SetSunSet, Day.SetMoonRise, Day.SetMoonSet], [sunrises, sunsets, moonrises, moonsets])

So effectively what I'm trying to do is get a pointer to a function but based on the class definition not the individual object/instance of that class. I'm sure there must be some simple, elegant way to do this but I am currently stumped.

Anybody?

Upvotes: 0

Views: 70

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1123410

You are almost there. You can do just that, refer to the unbound method on the Day class, then pass in an instance to invoke that method.

In other words: Day.SetSunRise is a reference to an unbound method waiting for you to call it with a Day() instance:

someday = Day()
Day.SetSunRise(someday, some_sunrise_time)

Unbound methods, like functions, are objects and you can store them in lists, etc:

for meth, timestamp in zip([Day.SetSunRise, Day.SetSunSet], [sunrise, sunset]):
    meth(someday, timestamp)

Now all you need to do is loop over your sunsets, your sunrises, etc. zip those up (or otherwise combine them) with their matching Day instances and for you to call the method.

Upvotes: 1

Related Questions