Fredrik Tolf <[EMAIL PROTECTED]> wrote: ... > I'm relatively new to Python, and one thing I can't seem to get over is > the lack of in-expression assignments, as present in many other > languages. I'd really like to know how Python regulars solve the > problems posed by that.
In general, we've learned to do without and structure our code differently -- less compactly, more "airy". Python is not about maximally compact code -- other languages of roughly equivalent power, such as Perl, are more suitable if that's your goal; in Python, we aim for less compactness and more readability (and maintainability). E.g.: > if callable(f = getattr(self, "cmd_" + name)): > # Do something with f > elif callable(f = getattr(self, "cmdv_" + name)): > # Do something else with f might become: f = getattr(self, "cmd_" + name) if callable(f): # Do something with f else: f = getattr(self, "cmdv_" + name) if callable(f): # Do something else with f 7 lines instead of 4 (if the comments stand for one line each), but exactly the same semantics. > Another common problem for me are while loops. I would often like to do That's part of why Python often prefers for loops -- with a generator to handle the "looping logic" part, if needed. For example, > while (pos = somestring.find("/")) != -1: > part = somestring[:pos] > somestring = somestring[pos + 1:] > # Handle part might often become a simple: for part in somestring.split('/'): # handle part but that has slightly different semantics (handles the part after the last occurrence of / too, doesn't explicitly record pos, ...) which might be adjusted if needed (e.g. with a [:-1] after the call to split and before the colon to omit the last part). If the adjustment is "major", e.g. you do need every variable to be set just like so in the body, then a generator can help -- with the focus being on a separation between the business logic (the "handle part" processing) and the plumbing (generate all 'parts' in sequence), and the latter going in the generator, not distracting from the handling as may happen when you mix the two things. The business-logic part will always look like: for pos, part in splitter(somestring, '/'): # handle part, using pos as well and the splitter generator is written elsewhere, a la def splitter(somestring, separ): while True: pos = somestring.find(separ) if pos == -1: break yield pos, somestring[:pos] somestring = somestring[pos+1:] with the big advantage that you may change the implementation to be more efficient, if and when needed, without touching the business logic part which remains nestled in the nice, simple, readable for loop. for example: def splitter(somestring, separ): pos = 0 while True: nextpos = somestring.find(separ, pos) if nextpos == -1: break yield nextpos-pos, somestring[pos:nextpos] pos = nextpos+1 Same semantics, less busywork, so presumably faster (the timeit module exists to let you check the speed of code fragments, of course). All this being said, I do sometimes find myself coding a first version of some algorithm by following as closely as possible some published reference code or pseudocode, before enhancing it to be clearer, more efficient, more Pythonic, or whatever. When that happens, some syntax sugar to "assign and test in the same expression" does come in handy, to enable coding of a first version that's closer in spirit to the non-Python reference version. It was, of course, no trouble at all to make myself an "assign and test in the same expression" snippet, and I (again, of course) published it in the Python Cookbook (both online and printed editions) for others' benefit. For example: class Holder(object): def set(self, value): self.value = value return value data = Holder() Now, with this tiny piece of "plumbing adapter", you can code, e.g.: while data.set(somestring.find("/")) != -1: part = somestring[:data.value] somestring = somestring[data.value + 1:] # Handle part Another use case for this Holder class is when you're using Python to prototype something that you already know will need to be recoded in another given language once it's ready -- the motivation is similar to the one for the main use case of "code as close as possible to a published reference implementation", namely enabling Python code that is closer to what's idiomatic in some other language than to idiomatic Python itself. Therein, of course, lies the danger -- over-relying on this adapter may mean you never really learn to "think the Python way" and thus to code idiomatic Python, even when that would be most appropriate (i.e., in most cases). Still, Python _is_ a "consenting adults" language, so I think it's appropriate to show how its power can easily let you keep using idioms coming from different languages... even when that usage is not the optimal choice that you could and should make, it's up to you. Alex -- http://mail.python.org/mailman/listinfo/python-list