Python

From Useful Data
Jump to navigation Jump to search

Python, the programming language

Quick Reference

  • for x in range(12) :
    else :
  • while condition :
    else :
  • def nameOfIt(parameter, parameter) :
  • 7 / 3 = 2   and   7 / 3.0 = 2.33333333333   but   float(7 / 3) = 2.0
  • if x == y :
  • """ Multi-line
    comments """
  • True, False, and, or, not
  • list = ["cat", 2, 3.132, 'stuff and nonsense']
  • print len(list)
  • list.append("New item")
    list.insert(4,"Another item")
    list.append(["Item",'thing',13]) to add more than one item
    list.pop(n) removes the nth item from the list
    list.remove("Value") removes first instance of "Value" from the list
    find = list.index("Item")
    list.sort()
  • Reversedlist = list[::-1] using a negative stride to reverse a list
  • dictionary = { 'Key': 'value', 'Age': 42, 'Name', "Fred" } # the keys are unique
  • print dictionary['Key']
    dictionary['Key'] = 21
    dictionary["New thing"] = "Value" (no .insert is required)
    del dictionary['Key'] (removes a key and its value)
    dictionary.remove("Fred") removes a key with the value of "Fred"
    print dictionary.keys()
    print dictionary.values()
    dictionary.has_key("Bill")
    Age in dictionary # True or False according to whether the key is in the dictionary
  • newList = [x for x in list if condition]
    even_squares_to_50 = [x**2 for x in range(1,51) if x % 2 == 0]
  • Anonymous functions: lambda variable: expression
# normal function
my_list = range(16)
def by_three(x) :
    return x % 3 == 0
print filter(by_three,my_list)
> [0, 3, 6, 9, 12, 15]
# anonymous function
my_list = range(16)
print filter(lambda x: x % 3 == 0, my_list)
> [0, 3, 6, 9, 12, 15]

Getting help and providing help() using a docstring

To get to the description of a built-in function:

help(function)

To provide help() in a home-made function - called a 'docstring':

def area(base, height) :
    '''(number,number) -> number

    Returns the area of a triangle with dimensions base and height.
    '''
    return base *height / 2


Finding functions with dir()

dir(_builtins__)
help(abs)

A method is a function inside an object.


Classes example

# Class definition
class Animal(object):
	"""Makes cute animals."""
	is_alive = True
	health = "good"
	# For initializing our instance objects
	def __init__(self, name, age, is_hungry):
		self.name = name
		self.age = age
		self.is_hungry = is_hungry
	# Add your method here!
	def description(self):
		print self.name, self.age
# Note that self is only used in the __init__()
# function definition; we don't need to pass it
# to our instance objects.

zebra   = Animal("Jeffrey", 2, True)
giraffe = Animal("Bruce"  , 1, False)
panda   = Animal("Chad"   , 7, True)
hippo   = Animal("Harry"  , 8, True)

print zebra.name  , zebra.age  , zebra.is_hungry
print giraffe.name, giraffe.age, giraffe.is_hungry
print panda.name  , panda.age  , panda.is_hungry

hippo.description()
print hippo.health, sloth.health, ocelot.health


File handling

There are four methods for reading a file:

  filename = "../whatever/file.dat"
  file_ref = open(filename,'r')       # 'w' to write and 'a' to append
1 record = file_ref.readline()        # will have '\n' at the end, or null at the end of the file
  print(record, end='')               # prevents print() from appending a newline.
  file_ref.close()
  
2 for record in file_ref :
      print(record, end='')
  
3 entire_contents = file_ref.read()   # read() returns the entire file
  
4 record_list = file_ref.readlines()  # readlines() returns all the records in the file as a list.

Writing:

import tkinter.filedialog
filename = tkinter.filedialog.askopenfilename()    # a graphical file prompt for a file to open
filename = tkinter.filedialog.asksaveasfilename()  # a graphical file prompt for a file name to write to
file_ref = open(filename,'w')       # 'w' to write and 'a' to append
record = "Blah\n"
file_ref.write(record)              # write() does not append a newline
file_ref.close()

Grizzles

  • The use of colons with 'for' and 'if'. The are immediately followed by indentation. Python says it uses white space to determine structure, not { } or other constructs. The reality is that ':' is determining the structure and the whitespace merely an inconvenience to the programmer. Personally, I like the whitespace idea, but the ':' is an unnecessary faff. And do you know why it is there? Supposedly to allow text editors to highlight code properly - but if indenting with whitespace determines structure, then why can't the editors do the same?
  • Immutable strings. There is no reason for this constraint. It was done to make memory management easier and very slightly more performance efficient, but it is a constraint that has had knock-on effects through other parts of the language definition. As a constraint to improve performance ... who the hell cares about memory manipulation in RAM time any more? That's so 1970s. There is no real reason why one cannot say myString[7:10] = "replacement text". It was even possible in QuickBASIC!
  • So are strings lists or not? One can treat strings as arrays using for x in "How long" : print x, so why not MyString[3] = "z"?
  • Version 2 or version 3? Just fork the God-damned schizophrenic language into two and get it over and done with! At least then version 3 can die in peace.
  • Functions or methods? Methods or functions? Which is it to be, Python? Why can't I say sort(myTable) or myString.length() This is just sloppiness that makes it hard for newbies. I thought Python was meant to be easy for newbies, and with only one way to do things? Hmm?
  • Count from 0 in indexes, except for terminators. Eh? Why is a substring myString[2:4] only 2 characters long? I have no trouble with counting from zero, but why is the [:y] parameter one higher than it needs to be? It just causes confusion.
  • __init__() to initialise classes/objects. What sort of name it that? What was wrong with init()?


Confusion

  • Passing variables to functions - why bother? Since passing a variable to a function, then changing the variable, changes the global variable, this means variables in functions are not local to the function. In which case, why bother passing parameters to the function at all and not just work on the global variable, like one would in BASIC? Unless the function is going into an external library, there is rarely ever going to be any point passing in parameters. In fact, why aren't variables passed as parameters to functions treated as local variables?
  • Why del dictionary['Key'] to remove a dictionary key and its value rather than dictionary.delete('Key')? Why have a distinct del command for this one activity?
  • In Python version 3, int + int = int. int - int = int. int * int = int. So what is int / int? Nope, it is always a float; even 4 / 2 = 2.0 rather than 2. This is inconsistent behaviour. (In Python version 2, the result of dividing an int by an int is an int.)


WTF???

  • Create a table to play Noughts and Crosses:
table = [ ["."] * 3 ] * 3
>>> print(table[0],"\n",table[1],"\n",table[2])
['.', '.', '.'] 
 ['.', '.', '.'] 
 ['.', '.', '.']

The formatting needs fixing, but otherwise it's looking good. We've got "." for where a "O" or a "X" can be played. So, 1st player makes a move:

>>> table[1][2] = "X"
>>> print(table[0],"\n",table[1],"\n",table[2])
['.', '.', 'X'] 
 ['.', '.', 'X'] 
 ['.', '.', 'X']

Eh? Why three lots of "X" in a column? Now the second player makes a move:

>>> table[2][0] = "O"
>>> print(table[0],"\n",table[1],"\n",table[2])
['O', '.', 'X'] 
 ['O', '.', 'X'] 
 ['O', '.', 'X']

WTF? Yep, the command table = [ ["."] * 3 ] * 3 creates a list of 3 dots, then creates three pointers to that same list. What on earth is the point of that? And why doesn't the first "[…]* 3" behave like the second "[…]* 3" and just create three pointers pointing at the first "."? This is just stupid and inconsistent and confusing.

  • Assigning a variable to another variable creates a new variable:
>>> andy = "Apples"
>>> pete = "Pears"
>>> andy = pete
>>> andy
'Pears'
>>> andy = "Bananas"
>>> pete
'Pears'

BUT assigning a list to another list does not create a new list:

>>> andy = ["Apples"]
>>> pete = ["Pears"]
>>> andy = pete
>>> andy
['Pears']
>>> andy[0] = "Bananas"
>>> pete
['Bananas']

Both andy and pete are pointing at the same place in memory; changing one changes another. This is stupid and inconsistent and confusing.

  • Another example
>>> row = [1,2,3]
>>> table1 = row * 3
>>> table2 = [row] * 3
>>> table3 = [row * 3]
>>> table1
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> table2
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> table3
[[1, 2, 3, 1, 2, 3, 1, 2, 3]]
>>> row[1] = 99
>>> row
[1, 99, 3]
>>> table1
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> table2
[[1, 99, 3], [1, 99, 3], [1, 99, 3]]
>>> table3
[[1, 2, 3, 1, 2, 3, 1, 2, 3]]

So it is not just as simple as two variables pointing to the same place in memory; it is 'cleverer' than that. It actually remembers that table2 is constructed from three instances of row. And this works both ways:

table2
[[1, 99, 3], [1, 99, 3], [1, 99, 3]]
>>> row
[1, 99, 3]
>>> table2[0][1]=88
>>> table2
[[1, 88, 3], [1, 88, 3], [1, 88, 3]]
>>> row
[1, 88, 3]

So you have to remember that when assigning a list variable to another list variable, that Python behaves differently than with other variable assignments. And you have to also remember that whenever you change the contents of a list, the values in that list may be being used by another list somewhere else in the program without your knowledge. What a mess.

>>> a=[99]
>>> b=[a]
>>> a[0]=[b]
>>> a
[[[[...]]]]
>>> b
[[[[...]]]]

Oops. I broke Python.