-3

Is there any way I can assign a variable from a complex calculation? I know I can create a function and use that, but sometimes that's overkill. I would like to assign a variable from a complex calculation without declaring a bunch of local variables.

Take these statements for example, I'm only interested in using the 'total_days' variable from now on, but putting the calculation all on a long line is messy:

days_until = (self.last_date - self.first_date).days   
opening_time = datetime.combine(self.last_time, EXCHANGE_OPEN_TIME)
time_open = self.last_time - opening_time
ratio = time_open.total_seconds()
    /EXCHANGE_OPENING_HOURS.total_seconds()
total_days = days_until + ratio if ratio < 1 else days_until + 1

In my mind, I would like to use something like:

total_days = (
     days_until = (self.last_date - self.first_date).days
     time_open = self.last_time - opening_time
     ratio = time_open.total_seconds()
         /EXCHANGE_OPENING_HOURS.total_seconds()
     return days_until + ratio if ratio < 1 else days_until + 1
     )        
ni9e
  • 151
  • 1
  • 11
  • 1
    You're looking for a solution to a non-problem. What's the matter with declaring a bunch of locals to break up lines? – Two-Bit Alchemist Nov 19 '15 at 21:19
  • Can you at least show an ideal behaviour in some pseudocode or similar solution in other language. Is rather unclear what you are trying to achieve here. – Łukasz Rogalski Nov 19 '15 at 21:20
  • It makes the code messy. If it's a series of long calculations I need to make up a series of long names to avoid ambiguity. If this was a small function I could have used short throw away variables. But creating a lot of small functions doesn't do anything for readability. – ni9e Nov 19 '15 at 21:23
  • @ni9e 'Messy' is subjective, but consider this: assuming you do this imperatively (one calculation after the other, no functions), is a series of short steps each producing one-time-use locals really _messier_ than one big long line? This is not to mention how much more error-prone and difficult to debug one-liners can be. Beyond that, if you think breaking code down into functions makes it less readable, I suppose we'll just have to agree to disagree on that point. – Two-Bit Alchemist Nov 19 '15 at 21:27
  • @Two-BitAlchemist Yes, true that. But I really love list comprehensions, and they make the code more readable, or conditional assignments. – ni9e Nov 19 '15 at 21:29
  • 1
    If you think breaking code down into separate functions is bad you should check this out http://nbviewer.ipython.org/url/norvig.com/ipython/Probability.ipynb – Padraic Cunningham Nov 19 '15 at 21:29
  • 1
    @PadraicCunningham I think you a word but yes! – Two-Bit Alchemist Nov 19 '15 at 21:34
  • @Two-BitAlchemist, indeed – Padraic Cunningham Nov 19 '15 at 21:34
  • If you are allergic to functions, you could probably use properties instead when the calculations are simple as in the example and you don't pass any arguments anyway (thought maybe you should) http://stackoverflow.com/a/16849769 – user44 Nov 19 '15 at 21:43
  • I note with some interest that you actually _do_ use the locals you're objecting to more than once. If you were to rewrite your calculation as a single line with no additional locals, you'd have to calculate some stuff twice which you are currently storing. I think the only solution to this without a function (still using locals just in another scope) is simply to call `del days_until, time_open, ratio` after your calculation, but I just don't see the point. – Two-Bit Alchemist Nov 19 '15 at 21:53

1 Answers1

0

Here is your code sample (I stripped out self for a bit of extra clarity):

days_until = (last_date - first_date).days   
opening_time = datetime.combine(last_time, EXCHANGE_OPEN_TIME)
time_open = last_time - opening_time
ratio = time_open.total_seconds() / EXCHANGE_OPENING_HOURS.total_seconds()
total_days = days_until + ratio if ratio < 1 else days_until + 1

Everything is broken into short, readable lines. The result of each calculation is stored into a neat name that indicates what it is. Will you ever use the intermediate steps again? Perhaps not. But suppose a bug is found with this calculation. Can you see how by having it in discrete steps like this makes it simple to find where things go wrong?

Moreover, it's interesting that you say you're only interested in total_days from this point on. It's not that your locals (days_until, opening_time, time_open, ratio) are not useful: to rewrite your calculation in a single line without them would not only be unwieldy in the extreme, but would require the calculation of some parts twice (like where you write ratio if ratio).

I'm not sure what the objection is here, except that this somehow "pollutes" the local scope. (What else is local scope for?) A common solution to this, which your question precludes, would be to turn this calculation into a small function. Not only would it then be more reusable, but all your locals would be confined to the small function's scope, and wouldn't bother the larger scope you're working in (which I guess by your code sample is some class's method).

Without doing this, the only way left to "clean up" the scope is del. So after your last statement (setting total_days), you would write:

del days_until, opening_time, time_open, ratio

Hopefully this makes as little sense to you as it does to me. The cost of deleting these references (CPU time) vs leaving them in memory is, to me, unjustifiable. Since this is the last available solution and seems completely pointless, I leave you with my initial assessment: you were right in the first place, your code is fine, and this is a non-issue.

Two-Bit Alchemist
  • 17,966
  • 6
  • 47
  • 82