10 ms·
Can you give an actual example of some well-written Python code that you can't fit maxExchangeBufferLengthBytes in? It's a bit handwavey otherwise. I'm also a
by sago 11y ago
Can you give an actual example of some well-written Python code that you can't fit maxExchangeBufferLengthBytes in?
It's a bit handwavey otherwise. I'm also a long-names fan, sometimes I go overboard, but in 20 years I've not been able to logically break my line in an obvious place only once or twice.
- RussianCow 11y agoIf you add two of those variables and assign the result to another variable, you're already at about 96 characters before considering whitespace. I don't think it's that hard to exceed 80 characters doing very simple things.
- sago 11y agoYou mean this_is_my_very_long_variable_name = ( this_is_one_variable_that_goes_into_calculating_it + this_is_another_variable_that_needs_considering) The issue wasn't the fact that some expressions are longer than 80 cols (that one is longer than 120, even, its 136 characters minimum), but that they can't be clearly and appropriately written in 80 cols.
- RussianCow 11y agoThat example is pretty trivial, but I'd hate to read code where every other logical line is broken up into multiple. It breaks up the flow of the code and makes it much harder to read, especially with how the indentation constantly changes (which is especially important in a language like Python, because I've trained my eyes to the special meaning of whitespace, so seeing non-significant indentation adds additional noise).
- sago 11y agoRight, but again, can you see you've just gone abstract and handwavey. I'd also hate to read code where every other line is broken midway through an expression. Can you give an example of code that 80cols would force that on, which doesn't have deeper issues of clarity and structure? It's not a trick question. I've written millions of lines of code over 20 years, and I've been renowned for using overly long names (compared to most Python coders), but I've not found that issue. Some breaks, yes, but never 'every other line', or even nearly that.
- RussianCow 11y agoYou're right, I don't write much Python anymore and don't have an example on hand. But I write Swift for a living now, and I know that if I restricted my lines to 80 characters wide, I would have to split up a lot of lines, including most method definitions. I much prefer the long lines, because if the details aren't important, they're easier to skip, and they're much easier to scan through when you're trying to read a large amount of code at once.
- sago 11y agoThanks, its a good point. I've only played with swift, but I've written a fair amount of objective C, and I didn't put 80 cols in coding standards for my company for that. We got away with that because the environment was fixed. And the path of least resistance was to use it in the way Apple told you to. You couldn't even split XCode more than two ways back then (iirc). So the issue of different tools, different screen layouts, and different workflows didn't raise. So yeah, 80cols isn't a panacea across all languages.
- pyre 11y agoFrom current production code: class VendorOrderShipmentResource(): ... def post(...): ... for item in data.order_items: ... if not shipment_qty: abort(400, message='All order_items must have a quantity_to_ship.') That line goes out to col 86. I realize that it's possible to break it like this (#1): abort( 400, message='All order_items must have a quantity_to_ship.') or this (#2): abort( 400, message='All order_items must have a quantity_to_ship.' ) or this (#3): msg = 'All order_items must have a quantity_to_ship.' abort(400, message=msg) or this (#4): abort(400, message='All order_items must have a ' 'quantity_to_ship') I'm not really a fan of any of those: 1. I'm not a fan of this one, in this case at least, because it "looks weird" due to the mismatch between the length of the function name, and the length of the next line. Also, I'm not a fan of "hiding" the closing parenthesis at the end of the line, rather than putting it on new line at the original indent level (like #2). 2. I'm not really a fan of this because the first argument and the function name are so much shorter than the message argument, that it looks really lopsided. 3. I'm not a fan of this because it seems stupid to create a new variable just to use it on the next line (and never again). 4. I'm not really a fan of breaking strings up this way, but sometimes I'm forced to. Breaking strings up this way tends to be really fragile when you want to modify them, and might need to reflow the entire wrap. Personally, I'm just a fan of increasing line length to ~100. The number of things that go over 100 columns (in practice) is much smaller than the number of things that go over 80 columns.
- sago 11y agoThank you. Why is 3 stupid? That would be my preference. It is clear, simple and gets compiled away (in many cases). I alias in variables frequently, to make things more explicit. For example, I might write iterations = 300 for _ in range(iterations): ... which makes it less likely I'll end up repeating things or copy and pasting when new cases come up, e.g. if not shipment_qty: abort(400, message) elif shipment_qty < 0: abort(400, message) What happens in your case if you come back and edit the message and add a few characters, exceeding your longer line length? When I'm forced to break a string it is usually an indication that I need a better way of defining text than inline in expressions in code.
- bsder 11y ago> Can you give an actual example of some well-written Python code that you can't fit maxExchangeBufferLengthBytes in? Sure: thisIsAnOutgoingBuffer = this_is_a_function(descriptiveKeywordArg = maxExchangeBufferLengthBytes, ...) It's been a while, but I seem to recall that Python would require a continuation character to break anywhere prior to the comma.
- sago 11y agoNo continuation character needed outgoing_buffer = a_function( descriptive_keyword=max_exchange_buffer_length_bytes ...) Breaks nice and semantically. Calling functions with arguments on new lines is very pythonic, so much so that it is a lot of the examples of indentation in PEP8. For functions with more arguments, it is readable for the same reason that you might want to define variables on successive lines. Interestingly, notice that in your quick back-of-the-envelope example your variable and function names are quite redundant. I know it was throwaway and it wasn't your point: I'm not suggesting you were holding it up as good naming, but it is interesting that the toy examples being quoted have to work quite hard to make it bad. That suggests to me that a lot of the problem is manufactured, in practice.
- bsder 11y agoHuh? I could have sworn that Python didn't allow a break after a function call. There is something odd in the grammar that does weird things that I have tripped over that forced me to use a continuation character where I really wanted to just use a line break. And, it should be Python because what I'm remembering would need to be a whitespace-delimited language. I'll leave it up to the language lawyers to find. :) > Interestingly, notice that in your quick back-of-the-envelope example your variable and function names are quite redundant. Agreed. The keyword argument is likely to specify things like "maxBufferLengthBytes" even as the variable does. The problem is that they serve two different purposes. The variable is moving around the program and needs to carry it's meaning with it, while the keyword argument serves to document the API that the function is part of. Because they are orthogonal, they are redundant. In the end, the goal is productivity. I can live in 80 characters if I have to, but, if I'm in charge, it's 120-130. Raymond's warning about reformatting introducing bugs is spot on though.
- pjtr 11y agoCan I ask about a similar real problem I had a few times? How would you format this code? class Batman(): # ... def handle_jokes(self, villains): for villain in villains: if villain.supports_jokes: formats, transports = villain.query_joke_formats_and_transports() # ... That long line is 82 characters. Assume there's a good reason formats and transports are queried together. In practice this leads to variable names f and t. :(
- mherrmann 11y agoI would rename query_joke_formats_and_transports to jokes.
- sago 11y agoquery = villain.query_joke_formats_and_transports() formats, transports = query or formats, transports = ( villain.query_joke_formats_and_transports()) or formats, transports = \ villain.query_joke_formats_and_transports() Of which, we tend to do the first. Again, the longer version is clearer and simpler, but the shorter version is not so confounding that it is a slamdunk argument for longer lines, particularly as, for any length line, you could get this problem, so you'll have to do something like it eventually. If you're seeing this all over the place, it may be worth wrapping the API in more pythonic terms. 'Getters' taking no arguments, for example, are often a code-smell in python, though queries (as in your case) are a good exception, since it is also not great to have properties do expensive work (like querying a DB, say).