A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://www.npmjs.com/package/wtfpython below:

wtfpython - npm

What the f*ck Python! 🐍

An interesting collection of surprising snippets and lesser-known Python features.

Translations: Chinese 中文

Python, being a beautifully designed high-level and interpreter-based programming language, provides us with many features for the programmer's comfort. But sometimes, the outcomes of a Python snippet may not seem obvious to a regular user at first sight.

Here is a fun project to collect such tricky & counter-intuitive examples and lesser-known features in Python, attempting to discuss what exactly is happening under the hood!

While some of the examples you see below may not be WTFs in the truest sense, but they'll reveal some of the interesting parts of Python that you might be unaware of. I find it a nice way to learn the internals of a programming language, and I think you'll find them interesting as well!

If you're an experienced Python programmer, you can take it as a challenge to get most of them right in first attempt. You may be already familiar with some of these examples, and I might be able to revive sweet old memories of yours being bitten by these gotchas 😅

PS: If you're a returning reader, you can learn about the new modifications here.

So, here we go...

Table of Contents Structure of the Examples

All the examples are structured like below:

▶ Some fancy Title *

The asterisk at the end of the title indicates the example was not present in the first release and has been recently added.

# Setting up the code.

# Preparation for the magic...

Output (Python version):

>>> triggering_statement

Probably unexpected output

(Optional): One line describing the unexpected output.

💡 Explanation:

Note: All the examples are tested on Python 3.5.2 interactive interpreter, and they should work for all the Python versions unless explicitly specified in the description.

Usage

A nice way to get the most out of these examples, in my opinion, will be just to read the examples chronologically, and for every example:

PS: You can also read WTFpython at the command line. There's a pypi package and an npm package (supports colored formatting) for the same.

To install the npm package wtfpython

$ npm install -g wtfpython

Alternatively, to install the pypi package wtfpython

$ pip install wtfpython -U

Now, just run wtfpython at the command line which will open this collection in your selected $PAGER.

👀 Examples Section: Strain your brain! ▶ Strings can be tricky sometimes *

1.

>>> a = "some_string"

>>> id(a)

140420665652016

>>> id("some" + "_" + "string") # Notice that both the ids are same.

140420665652016

2.

>>> a = "wtf"

>>> b = "wtf"

>>> a is b

True

 

>>> a = "wtf!"

>>> b = "wtf!"

>>> a is b

False

 

>>> a, b = "wtf!", "wtf!"

>>> a is b

True

3.

>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'

True

>>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'

False

Makes sense, right?

💡 Explanation: ▶ Time for some hash brownies!

1.

some_dict = {}

some_dict[5.5] = "Ruby"

some_dict[5.0] = "JavaScript"

some_dict[5] = "Python"

Output:

>>> some_dict[5.5]

"Ruby"

>>> some_dict[5.0]

"Python"

>>> some_dict[5]

"Python"

"Python" destroyed the existence of "JavaScript"?

💡 Explanation ▶ Return return everywhere!

def some_func():

    try:

        return 'from_try'

    finally:

        return 'from_finally'

Output:

>>> some_func()

'from_finally'

💡 Explanation: ▶ Deep down, we're all the same. *

Output:

>>> WTF() == WTF() # two different instances can't be equal

False

>>> WTF() is WTF() # identities are also different

False

>>> hash(WTF()) == hash(WTF()) # hashes _should_ be different as well

True

>>> id(WTF()) == id(WTF())

True

💡 Explanation: ▶ For what?

some_string = "wtf"

some_dict = {}

for i, some_dict[i] in enumerate(some_string):

    pass

Output:

>>> some_dict # An indexed dict is created.

{0: 'w', 1: 't', 2: 'f'}

💡 Explanation: ▶ Evaluation time discrepancy

1.

array = [1, 8, 15]

g = (x for x in array if array.count(x) > 0)

array = [2, 8, 22]

Output:

2.

array_1 = [1,2,3,4]

g1 = (x for x in array_1)

array_1 = [1,2,3,4,5]

 

array_2 = [1,2,3,4]

g2 = (x for x in array_2)

array_2[:] = [1,2,3,4,5]

Output:

>>> print(list(g1))

[1,2,3,4]

 

>>> print(list(g2))

[1,2,3,4,5]

💡 Explanation ▶ is is not what it is!

The following is a very famous example present all over the internet.

>>> a = 256

>>> b = 256

>>> a is b

True

 

>>> a = 257

>>> b = 257

>>> a is b

False

 

>>> a = 257; b = 257

>>> a is b

True

💡 Explanation:

The difference between is and ==

256 is an existing object but 257 isn't

When you start up python the numbers from -5 to 256 will be allocated. These numbers are used a lot, so it makes sense just to have them ready.

Quoting from https://docs.python.org/3/c-api/long.html

The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behavior of Python, in this case, is undefined. :-)

>>> id(256)

10922528

>>> a = 256

>>> b = 256

>>> id(a)

10922528

>>> id(b)

10922528

>>> id(257)

140084850247312

>>> x = 257

>>> y = 257

>>> id(x)

140084850247440

>>> id(y)

140084850247344

Here the interpreter isn't smart enough while executing y = 257 to recognize that we've already created an integer of the value 257, and so it goes on to create another object in the memory.

Both a and b refer to the same object when initialized with same value in the same line.

>>> a, b = 257, 257

>>> id(a)

140640774013296

>>> id(b)

140640774013296

>>> a = 257

>>> b = 257

>>> id(a)

140640774013392

>>> id(b)

140640774013488

▶ A tic-tac-toe where X wins in the first attempt!

# Let's initialize a row

row = [""]*3 #row i['', '', '']

# Let's make a board

board = [row]*3

Output:

>>> board

[['', '', ''], ['', '', ''], ['', '', '']]

>>> board[0]

['', '', '']

>>> board[0][0]

''

>>> board[0][0] = "X"

>>> board

[['X', '', ''], ['X', '', ''], ['X', '', '']]

We didn't assign 3 "X"s or did we?

💡 Explanation:

When we initialize row variable, this visualization explains what happens in the memory

And when the board is initialized by multiplying the row, this is what happens inside the memory (each of the elements board[0], board[1] and board[2] is a reference to the same list referred by row)

We can avoid this scenario here by not using row variable to generate board. (Asked in this issue).

>>> board = [['']*3 for _ in range(3)]

>>> board[0][0] = "X"

>>> board

[['X', '', ''], ['', '', ''], ['', '', '']]

▶ The sticky output function

funcs = []

results = []

for x in range(7):

    def some_func():

        return x

    funcs.append(some_func)

    results.append(some_func())  # note the function call here

 

funcs_results = [func() for func in funcs]

Output:

>>> results

[0, 1, 2, 3, 4, 5, 6]

>>> funcs_results

[6, 6, 6, 6, 6, 6, 6]

Even when the values of x were different in every iteration prior to appending some_func to funcs, all the functions return 6.

//OR

>>> powers_of_x = [lambda x: x**i for i in range(10)]

>>> [f(2) for f in powers_of_x]

[512, 512, 512, 512, 512, 512, 512, 512, 512, 512]

💡 Explanation ▶ is not ... is not is (not ...)

>>> 'something' is not None

True

>>> 'something' is (not None)

False

💡 Explanation ▶ The surprising comma

Output:

>>> def f(x, y,):

...     print(x, y)

...

>>> def g(x=4, y=5,):

...     print(x, y)

...

>>> def h(x, **kwargs,):

  File "<stdin>", line 1

    def h(x, **kwargs,):

                     ^

SyntaxError: invalid syntax

>>> def h(*args,):

  File "<stdin>", line 1

    def h(*args,):

                ^

SyntaxError: invalid syntax

💡 Explanation: ▶ Backslashes at the end of string

Output:

>>> print("\\ C:\\")
\ C:\
>>> print(r"\ C:")
\ C:
>>> print(r"\ C:\")

    File "<stdin>", line 1
      print(r"\ C:\")
                     ^
SyntaxError: EOL while scanning string literal
💡 Explanation ▶ not knot!

Output:

>>> not x == y

True

>>> x == not y

  File "<input>", line 1

    x == not y

           ^

SyntaxError: invalid syntax

💡 Explanation: ▶ Half triple-quoted strings

Output:

>>> print('wtfpython''')

wtfpython

>>> print("wtfpython""")

wtfpython

>>> # The following statements raise `SyntaxError`

>>> # print('''wtfpython')

>>> # print("""wtfpython")

💡 Explanation: ▶ Midnight time doesn't exist?

from datetime import datetime

 

midnight = datetime(2018, 1, 1, 0, 0)

midnight_time = midnight.time()

 

noon = datetime(2018, 1, 1, 12, 0)

noon_time = noon.time()

 

if midnight_time:

    print("Time at midnight is", midnight_time)

 

if noon_time:

    print("Time at noon is", noon_time)

Output:

('Time at noon is', datetime.time(12, 0))

The midnight time is not printed.

💡 Explanation:

Before Python 3.5, the boolean value for datetime.time object was considered to be False if it represented midnight in UTC. It is error-prone when using the if obj: syntax to check if the obj is null or some equivalent of "empty."

▶ What's wrong with booleans?

1.

# A simple example to count the number of boolean and

# integers in an iterable of mixed data types.

mixed_list = [False, 1.0, "some_string", 3, True, [], False]

integers_found_so_far = 0

booleans_found_so_far = 0

 

for item in mixed_list:

    if isinstance(item, int):

        integers_found_so_far += 1

    elif isinstance(item, bool):

        booleans_found_so_far += 1

Output:

>>> integers_found_so_far

4

>>> booleans_found_so_far

0

2.

another_dict = {}

another_dict[True] = "JavaScript"

another_dict[1] = "Ruby"

another_dict[1.0] = "Python"

Output:

>>> another_dict[True]

"Python"

3.

>>> some_bool = True

>>> "wtf"*some_bool

'wtf'

>>> some_bool = False

>>> "wtf"*some_bool

''

💡 Explanation: ▶ Class attributes and instance attributes

1.

class A:

    x = 1

 

class B(A):

    pass

 

class C(A):

    pass

Output:

>>> A.x, B.x, C.x

(1, 1, 1)

>>> B.x = 2

>>> A.x, B.x, C.x

(1, 2, 1)

>>> A.x = 3

>>> A.x, B.x, C.x

(3, 2, 3)

>>> a = A()

>>> a.x, A.x

(3, 3)

>>> a.x += 1

>>> a.x, A.x

(4, 3)

2.

class SomeClass:

    some_var = 15

    some_list = [5]

    another_list = [5]

    def __init__(self, x):

        self.some_var = x + 1

        self.some_list = self.some_list + [x]

        self.another_list += [x]

Output:

>>> some_obj = SomeClass(420)

>>> some_obj.some_list

[5, 420]

>>> some_obj.another_list

[5, 420]

>>> another_obj = SomeClass(111)

>>> another_obj.some_list

[5, 111]

>>> another_obj.another_list

[5, 420, 111]

>>> another_obj.another_list is SomeClass.another_list

True

>>> another_obj.another_list is some_obj.another_list

True

💡 Explanation: ▶ yielding None

some_iterable = ('a', 'b')

 

def some_func(val):

    return "something"

Output:

>>> [x for x in some_iterable]

['a', 'b']

>>> [(yield x) for x in some_iterable]

<generator object <listcomp> at 0x7f70b0a4ad58>

>>> list([(yield x) for x in some_iterable])

['a', 'b']

>>> list((yield x) for x in some_iterable)

['a', None, 'b', None]

>>> list(some_func((yield x)) for x in some_iterable)

['a', 'something', 'b', 'something']

💡 Explanation: ▶ Mutating the immutable!

some_tuple = ("A", "tuple", "with", "values")

another_tuple = ([1, 2], [3, 4], [5, 6])

Output:

>>> some_tuple[2] = "change this"

TypeError: 'tuple' object does not support item assignment

>>> another_tuple[2].append(1000) #This throws no error

>>> another_tuple

([1, 2], [3, 4], [5, 6, 1000])

>>> another_tuple[2] += [99, 999]

TypeError: 'tuple' object does not support item assignment

>>> another_tuple

([1, 2], [3, 4], [5, 6, 1000, 99, 999])

But I thought tuples were immutable...

💡 Explanation: ▶ The disappearing variable from outer scope

e = 7

try:

    raise Exception()

except Exception as e:

    pass

Output (Python 2.x):

>>> print(e)

# prints nothing

Output (Python 3.x):

>>> print(e)

NameError: name 'e' is not defined

💡 Explanation: ▶ When True is actually False

True = False

if True == False:

    print("I've lost faith in truth!")

Output:

I've lost faith in truth!
💡 Explanation: ▶ From filled to None in one instruction...

some_list = [1, 2, 3]

some_dict = {

  "key_1": 1,

  "key_2": 2,

  "key_3": 3

}

 

some_list = some_list.append(4)

some_dict = some_dict.update({"key_4": 4})

Output:

>>> print(some_list)

None

>>> print(some_dict)

None

💡 Explanation

Most methods that modify the items of sequence/mapping objects like list.append, dict.update, list.sort, etc. modify the objects in-place and return None. The rationale behind this is to improve performance by avoiding making a copy of the object if the operation can be done in-place (Referred from here)

▶ Subclass relationships *

Output:

>>> from collections import Hashable

>>> issubclass(list, object)

True

>>> issubclass(object, Hashable)

True

>>> issubclass(list, Hashable)

False

The Subclass relationships were expected to be transitive, right? (i.e., if A is a subclass of B, and B is a subclass of C, the A should a subclass of C)

💡 Explanation: ▶ The mysterious key type conversion *

class SomeClass(str):

    pass

 

some_dict = {'s':42}

Output:

>>> type(list(some_dict.keys())[0])

str

>>> s = SomeClass('s')

>>> some_dict[s] = 40

>>> some_dict # expected: Two different keys-value pairs

{'s': 40}

>>> type(list(some_dict.keys())[0])

str

💡 Explanation: ▶ Let's see if you can guess this?

a, b = a[b] = {}, 5

Output:

💡 Explanation: Section: Appearances are deceptive! ▶ Skipping lines?

Output:

>>> value = 11

>>> valuе = 32

>>> value

11

Wut?

Note: The easiest way to reproduce this is to simply copy the statements from the above snippet and paste them into your file/shell.

💡 Explanation

Some non-Western characters look identical to letters in the English alphabet but are considered distinct by the interpreter.

>>> ord('е') # cyrillic 'e' (Ye)

1077

>>> ord('e') # latin 'e', as used in English and typed using standard keyboard

101

>>> 'е' == 'e'

False

 

>>> value = 42 # latin e

>>> valuе = 23 # cyrillic 'e', Python 2.x interpreter would raise a `SyntaxError` here

>>> value

42

The built-in ord() function returns a character's Unicode code point, and different code positions of Cyrillic 'e' and Latin 'e' justify the behavior of the above example.

▶ Teleportation *

import numpy as np

 

def energy_send(x):

    # Initializing a numpy array

    np.array([float(x)])

 

def energy_receive():

    # Return an empty numpy array

    return np.empty((), dtype=np.float).tolist()

Output:

>>> energy_send(123.456)

>>> energy_receive()

123.456

Where's the Nobel Prize?

💡 Explanation: ▶ Well, something is fishy...

def square(x):

    """

    A simple function to calculate the square of a number by addition.

    """

    sum_so_far = 0

    for counter in range(x):

        sum_so_far = sum_so_far + x

  return sum_so_far

Output (Python 2.x):

Shouldn't that be 100?

Note: If you're not able to reproduce this, try running the file mixed_tabs_and_spaces.py via the shell.

💡 Explanation Section: Watch out for the landmines! ▶ Modifying a dictionary while iterating over it

x = {0: None}

 

for i in x:

    del x[i]

    x[i+1] = None

    print(i)

Output (Python 2.7- Python 3.5):

0
1
2
3
4
5
6
7

Yes, it runs for exactly eight times and stops.

💡 Explanation: ▶ Stubborn del operator *

class SomeClass:

    def __del__(self):

        print("Deleted!")

Output: 1.

>>> x = SomeClass()

>>> y = x

>>> del x # this should print "Deleted!"

>>> del y

Deleted!

Phew, deleted at last. You might have guessed what saved from __del__ being called in our first attempt to delete x. Let's add more twist to the example.

2.

>>> x = SomeClass()

>>> y = x

>>> del x

>>> y # check if y exists

<__main__.SomeClass instance at 0x7f98a1a67fc8>

>>> del y # Like previously, this should print "Deleted!"

>>> globals() # oh, it didn't. Let's check all our global variables and confirm

Deleted!

{'__builtins__': <module '__builtin__' (built-in)>, 'SomeClass': <class __main__.SomeClass at 0x7f98a1a5f668>, '__package__': None, '__name__': '__main__', '__doc__': None}

Okay, now it's deleted 😕

💡 Explanation: ▶ Deleting a list item while iterating

list_1 = [1, 2, 3, 4]

list_2 = [1, 2, 3, 4]

list_3 = [1, 2, 3, 4]

list_4 = [1, 2, 3, 4]

 

for idx, item in enumerate(list_1):

    del item

 

for idx, item in enumerate(list_2):

    list_2.remove(item)

 

for idx, item in enumerate(list_3[:]):

    list_3.remove(item)

 

for idx, item in enumerate(list_4):

    list_4.pop(idx)

Output:

>>> list_1

[1, 2, 3, 4]

>>> list_2

[2, 4]

>>> list_3

[]

>>> list_4

[2, 4]

Can you guess why the output is [2, 4]?

💡 Explanation:

Difference between del, remove, and pop:

Why the output is [2, 4]?

▶ Loop variables leaking out!

1.

for x in range(7):

    if x == 6:

        print(x, ': for x inside loop')

print(x, ': x in global')

Output:

6 : for x inside loop

6 : x in global

But x was never defined outside the scope of for loop...

2.

# This time let's initialize x first

x = -1

for x in range(7):

    if x == 6:

        print(x, ': for x inside loop')

print(x, ': x in global')

Output:

6 : for x inside loop

6 : x in global

3.

x = 1
print([x for x in range(5)])
print(x, ': x in global')

Output (on Python 2.x):

[0, 1, 2, 3, 4]
(4, ': x in global')

Output (on Python 3.x):

[0, 1, 2, 3, 4]
1 : x in global
💡 Explanation: ▶ Beware of default mutable arguments!

def some_func(default_arg=[]):

    default_arg.append("some_string")

    return default_arg

Output:

>>> some_func()

['some_string']

>>> some_func()

['some_string', 'some_string']

>>> some_func([])

['some_string']

>>> some_func()

['some_string', 'some_string', 'some_string']

💡 Explanation: ▶ Catching the Exceptions

some_list = [1, 2, 3]

try:

    # This should raise an ``IndexError``

    print(some_list[4])

except IndexError, ValueError:

    print("Caught!")

 

try:

    # This should raise a ``ValueError``

    some_list.remove(4)

except IndexError, ValueError:

    print("Caught again!")

Output (Python 2.x):

Caught!

 

ValueError: list.remove(x): x not in list

Output (Python 3.x):

  File "<input>", line 3

    except IndexError, ValueError:

                     ^

SyntaxError: invalid syntax

💡 Explanation ▶ Same operands, different story!

1.

a = [1, 2, 3, 4]

b = a

a = a + [5, 6, 7, 8]

Output:

>>> a

[1, 2, 3, 4, 5, 6, 7, 8]

>>> b

[1, 2, 3, 4]

2.

a = [1, 2, 3, 4]

b = a

a += [5, 6, 7, 8]

Output:

>>> a

[1, 2, 3, 4, 5, 6, 7, 8]

>>> b

[1, 2, 3, 4, 5, 6, 7, 8]

💡 Explanation: ▶ The out of scope variable

a = 1

def some_func():

    return a

 

def another_func():

    a += 1

    return a

Output:

>>> some_func()

1

>>> another_func()

UnboundLocalError: local variable 'a' referenced before assignment

💡 Explanation: ▶ Be careful with chained operations

>>> (False == False) in [False] # makes sense

False

>>> False == (False in [False]) # makes sense

False

>>> False == False in [False] # now what?

True

 

>>> True is False == False

False

>>> False is False is False

True

 

>>> 1 > 0 < 1

True

>>> (1 > 0) < 1

False

>>> 1 > (0 < 1)

False

💡 Explanation:

As per https://docs.python.org/2/reference/expressions.html#not-in

Formally, if a, b, c, ..., y, z are expressions and op1, op2, ..., opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.

While such behavior might seem silly to you in the above examples, it's fantastic with stuff like a == b == c and 0 <= x <= 100.

▶ Name resolution ignoring class scope

1.

x = 5

class SomeClass:

    x = 17

    y = (x for i in range(10))

Output:

>>> list(SomeClass.y)[0]

5

2.

x = 5

class SomeClass:

    x = 17

    y = [x for i in range(10)]

Output (Python 2.x):

Output (Python 3.x):

💡 Explanation ▶ Needle in a Haystack

1.

x, y = (0, 1) if True else None, None

Output:

>>> x, y  # expected (0, 1)

((0, 1), None)

Almost every Python programmer has faced a similar situation.

2.

t = ('one', 'two')

for i in t:

    print(i)

 

t = ('one')

for i in t:

    print(i)

 

t = ()

print(t)

Output:

💡 Explanation: ▶ Yielding from... return!

1.

def some_func(x):

    if x == 3:

        return ["wtf"]

    else:

        yield from range(x)

Output:

>>> list(some_func(3))

[]

Where did the "wtf" go? Is it due to some special effect of yield from? Let's validate that,

2.

def some_func(x):

    if x == 3:

        return ["wtf"]

    else:

        for i in range(x):

          yield i

Output:

>>> list(some_func(3))

[]

Same result, that didn't work either.

💡 Explanation:

"... return expr in a generator causes StopIteration(expr) to be raised upon exit from the generator."

Section: The Hidden treasures!

This section contains few of the lesser-known interesting things about Python that most beginners like me are unaware of (well, not anymore).

▶ Okay Python, Can you make me fly? *

Well, here you go

Output: Sshh.. It's a super secret.

💡 Explanation: ▶ goto, but why? *

from goto import goto, label

for i in range(9):

    for j in range(9):

        for k in range(9):

            print("I'm trapped, please rescue!")

            if k == 2:

                goto .breakout # breaking out from a deeply nested loop

label .breakout

print("Freedom!")

Output (Python 2.3):

I'm trapped, please rescue!

I'm trapped, please rescue!

Freedom!

💡 Explanation: ▶ Brace yourself! *

If you are one of the people who doesn't like using whitespace in Python to denote scopes, you can use the C-style {} by importing,

from __future__ import braces

Output:

  File "some_file.py", line 1

    from __future__ import braces

SyntaxError: not a chance

Braces? No way! If you think that's disappointing, use Java.

💡 Explanation: ▶ Let's meet Friendly Language Uncle For Life *

Output (Python 3.x)

>>> from __future__ import barry_as_FLUFL

>>> "Ruby" != "Python" # there's no doubt about it

  File "some_file.py", line 1

    "Ruby" != "Python"

              ^

SyntaxError: invalid syntax

 

>>> "Ruby" <> "Python"

True

There we go.

💡 Explanation: ▶ Even Python understands that love is complicated *

Wait, what's this? this is love ❤️

Output:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

It's the Zen of Python!

>>> love = this

>>> this is love

True

>>> love is True

False

>>> love is False

False

>>> love is not True or False

True

>>> love is not True or False; love is love  # Love is complicated

True

💡 Explanation: ▶ Yes, it exists!

The else clause for loops. One typical example might be:

  def does_exists_num(l, to_find):

      for num in l:

          if num == to_find:

              print("Exists!")

              break

      else:

          print("Does not exist")

Output:

>>> some_list = [1, 2, 3, 4, 5]

>>> does_exists_num(some_list, 4)

Exists!

>>> does_exists_num(some_list, -1)

Does not exist

The else clause in exception handling. An example,

try:

    pass

except:

    print("Exception occurred!!!")

else:

    print("Try block executed successfully...")

Output:

Try block executed successfully...

💡 Explanation: ▶ Inpinity *

The spelling is intended. Please, don't submit a patch for this.

Output (Python 3.x):

>>> infinity = float('infinity')

>>> hash(infinity)

314159

>>> hash(float('-inf'))

-314159

💡 Explanation: ▶ Mangling time! *

class Yo(object):

    def __init__(self):

        self.__honey = True

        self.bitch = True

Output:

>>> Yo().bitch

True

>>> Yo().__honey

AttributeError: 'Yo' object has no attribute '__honey'

>>> Yo()._Yo__honey

True

Why did Yo()._Yo__honey work? Only Indian readers would understand.

💡 Explanation: Section: Miscellaneous ▶ += is faster

# using "+", three strings:

>>> timeit.timeit("s1 = s1 + s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100)

0.25748300552368164

# using "+=", three strings:

>>> timeit.timeit("s1 += s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100)

0.012188911437988281

💡 Explanation: ▶ Let's make a giant string!

def add_string_with_plus(iters):

    s = ""

    for i in range(iters):

        s += "xyz"

    assert len(s) == 3*iters

 

def add_bytes_with_plus(iters):

    s = b""

    for i in range(iters):

        s += b"xyz"

    assert len(s) == 3*iters

 

def add_string_with_format(iters):

    fs = "{}"*iters

    s = fs.format(*(["xyz"]*iters))

    assert len(s) == 3*iters

 

def add_string_with_join(iters):

    l = []

    for i in range(iters):

        l.append("xyz")

    s = "".join(l)

    assert len(s) == 3*iters

 

def convert_list_to_string(l, iters):

    s = "".join(l)

    assert len(s) == 3*iters

Output:

>>> timeit(add_string_with_plus(10000))

1000 loops, best of 3: 972 µs per loop

>>> timeit(add_bytes_with_plus(10000))

1000 loops, best of 3: 815 µs per loop

>>> timeit(add_string_with_format(10000))

1000 loops, best of 3: 508 µs per loop

>>> timeit(add_string_with_join(10000))

1000 loops, best of 3: 878 µs per loop

>>> l = ["xyz"]*10000

>>> timeit(convert_list_to_string(l, 10000))

10000 loops, best of 3: 80 µs per loop

Let's increase the number of iterations by a factor of 10.

>>> timeit(add_string_with_plus(100000)) # Linear increase in execution time

100 loops, best of 3: 9.75 ms per loop

>>> timeit(add_bytes_with_plus(100000)) # Quadratic increase

1000 loops, best of 3: 974 ms per loop

>>> timeit(add_string_with_format(100000)) # Linear increase

100 loops, best of 3: 5.25 ms per loop

>>> timeit(add_string_with_join(100000)) # Linear increase

100 loops, best of 3: 9.85 ms per loop

>>> l = ["xyz"]*100000

>>> timeit(convert_list_to_string(l, 100000)) # Linear increase

1000 loops, best of 3: 723 µs per loop

💡 Explanation ▶ Explicit typecast of strings

a = float('inf')

b = float('nan')

c = float('-iNf')  #These strings are case-insensitive

d = float('nan')

Output:

>>> a

inf

>>> b

nan

>>> c

-inf

>>> float('some_other_string')

ValueError: could not convert string to float: some_other_string

>>> a == -c #inf==inf

True

>>> None == None # None==None

True

>>> b == d #but nan!=nan

False

>>> 50/a

0.0

>>> a/a

nan

>>> 23 + b

nan

💡 Explanation:

'inf' and 'nan' are special strings (case-insensitive), which when explicitly typecast-ed to float type, are used to represent mathematical "infinity" and "not a number" respectively.

▶ Minor Ones Contributing

All patches are Welcome! Please see CONTRIBUTING.md for further details.

For discussions, you can either create a new issue or ping on the Gitter channel

Acknowledgements

The idea and design for this collection were initially inspired by Denys Dovhan's awesome project wtfjs. The overwhelming support by the community gave it the shape it is in right now.

Some nice Links! 🎓 License

© Satwik Kansal

Help

If you have any wtfs, ideas or suggestions, please share.

Surprise your geeky pythonist friends?

You can use these quick links to recommend wtfpython to your friends,

Twitter | Linkedin

Need a pdf version?

I've received a few requests for the pdf version of wtfpython. You can add your details here to get the pdf as soon as it is finished.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4