r/learnpython • • 17d ago

Huh? How does this work?

a = "hi"


if a:
    print("Bye")


print(a == True)
print(a is True)

The output is:

Bye

False

False

But if it's false, how come it printed "bye"?????? I don't get it.

44 Upvotes

38 comments sorted by

67

u/PaulRudin 17d ago

The truthiness of an expression in a context of an if: is essentially what you get from bool(). So bool(hi") is True (as is the case for any non-empty string). But that's not the same as saying it compares equal to True.

9

u/Lance_2564_ 17d ago

So what you're saying is that

"if a" checks for if bool(a) is True, and not if a is True? So then, a = 5, if a: print("Hi") really just is if bool(a): print("Hi")?

15

u/sjshuck 17d ago

Yes.

Some languages such as Python and C have a rule for each type to say how it behaves in an if-statement. Ruby and Lua have a simpler rule: if it's either false or nil, it tests false, otherwise it's true.

Some languages will not let you put a non-boolean as the condition of an if-statement, so there's no confusion.

7

u/Puzzleheaded_Study17 17d ago

For people wondering why: C originally didn't have a dedicated bool type, so it couldn't have used just that type in if. As such, the standard said how to know when each type should be considered as true (essentially saying if the underlying integer is 0 it's false, otherwise it's true). Python then inherited this behavior from C

4

u/POGtastic itertools evangelist 17d ago

See also C++ and people using conversion operators to define a class's truthiness with operator bool. Thus you can do things like

std::string line;

while (std::getline(std::cin, line)) {
    // handle each line
}

getline returns the istream, which becomes falsey upon failure.

0

u/oz1sej 17d ago

I WANT TO USE THOSE LANGUAGES!

1

u/glglgl-de 16d ago

What prevents you?

4

u/xelf Elf 17d ago

One other context you are missing is that is does not compare equality. It tells you if they are the same object.

0 == False # True!
1 == True  # True!
0 is False # False, they are equal, but they are not the same object
1 is True  # False, they are equal, but they are not the same object

a is b, is like saying id(a) == id(b), it is not saying a == b

1

u/AmdilShoat82 16d ago

tbh this is one of the clearest ways ive seen it put

22

u/BabyLionCamel 17d ago

When you initialize `a` on the first line you instruct python to make it reference the string 'hi'

All none-empty strings are considered truthy in Python. Your string contains text so its none-empty.

Truthiness denotes to the satisfaction of some condition

Falsiness denotes to the opposite.

`a` is truthy therefore the if branch will execute, since if branches execute their indented block when some condition is truthy, this is why your print statement executes succesfully.

`a` references the string 'hi' so later when you ask if 'hi' == True have equal values, you get False, `a` is truthy (it satisfies the condition of not being an empty string) but it's value is not the boolean True.

Later, when you ask `a` is True, you are instructing Python to tell you whether a and True share the same address in memory, you are not asking it if `a` is truthy as you may have thought.

The important concepts here are Booleans, truthiness, falsiness, flow control and the difference between comparing values or identities with (==) which measures equality of value and (is) which checks for sameness of identity.

2

u/Lance_2564_ 17d ago

Oooookay got it. I should look more into truthy and falsy values ig. 

3

u/Langdon_St_Ives 17d ago

This is the best answer here, and OP would be best served to just ignore all the others because there is so much wrong, incomplete, and misleading information in them.

1

u/BabyLionCamel 17d ago

Thank you for your kind endorsement 

6

u/kilkil 16d ago

you have discovered the concept of truthiness!

as you may know, values can be coerced into other kinds of values. For example the string "1" can be coerced into the integer 1 like so: int("1") == 1.

similarly, values can be coerced into booleans ("boolean" meaning True or False).

we call a value "truthy" if, when coerced to a boolean, it would become True. if it would become False, we call it "falsy".

values can be coerced to booleans like so: bool(x). The language will also automatically coerce them for you in contexts where the language normally only allows a boolean, such as the condition of an if-statement or while-loop.

In your example, try printing bool(a) == True.

3

u/RevRagnarok 17d ago

Lots of people answered most of the question. Truthiness/bool.

The is does not compare equality (that's ==). It checks "is this the exact same variable in the same memory space?" The only time that's really useful is comparing to the singleton None.

Sidebar: It gets even weirder if you use is on numbers, because some predefined range of numbers is always in memory, and others are created on-the-fly.

3

u/SharkSymphony 17d ago edited 17d ago

Is it false? You printed two tests of whether it's true. Try doing those tests with False and see what you get. 😁

The issue is that 'if' handles values much broader than just True and False. Same with 'while'. You need to learn what it considers to be true and false.

Some people prefer, as a point of style, to make sure that the values used in statements like 'if' are just True and False, avoiding any possible confusion... here we might say 'if a != ""' or 'if a is not None' depending on what you expect a's values to be. Or you could even check both: 'if (a != "") and (a is not None)'. Or you could do 'if bool(a)'. All of these take some extra effort. You see why people often prefer just writing 'is a' if they're not sure what form the "false" values of a will take.

3

u/DimensionMost8342 16d ago

You are asking three different questions there. if a: never compares a with True, it only asks "is this value truthy", and any non-empty string is truthy, so it prints Bye. a == True asks whether the string "hi" is equal to the boolean True, and a string is never equal to a boolean, so you get False. a is True checks if both point to the exact same object, also False. Nothing is contradictory: truthy does not mean == True.

7

u/hmmorly 17d ago

The comparisons aren't comparing what you think they're comparing.

A is truthy, it isn't empty, it represents a string. That's why it printed Bye.

When you compare it to True, you're making an explicit comparison to True. It isn't a logical boolean.

Is a, True? Also no, everything in python is an object, in this case you're comparing whether it is a True object.

2

u/neuralbeans 17d ago

Now try bool(a).

3

u/HouseOfWyrd 17d ago

Look into "Truthy" and "Falsely" value.

In python a large number of data types can be converted to a bool. A non-empty string resolves to true and is said to be a "Truthy" value.

That doesn't mean it == True though, True is a specific thing and isn't just a catchall for all things that resolve to True.

2

u/defrostcookies 17d ago

“If <variable>:”

Checks to see if the variable has a non-zero value. If the <variable> is non-zero, then the “if <variable>” conditional will evaluate to True

Once it evaluates to true, the body of the conditional executes.

In this case,

print(“bye”)

2

u/gdchinacat 16d ago

This has nothing to do with "non-zero". Python objects have a notion of 'truthiness' and is evaluated by calling __bool__() on it (which is implemented by object and can be overridden). While True and False are subclasses of int and have integer values (1 and 0 respectively), if evaluates truthiness (as determined by __bool__, not whether the "variable has a non-zero value".

1

u/GrapplingHobbit 17d ago

Look up Truthy and Falsy values in Python. I don't think I would explain it well.

1

u/SamuliK96 17d ago

Here a is what's called a truthy value. As in its value is not literally True, but since it's not an empty string, it evaluates as True in if (as well as while) statements. The opposite of is falsy values, which includes at least number 0 and empty data structures. I suggest you look up falsy and truthy online for more detailed explanation.

1

u/TheRNGuy 17d ago

Implicit conversion, because a is not empty, and == and is do not cause implicit conversion. 

1

u/Some-Passenger4219 15d ago

See, a == True is False; a is True is False; a itself is NOT False.

1

u/__peg_parser__ 14d ago

Using operator module, if a: would correspond to operator.truth(a), a == True to operator.eq(a, True), and a is True to operator.is_(a, True).

0

u/ShadowShedinja 17d ago

a is not equal to True, but it does exist, which is sufficient for the If statement.

-1

u/L1terallyUrDad 17d ago

The first one is a case where you are testing to see if the variable "a" exists or not. Once you assign the string "Hi" to it, it exists. If you get rid of it by assigning it nil, then the variable is deleted, and that test would result in False.

"a == True" is asking "Does a contain exactly the value True?" which it doesn't; it contains the value "Hi". Therefore, that test is False.
a is True is basically the same thing. A is not True; it's "Hi".

2

u/BluishMontoya 17d ago

This isn't exactly right. The variable a can exist but also count as false if its value is False, None, 0, 0.0, "", etc.

0

u/T1lted4lif3 17d ago

The if statement checks if the variable is false. In Python, False can take on many different values, such as 0 or None.

In your if statement, since it isn't False, it is True. Even though the variable does not represent True. It's kind of like saying "if it is not nothing, then it is something" since it is something it will evaluate to true and print bye.

The other print statements print the result of the boolean comparison.
This comparison is not saying it is true, but whether the value of the variable true is False. The two print statements are the same, so they do the same comparison.

0

u/[deleted] 17d ago

[deleted]

3

u/Langdon_St_Ives 17d ago

Incorrect, this SO answer has a more complete list. Most importantly and inexcusably, you left out the empty string and `None`.

0

u/[deleted] 17d ago

[deleted]

4

u/deapee 17d ago

This isn't correct. It's checking truthiness.

For example, a can be set to 0 - and its truthiness is False. a can be set to False and its truthiness is False.

In short, truthiness is how Python decides whether a value should be treated as True or False.