[Python-ideas] Inline Functions - idea

Chris Angelico rosuav at gmail.com
Wed Feb 5 22:16:17 CET 2014


On Thu, Feb 6, 2014 at 6:48 AM, Alex Rodrigues <lemiant at hotmail.com> wrote:
> I'm not under any illusions about how hard it is to actually get something
> added to standard python . But I thought this would be a fun and informative
> undertaking that possibly even helps people. Thank you for your kind words.

A good discussion is seldom a waste of time. :)

> After some consideration I have come up with another use case that
> demonstrates a little more of how this might be useful:
> Let's say that I am a weather forecaster and I maintain a large library of
> different simulation techniques. All the techniques need to get their
> initial data from some database. Let's take a look at some way of writing
> this code and their advantages/disadvantages:
>
> Classes - This is probably the best option currently available. Make a
> simulation class that has a initialize function and have each simulation
> inherit from it. This also has some drawbacks though, since I must now
> instantiate a copy of the object to find the output of the simulation, which
> makes calling the function harder (especially on a one time basis).

This was my immediate thought on reading your description. Either
that, or your start_simulation function is really a single simple
class. Try this:

class simulation(object): # the explicit inherit is optional in Py3
  def __init__(self):
    self.date = datetime.utcnow()
    self.date.replace(tzinfo=utc)
    self.start_data =
urllib2.urlopen('http://www.source.com/seed_sims').read().split()
    self.num_clouds = int(start_data[0])
    self.temp = float(self.start_data[1])
    # List comprehension is simpler than the nested loop
    self.grid = [[0]*int(self.start_data[3]) for _ in range(int(start_data[2]))]

def sim_basic():
    sim = simulation()
    return sim.temp

def sim_iterative():
    sim = simulation()
    for row in sim.grid:
        # You had this, which won't work anyway:
        # for cell in row:
            # cell = random.random()
        for i in range(len(row)):
            row[i] = random.random()
    for i in range(10):
        for row in sim.grid
            # Again, modifying cell wouldn't work
            for i in range(len(row)):
                row[i] += random.random()-0.5
    return average([cell for row in sim.grid for cell in row])

def sim_clouds():
    sim = simulation()
    return sim.temp - sim.numclouds/10.


As you see, it's a very straight-forward translation (apart from the
bits that I had to change because Python's iteration isn't done with
writable references). It's easy to add more to the namespace - and
there's no way that it can accidentally collide with a variable name
used elsewhere in the simulation. With your model, suppose you wanted
to have start_simulation return a thing called 'row'... oops, it's
been overwritten by sim_iterative, that's not good. With my model, the
new thing would be called self.row or sim.row, so it won't collide.
Yes, it's slightly more typing; and when you refactor something (say
you find that 95% of your sim_*() functions are deriving the value
temp_per_cloud from self.temp and self.num_clouds - yeah, I know,
shows how much I know about weather), you have to stick 'sim.' in
front of it. But it's guaranteed to be safe. It gives a pretty big
benefit in readability, since you know where to go looking for
something. Remember, assigning to a name inside a function makes it
local; anything you _don't_ assign to is automatically global. That
means that you could be happily referencing a global, but then
start_simulation gets updated to assign to that name... now your
code's broken. This will be very confusing.

I'm sure there are situations where inline blocks are extremely
useful. I'm just concerned that, in a language where scoping is
defined by fairly free rules based on assignment, it'd be way too easy
to have the inline block break stuff all over the place.

ChrisA


More information about the Python-ideas mailing list