• Last edited on May 13, 2015, 9:03:52 AM by 1252759 Jon Clements

### `is not`

`is not` is a single binary operator, and has behavior different than using `is` and `not` separated.

```2 is not None
#result: True
2 is (not None)
#result: False
```

### `==` in chained comparisons

Used in conjunction with `>` or `<`, `==` can comprise an expression whose result differs from any variant that uses parentheses.

```(42 > 23) == True
#effectively equivalent to `True == True`, which is True

42 > (23 == True)
#effectively equivalent to `42 > False`, which is True

42 > 23 == True
#effectively equivalent to `42 > 23 and 23 == True`, which is False
```

### Lazy binding

A lambda expression that uses a local variable will not bind to the value the variable had when the lambda was created. Instead, it uses the value the variable has when the lambda is executed.

```x = 23
f = lambda: x
x = 42
print f()
#expected result: 23
#actual result: 42

funcs = []
for i in range(10):
funcs.append(lambda: i**2)
print [f() for f in funcs]
#expected result: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
#actual result: [81, 81, 81, 81, 81, 81, 81, 81, 81, 81]
```

To get the desired result you can bind the variable as a default argument to the lambda.

```x = 23
f = lambda x=x: x
x = 42
print f()
# 23

funcs = []
for i in range(10):
funcs.append(lambda i=i: i**2)
print [f() for f in funcs]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```

### Default Mutable Argument

The default value in a function definition is only evaluated once, at declaration time. This means that a mutable default argument has persistent state across multiple invocations.

```def frob(x=[]):
x.append(1)
print len(x),

frob()
frob()

#expected result: 1, 1
#actual result: 1, 2
```

### Evaluation time discrepancy

In a generator expression, the `in` clause is evaluated at declaration time, but the conditional clause is evaluated at run time.

```seq = [4, 8, 15, 16, 23, 42]
g = (x for x in seq if x in seq)
seq = [16]
print list(g)
#expected result: [4, 8, 15, 16, 23, 42]
#actual result: [16]
```

### Persistent state of multiple references to one iterator

Calling `next` on an iterator will advance all instances of that iterator, not just the one you called it on.

```#returns True if exactly one element of `iterable` is True
#courtesy of Jon Clements at http://stackoverflow.com/a/16801605/1903116
def single_true(iterable):
i = iter(iterable)
return any(i) and not any(i)

#returns True if exactly one element of `iterable` is False
def single_false(iterable):
i = iter(iterable)
return not all(i) and all(i)

#splits a list into evenly sized chunks
def chunk(input, size):
return map(None, *([iter(input)] * size))

#ok, these examples don't demonstrate how it can be used to confuse
#the reader. But I promise it can.
#todo: be more evil.
```

### Identical looking variable names

Some unicode characters look identical to ascii ones, but are considered distinct by the interpreter.

```value = 42 #ascii e
valuŠµ = 23 #cyrillic e
print(value)
#expected result: 23
#actual result: 42
```

### Tab indentation variability

A tab can be equivalent to a variable number of spaces depending on its position on the line. See http://docs.python.org/2/reference/lexical_analysis.html#indentation

```def frob(x):
if x:
print "A"
#this next line is indented with a tab.
#although it looks four spaces long in the editor,
#in this context the interpreter thinks it's eight spaces long.
print "B"
frob(False)
#expected result: "B"
#actual result: no output
```

### `yield from` in generator expressions

Normally, `yield from` is only used inside function declarations. But the interpreter won’t complain if you use it in a generator. You can even put it in the conditional clause.

```g = [(1,2),(2,4),(3,8),(4,16)]
print list((None for g in g if (yield from g) and False))
#result: [1, 2, 2, 4, 3, 8, 4, 16]
```

### `__dunder__` methods don’t look at instance level

class-level dunder methods are invoked by operators, even if you override them at the instance level.

```class Widget():
def __init__(self):
self.__eq__ = lambda self, other: True
def __eq__(self, other):
return False

print(Widget() == Widget())
#expected: True
#actual: False
```

### Name resolution ignores class scope

Scopes nested inside class definition ignore names bound at the class level. For example, a generator expression has its own scope. Starting in 3.X, list comprehensions also have their own scope. See this

```x = 23
class Fred:
x = 42
y = (x for i in range(10))
print(list(Fred.y)[0])
#expected result: 42
#actual result: 23

#3.X only:
x = 23
class Fred:
x = 42
y = [x for i in range(10)]
print(Fred.y[0])
#expected result: 42
#actual result: 23 (42 in 2.X)
```

### `sys.argv[0]` is the filename of the current Python file.

When using `sys.argv` to accept command line arguments to Python scripts the first argument in `sys.argv` is the current Python filename. This argument is passed by default and can cause issues if you’re using filename arguments in the command line.

The below code will write over the Python file with the text `'Hello World!'`. This snippet was inspired by Al.Sal <3

```import sys

with open(sys.argv[0], 'w') as f:
f.write('Hello World!')
```