+
, -
, *
, /
) work as expected.//
. Modulo (remainder) is done with %
.4 // 3
4 % 3
10 // 3
10 % 3
**
^
does something else2 ** 4
CISV
This is bitwise OR.
4 ^ 2
A function is a structure which takes some arguments and returns some output or performs some action.
Printing to the command line is done using the print
function.
print(3)
=
type
function.int
: An integer (There is also a long
in Python, but regular int
uses C's long
, so you don't usually need Python long
).float
: A floating-point number (again, no size, like double
, is
specified).bool
: A booleanTrue
or False
(note the capital letters).NoneType
: indicated using keyword None
. Similar to void
in
other languages.str
: A string of charactersr
before the opening quotation marks means that backslashes are
not interpreted within the string. These are called "raw strings."# Declare an integer:
a = 3
print(a)
# Declare a float:
b = 4.0
print(b)
# Add the integer and float. The integer is automatically cast to a float:
c = a + b
print(c)
print(type(c))
# Declare some regular strings:
d = 'The quick brown fox'
e = "jumps over the lazy dog."
# Plus sign concatenates strings.
# Strings can be used without being declared.
f = d + ' ' + e
print(f)
# Create a multi-line string:
g = """This is a
multi-line string."""
print(g)
# Create a string with an escape sequence
h = "This string is\n not raw."
print(h)
# Create a similar string, but make it raw.
i = r"This string is\n raw."
print(i)
# Also, there are complex numbers:
j = complex(3, 4)
print(j)
print(j.conjugate())
print(j.conjugate()*j)
varname[index]
. Indices start at 0
.list
)¶Indicated by square brackets: [<>, <>, <>, ...]
# Declare a list:
list1 = [1, 3.14, False, 'dog']
print(list1)
# Access an element:
print(list1[3])
Lists are mutable, meaning that you can
list1[3] = 'cat'
print(list1)
list1.append(None)
print(list1)
list1.insert(1, 'dog')
print(list1)
item = list1.pop(4)
print(list1)
print(item)
list1.remove(1)
print(list1)
tuple
)¶Indicated by parentheses: (<>, <>, <>, ...)
# Declare a tuple
tup1 = (1, 3.14, False, 'dog')
print(tup1)
# Access an element:
print(tup1[3])
Tuples are Immutable. They cannot be changed. To change a value, you must create a new tuple.
# Attempt to change an element:
tup1[3] = 'cat'
Tuples and lists can be converted into each other:
list2 = list(tup1)
tup2 = tuple(list1)
print(list2)
print(tup2)
Lists and tuples can be nested in a variety of ways
list3 = list2 + [tup2]
print(list3)
tup3 = (tup2, list2)
tup3
tup3[1][2] = True
print(tup3)
dict
)¶key
- value
pairshash
types in other languagesCreating dictionaries directly:
dict_name = {<key1>: <val1>,
<key2>: <val2>,
...}
Warning: all keys must be immutable.
dict1 = {'key1': 'val1',
'key2': 'val2',
3 : 'val3',
None : 'valNone'}
dict_name = dict( [(<key1>, <val1>), (<key2>, <val2>), ...] )
dict2 = dict([('key1', 'val1'),
('key2', 'val2'),
(3, 'val3'),
(None, 'valNone')])
dict_name[<key>]
print(dict1['key1'])
print(dict2[None])
dict_name[<new_key>] = <new_val>
dict2[(4, 5)] = 'tuples can be keys'
print(dict2)
dict_keys
object and turning it into a list:keys_as_dict_keys = dict_name.get_keys()
keys_as_list = list(keys_as_dict_keys)
dict2_keys = dict2.keys()
print(dict2_keys)
print(list(dict2_keys))
Getting all values, and getting key-value pairs:
values = dict_name.values()
items = dict_name.items()
These variables now refer to special containers for the respective kinds of things.
They can be turned into simple lists using
list(values)
list(items)
as before.
values = dict2.values()
print(values)
items = dict2.items()
print(items)
Warning: Dictionary elements have no guaranteed order. There is no
guarantee that items will be returned in the order in which they are added.
However, there is a guarantee that, as long as the dictionary is not changed
between calls, successive calls to any or all of keys()
, values()
, and/or
items()
will return elements in the same/corresponding orders.
For purposes of comparisons and other boolean expressions, the
following are considered to be equivalent to False
:
False
None
0
0.0
[]
(the empty list)""
(an empty string)()
(an empty tuple){}
(an empty dictionary)Everything else is treated as true.
# The false things
things = [ False, None, 0, 0.0, '', [], {}, () ]
for i, t in enumerate(things):
print(i, ':', t, "is", bool(t))
# Some True things
things = [ True, -1, 0.5, 'a', [False], {False: False}, (False, False) ]
for i, t in enumerate(things):
if t:
print(i, ':', t, "is", bool(t))
Identical: Do two things point to the same thing in memory?
Tested by the keyword is
.
Equal: Do the two things represent the same thing? Tested using
double-equal sign ==
.
Unequal: As in most languages, it's tested using !=
.
Not identical: Tested using is not
.
print(0 is 0)
print(0 == 0)
a = 0
b = 0
print(a is b)
print(a == b)
a = True
b = 1
print(a is b)
print(a == b)
a = ['a', 'b', 'c']
b = ['a', 'b', 'c']
print(a is b)
print(a == b)
a = ('a', 'b', 'c')
b = ('a', 'b', 'c')
print(a is b)
print(a == b)
a = ['a', 'b', 'c', 'd']
b = ['a', 'b', 'c']
print(a is b)
print(a == b)
Be careful with lists (and other mutables). Variable assignment is done by reference, not by value.
a = ['a', 'b', 'c']
b = a
print(a is b)
print(a == b)
b[1] = 'd'
print(a is b)
print(a == b)
print(a)
print(b)
Be careful with floating-point numbers. Rounding errors can cause problems.
a = 1/3
b = 0.1/0.3
print(a)
print(b)
print(a == b)
Greater-than, Less-than, and the like work as you'd expect in comparing items of the same type:
When comparing objects of different types, there are rules. Some work and make sense...but you should look them up.
Unlike in most languages, and
, or
, and not
are done using the
English words just given, rather than strange symbols like &&
, ||
,
and !
.
Notes
or
and and
are short-circuit operators.or
to be true, only one of the operands needs to be true. If the
first operand is true, the second isn't even checked, and the output
is True
.and
to be true, both operands must be true. If the first is
false, the second is not checked, and the output is False
not
has lower priority than non-boolean operators.not a == b
. ==
is evaluated before not
is even
considered, so the expression is equivalent to not (a == b)
.a == not b
. The interpreter reads this as a == not
before
considering b
. This will give an error. The intended meaning is
a == (not b)
.a = 1
b = 3
c = 3
d = 10
a < b < c < d
a <= b <= c <= d
The in
keyword tests whether
a = ['apple', 'balloon', 'cat', 'dog']
b = {'fruit': 'apple',
'toy': 'balloon',
'bad animal': 'cat',
'good animal': 'dog'}
c = 'The quick brown fox jumps over the lazy dog'
print('good animal' in b)
print('dog' in b)
print('fox' in c)
print('foxes' in c)
In Python, logical groupings are indicated by indentation levels (rather than curly braces, as in C or Java). By convention, each indentation level is four spaces (tabs are frowned upon).
For a simple conditional, the syntax is
if <condition>:
<code>
code
will be executed if and only if condition
is true. The code
may occur on more than one line (which all must be indented by the
same amount relative to if
).
if 3 <= 4:
print('I know numbers.')
To execute some other code if the condition
failes, add an else
block.
if <condition>:
<code>
else:
<other code>
if 3 <= 4:
print('I know numbers.')
else:
print('I do not know numbers.')
More complicated lists of conditions are done using elif
blocks.
if <condition1>:
<code1>
elif <condition2>:
<code2>
else:
<else code>
x = 50
if x < 3:
print('The variable is small.')
elif x < 100:
print('The variable is not too large.')
else:
print('The variable is too large.')
Python does not have a regular for
loop, but only what in other languages
would be called for each
loops. The syntax is
for <var> in <iterable>:
<code>
<iterable>
is any sequence-like quantity (a list, tuple, dictionary,
or string, though note that order may be unpredictable for a
dictionary). For each iteration of the loop, one element of the
iterable is available through the variable var
.
elements = ['H', 'He', 'Li', 'Be', 'B']
for element in elements:
print(element)
If you want to iterate over numbers, or simply do the same thing multiple times, use the built-in function
range(start, stop, step)
stop
,
with start=0
and step=1
.start
and stop
,
with step=1
.stop
is not included in the range.for i in range(1, 9, 2):
print(i)
If you want an integer index and successive values in an iterable, use
the enumerate
function. The basic syntax is
for <index>, <var> in enumerate(<iterable>):
<code>
for i, element in enumerate(elements):
print('Element', i+1, 'is', element)
The syntax for a while
loop is similar to that in other languages.
while <condition>:
<code>
i = 1
while i < 10:
print(i)
i += 1
Don't repeat yourself. If there's some task you're going to want to
perform frequently on different values, put it into a
function. Functions are defined using the def
keyword:
def <function_name>(<par1>, <par2>, <par3>=<default>, ...):
<code>
return <output>
=<default>
are called optional arguments or
keyword arguments. If no value is given when the function is called,
<default>
is used.<argument name> = <value>
, all later arguments must be supplied in
that form, and then order no longer matters.def get_weighted_average(values, power=1):
total = 0
num = 0
for value in values:
total += value ** power
num += 1
return total / num
get_weighted_average([2, 3, 5, 9], 1)
get_weighted_average([2, 3, 5, 9])
get_weighted_average([2, 3, 5, 9], 2)
String formatting is done using format strings, which contain literal text and replacement fields. The format of each replacement fields is as follows.
"{" [field_name] ["!" conversion] [":" format_spec] "}"
Note that each field is surrounded by braces. If you want a brace to
be interpreted as literal text, you escape it using double braces '{{'
or '}}'
.
Each of these is optional. We'll return to conversion
and format_spec
later.
There are two common ways of applying format strings.
Create a regular string, containing text and replacement fields,
and then call the strings format
function.
Here are some examples.
s = 'The quick brown {animal} jumps over the {adjective} dog.'
s.format(animal='fox', adjective='lazy')
But field_name
is optional, too. Without field names, arguments are
passed positionally:
s = 'The quick brown {} jumps over the {} dog.'
s.format('fox', 'lazy')
field_name
can also be a number, in which case it will be
interpreted as the position of the argument. We could then
reverse the inputs:
s = 'The quick brown {1} jumps over the {0} dog.'
s.format('fox', 'lazy')
'f'
in
front of the opening quotation mark. In that case, whatever goes
in the field_name
slot is evaluated as Python code. Note
that the field_name
is not optional when using f-strings.s = f'The quick brown {animal} jumps over the {adjective} dog.'
animal = 'fox'
adjective = 'lazy'
s = f'The quick brown {animal} jumps over the {adjective} dog.'
print(s)
f-strings allow you to do fancy things in the format strings.
s = f'The quick brown {animal} jumped over the {adjective} dog {3+4} times.'
print(s)
other_animal = 'cat'
s = f'The quick brown {animal + " and " + other_animal} jumped over the {adjective} dog {3+4} times.'
print(s)
CISV Of course, that example was silly. It would have been simpler to do this.
#CISV
s = f'The quick brown {animal} and {other_animal} jumped over the {adjective} dog {3+4} times.'
print(s)
The conversion
flag can be omitted, or it can be one of
'!s'
, which calls str()
on the value'!r'
, which calls repr()
on the value'!a'
, which calls ascii()
on the valueThe format_spec
can be omitted, in which case defaults are used based
on the type of the value supplied. The supported type specs depend on
the type of the value.
The full format_spec
may have the following parts:
[[fill]align][sign][0][width][grouping][.precision][type]
Since type
is the parameter most commonly supplied, here is a
list of the most common values (though without any of the other
flags, specifying only a type is not usually more useful than
leaving format_spec
out altogether).
str
, 's'
is the only supported type, so it
can be omitted.int
, the following are often used.'d'
: returns the number in base 10 (this is default and can
be omitted)'b'
: returns the number in base 2 (binary)'x'
or 'X'
: returns the number in base 16 (hex). The case
of the letter determines the cases of letters in the valuefloat
, the following are common.'f'
: fixed-point notation (the normal way to write numbers
with digits after a decimal point). The default number of
decimal places is 6.'e'
or 'E'
: scientific notation, with a default number
of decimal places of 6. The case determines the case of the
"e" or "E" separating the number from the exponent.'g'
: "general format." Behaves like either 'e'
or 'f'
,
depending on the size of the number, and tries to remove
unnecessary zeroes from the end. This is the default.'%'
: percentage (similar to 'f'
, but the number is
multiplied by 100 and has a percent sign appended.For the other flags, we'll go one at a time, moving (roughly) right to left, first definining some values to play with.
v1 = 1234.5
v2 = 299792458
v3 = 3.1415826535
print(f'{v1}')
print(f'{v2}')
print(f'{v3}')
print(f'{v2:x}')
.precision
specifies the number of digits to keep after a decimal point.
If the type flag is either 'f'
or 'e'
, the default is 6.print(f'{v1:.3f}')
print(f'{v2:.3f}')
print(f'{v3:.3f}')
grouping
specifies the thousands separator. It may be blank (no
grouping), ','
, or '_'
.print(f'{v1:_.3f}')
print(f'{v2:,.3f}')
print(f'{v3:,.3f}')
width
determines the minimum amount of space occupied by the
value.print(f'{v1:20_.3f}')
print(f'{v2:20,.3f}')
print(f'{v3:20,.3f}')
Clearly, the numbers are by default right-aligned.
align
specifies the alignment of the text within the allotted space.
The options are'<'
: left-aligned (default for most things)'>'
: right-aligned (default for numbers)'^'
: center-alignedprint(f'{v1:^20_.3f}')
print(f'{v2:20,.3f}')
print(f'{v3:<20,.3f}')
fill
determines what character should take up the blank space
to satisfy width
and align
. It can be any character except
a brace.print(f'{v1:)^20.3f}')
print(f'{v2:20.3f}')
print(f'{v3:*<20.3f}')
sign
can be '+'
: every number gets a sign, whether positive or
negative'-'
: only negative numbers get a sign' '
: only negative numbers get a sign, but positive
numbers get an extra space in front to help them align
with negative numbersprint(f'{v1:+20.3f}')
print(f'{v2:-20.3f}')
print(f'{v3: 20.3f}')
[0]
is present before the width
, then the padding is done
with zeroes rather than spaces.print(f'{v1:+020.3f}')
print(f'{v2:-020.3f}')
print(f'{v3: 020.3f}')
To open a file, use
with open('<path to file>') as <handle>:
<code>
The with
structure makes sure that resources used to access the file
are closed at the end of the block. <code>
should be something that
pulls data out of the file.
The open
function returns a file
object. It takes the path to the
file (either relative or absolute) as its first argument. It has a second,
optional argument to indicate the mode:
'r'
: read mode (default).'w'
: write mode (this will overwrite the contents of the file.'a'
: append mode (writing will append to the end of the file.The main options for pulling data are
file.read()
: Read the whole file as a single string.file.readlines()
: Read the file as a list of strings, one string
per line.Use the second with the example file.
with open('LRC_resonant_data.csv') as f:
data = f.readlines()
To work mathematically with the data, we need to clean it up.
str.strip()
method.str.split(<delimiter>)
method.for i, row in enumerate(data):
data[i] = row.strip().split(',')
A more elegant and computationally efficient method uses a list comprehension:
data = [row.strip().split(',') for row in data]
The heading can be separated using slicing.
heading = data[0]
data = data[1:]
We could get easy access to the columns using a for loop, as follows.
# CISV
columns = [ [] for _ in range(len(data[0])) ]
for row in data:
for i, col in enumerate(row):
columns[i].append(float(col))
Now the magic way.
# CISV
columns = [list(col) for col in zip(*data)]
# Create some smaller arrays and zip them up
a1 = [1, 2, 3, 4, 5]
a2 = ['a', 'b', 'c', 'd', 'e']
a3 = [0.1, 0.2, 0.3, 0.4, 0.5]
z = zip(a1, a2, a3)
list(z)
# Create a simple function
def join(a, b, c, d):
"""Combine the strings, separating them with spaces, and add a
period.
"""
return f'{a} {b} {c} {d}.'
# Create some arguments to play with in a list.
args = ["Do not", "drink", "battery", "acid"]
# Supplying the list does not work... `join` expects four arguments
join(args)
# CISV
# We could supply them by index
join(args[0], args[1], args[2], args[3])
# CISV
# But that's tedious, and it doesn't generalize to numbers other
# than four (for this case)
# The star **unpacks** the arguments
join(*args)
rows = [list(row) for row in zip(*columns)]
with open('LRC_resonant_data_out.csv', 'w') as outfile:
outfile.write(f'{heading[0]},{heading[1]}\n')
for f, V in rows:
outfile.write(f'{f},{V}\n')