-1

Here is simple ST plugin. Is there a difference between commented lines? Personally, I don't see any difference in how they work, just a difference in visual appearance.

However, some plugin developers prefer second version (== 1), which looks just useless and ugly for me. Probably there are some reasons to prefer it?

import sublime_plugin

class ExpandUnexpandTabsCommand(sublime_plugin.EventListener):
    def on_pre_save(self, view):

        # if view.settings().get("translate_tabs_to_spaces"):
        # if view.settings().get("translate_tabs_to_spaces") == 1:
        # if view.settings().get("translate_tabs_to_spaces") == True:
            view.run_command("expand_tabs")
        else:
            view.run_command("unexpand_tabs")
user90726
  • 939
  • 1
  • 8
  • 28
  • 3
    It depends. What are the possible values in the settings files? In Python, `if spam:` is a test for whether `spam` is truthy. If `spam` has to be a number, and you want to test nonzero-ness, `if spam:` is fine; if you test `if spam == 1:`, you're saying you want it to fail on `2`. If `spam` has to be a boolean, `if spam:` is good and `if spam == 1:` is terrible and misleading. If `spam` could be either `None` or some valid object, you want `if spam is not None:`; `if spam:` may seem to work, until `[]` or `0` is a valid object. And so on. Understand what you're writing, write what you mean. – abarnert Aug 01 '18 at 01:03
  • This question is probably off-topic because it is likely to attract opinion-based answers. That said, since all values in Python have a boolean value, the `== True` looks really silly for me. The `== 1` looks silly unless you are actually testing for the value being exactly 1. So IMO the idiomatic choice is to omit the `==` operator. – Paulo Scardine Aug 01 '18 at 01:04
  • @PauloScardine `== True` has a specific idiomatic meaning: it's for the (very rare) case when you want the test to be true for the specific value of `True`, or for anything else which declares itself `== True`, but not for other truthy values like `17` or `{1, 2, 3}` or `object()`. If that's not what you mean, you shouldn't write `== True`. It's not just silly, it's actively misleading. – abarnert Aug 01 '18 at 01:08
  • @abarnert How about `is True`? – Paulo Scardine Aug 01 '18 at 01:10
  • @PauloScardine That's slightly less rare: you want the test to pass for `True`, but not for anything else, not even allowing for classes that declare themselves `== True`. – abarnert Aug 01 '18 at 01:11
  • @abarnert are you talking about a class that places a `return other is True` inside `def __eq__(self, other)`? This is funny, never saw this in the wild. – Paulo Scardine Aug 01 '18 at 01:16
  • @PauloScardine Well, it would probably `return other is True or `, but yeah, it's hard to imagine a case where you'd want to write such a class, much less a case where you'd need to test for the possibility that someone wrote such a class and stuffed an instance of it in a config somehow. – abarnert Aug 01 '18 at 01:20

3 Answers3

4

This is covered in PEP8, the official Python style guide's, "Programming Recommendations" section:

  • Don't compare boolean values to True or False using ==.

    Yes: if greeting:

    No: if greeting == True:

    Worse: if greeting is True:

In other parts of the guide, they emphasize this for other use cases (e.g. testing for empty/non-empty collections should not use len()); unless a specific value is critical to your logic, use the implicit boolean nature of what you're testing (with not if it must be inverted), don't spin your wheels with comparisons that ultimately add little in terms of readability, increase fragility, and slow your code to boot.

The only reason to prefer the other approaches is if you expect there to be other truthy values that should not count as truthy. In this case, the translate_tabs_to_spaces setting is very clearly boolean in nature, so you almost certainly want to handle any truthy value the same way; if they later redesigned the setting to have a numeric value, where 0 meant "don't translate" and any positive value meant the number of spaces each tab was worth, implicit truthiness evaluation would continue to work, but for the standard four space indents, a test for == 1 or == True would suddenly decide no translation was occurring.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Well, if it is in PEP8 its officially idiomatic and not just my opinion. This is the right answer. – Paulo Scardine Aug 01 '18 at 01:27
  • I can't se the case for `if something == True`. There is no difference at all to `if something` (well, there is the silly case where someone can override `__eq__` to mask a `is True` test but I would write it off as a stinky code smell in Python). – Paulo Scardine Aug 01 '18 at 01:32
  • @PauloScardine: Agreed. In *very* rare cases I might use `is True`; I'd never use `== True` unless I wasn't actually using it in a boolean context at all, e.g. where you expect `==` to be overridden to produce a special query object (part of an ORM like SQLAlchemy or the like, where a `.filter(Table.some_column == True)` makes some sense, though even then, I'd sort of hope the ORM knew how to handle boolean columns without requiring the use of `== True`). – ShadowRanger Aug 01 '18 at 01:35
  • @PauloScardine Examples I've seen (not counting ones that return an ORM query or NumPy bool array or the like) include an equals-everything object to affect stable sorting/tree-balancing/etc., and a proxy object that wanted to treat proxied `TRUE` (or whatever) as much like native `True` as possible. If you're expecting such a type, anywhere you would use `is True` (which is already rare at best), you'd want to use `== True` instead. It's rare enough, and weird enough, that I'd definitely double-check the type's docs or code first, but if that's what they intended, it's not silly, just weird. – abarnert Aug 01 '18 at 17:52
  • Ok, I concede it is a tribute to the "we are all consenting adults" in Python but while it allows some DSL magic it is definitely is a code smell for more general code. – Paulo Scardine Aug 02 '18 at 21:50
2

It depends on what the possible values are.

  • If the file must have 0 or 1 in it, anything else is an error, and you're reading it as an int, then you probably want == 1.
  • If the file can have either True or no entry at all, and you're using get(…) instead of [] so you get back None whenever it's not True, then you want to just test the truthiness. (Or maybe is not None, but definitely not == True or == 1.)

The rule is pretty simple: when writing a test, write what you mean to test.

Different tests mean different things:

  • if spam:: passes if spam is anything truthy. That means anything besides None, False, numeric zero, or empty containers.

  • if spam == 1:: passes if spam is the number 1.

  • if spam is True:: passes only if spam is the special constant True. If you want to make sure other truthy values fail, and only True counts, use is. You rarely want this.

  • if spam == True:: passes if spam is the special constant True, or some object equal to it. If you've gone out of your way to write a class whose __eq__ tests for True or something, then you might want this test, but it's hard to imagine why you would otherwise.

It happens to be true that 1 == True. But writing == True when you want to test for the number 1, or == 1 when you want to test for True but not other truthy values, is misleading to anyone who understands idiomatic Python, and mildly confusing to anyone who doesn't, and there's no benefit to anyone. So don't do it.

And writing either of those when you want to test for anything truthy isn't just misleading, it's wrong.

abarnert
  • 354,177
  • 51
  • 601
  • 671
1

if view.settings().get("translate_tabs_to_spaces") is more concise and readable. There is little if ever any need to compare a Boolean to another Boolean value, and using integers of 0 and 1 to denote a Boolean value should only be considered when the programming language does not support Boolean values.

blhsing
  • 91,368
  • 6
  • 71
  • 106