# Python: Installation and Basic Syntax

## Installation

First of all you need to install the interpreter of the Python. Interpreter is the programm which will execute you code. Download Python and package manager pip from the official website and install in as an ordical programm. Don't forget to check the option Add Python 3.X to PATH to call Python's interpreter from the command line with simple python command. Mac users can install the python using the Homebrew package manager: brew install python3.

Then, install code editor you like. I would advise to use Sublime Text 3 but it is a matter of taste.

## Runnung the code

During this lesson I will extensively cite excelent book by Mark Lutz [1]. You can read it by self to refresh the material.

There are two ways to write and run Python's code: using interactive prompt or modules. The simplest one is to type commands at the Python’s interactive prompt and run it immediately.

To launch interactive prompt type python and pressing the Enter in the command line. Then you can write commands. Each command is run immediately after it’s entered. Moreover, because the interactive session automatically prints the results of expressions you type, you don’t usually need to say print explicitly at this prompt.

See Comparison of Common DOS and Linux Commands to do more with command line.

The interactive prompt runs code and echoes results as you go, but it doesn’t save your code in a file. Although this means you won’t do the bulk of your coding in interactive sessions, the interactive prompt turns out to be a great place to both experiment with the language and test program files on the fly.

Write down and execute a simple arithmetical expression: $1+1$. What is the answer?

To save programs permanently, you need to write your code in files, which are usually known as modules. Modules are simply text files containing Python statements. Once they are coded, you can ask the Python interpreter to execute the statements in such a file any number of times, and in a variety of ways — by system command lines, by file icon clicks and so on.

Create text file with .py extension. Paste former arithmetical expression to the file and show its result using the print() function. Run the module from the command line like this:
python <path-to-modile-here>


## Documentation

Ok, you have done a great job, but, I suppose, you have a lot of questions. The best way to answer them is to read the documentation. Spend at least 15 minutes browsing the Python library and language manuals before moving on to get a feel for the available tools in the standard library and the structure of the documentation set. It takes at least this long to become familiar with the locations of major topics in the manual set; once you’ve done this, it’s easy to find what you need.

## Structute of Python programms

Python programs can be decomposed into modules, statements, expressions, and objects, as follows

1. Programs are composed of modules.
2. Modules contain statements.
3. Statements contain expressions. Statements
4. Expressions create and process objects. Expression is an instruction that combines objects and operators and always evaluates down to a single value.

There is quite subtle difference between Statements and Expressions:

• Statements executed solely for their side effects, while expressions always return a result and often do not have side effects at all.
• ...hence statements are executed, while expressions are evaluated.
1 + 1 # this is an expression
some_var = 1 + 1 # but this is a statement, assignment statement namely
if some_var > 0: # this is also a statement
pass

It would be logically to start with expressions, but first of all I would like to mention assignment statement first since it is the most frequently used consructions in any language.

## Assignment statement and Variables

Variables are simply names created by you or Python that are used to keep track of information in your program.

a = 3 # create reference from name "a" to object "3" using assignment operator
a # now you can reference to the object "3" by the name "a"
3

Each time you generate a new value in your script by running an expression, Python creates a new object (i.e., a chunk of memory) to represent that value. Assignment statement is used to refer to that value in future.

Wikipedia said: "Assignment statement ... copies a value into the variable". It is really so for most languages, and in R, for example, assignment statement would be written as a <- 3 which stress that fact that you put (copy) the value into variable. But Python is different in that aspect, because assignment in Python mean reference.

• Variables are created when they are first assigned values.
• Variables are replaced with their values when used in expressions.
• Variables must be assigned before they can be used in expressions.
• Variables refer to objects and are never declared ahead of time.

Variables can be assigned in the following ways:

Operation Interpretation
spam = 'Spam' Basic form
spam, ham = 'yum', 'YUM' Tuple assignment (positional)
[spam, ham] = ['yum', 'YUM'] List assignment (positional)
a, b, c, d = 'spam' Sequence assignment, generalized
a, *b = 'spam' Extended sequence unpacking (Python 3.X)
spam = ham = 'lunch' Multiple-target assignment
spams += 42 Augmented assignment (equivalent to spams = spams + 42)

## Commentaries

The text after a # is simply ignored as a human-readable comment and is not considered part of the statement’s syntax. Comments can show up on lines by themselves, or to the right of code on a line.

## Expressions: core data types its operators

Now we can approach to the comprehension of the expressions. As you probably remember, expressions are instructions that combines objects and operators and always evaluates down to a single value. Lets consider core types of objects. It is extremely important since everything we process in Python programs is a kind of object — numbers, functions, classes, modules, everything! But fow now we will only consider objects which can store the data — core data types.

Core data type Build-in notation Constructor Mutable
Numbers 1234, 3.1415, 3+4j int, float, complex ✖️
Boolean bool ✖️
Strings 'spam', "Bob's" str ✖️
Lists [1, [2, 'three'], 4.5] list
Dictionaries {'food': 'spam', 'taste': 'yum'} dict
Tuples (1, 'spam', 4, 'U') tuple ✖️
Sets {'a', 'b', 'c'} set
Frоzen set frozenset ✖️
Other core types types, None

To get the type of any object pass it to the function type:

type("what type?")
str

Every type of object can be used with a definite set of operators in a definite way. For example, operator plus + sum numbers but concatinate the strings, operator - substract one number from anoth and can not be used with strings:

1 + 1 # sum
2
"abc" + "def" # string concatenation, not the sum
'abcdef'
"abc" - "def" # error
TypeError: unsupported operand type(s) for -: 'str' and 'str'
Guess, what will be the result if we apply multiplication operator to the string, like that: "mama" * 3?

Moreover, in addition to expression operators, data types provide a set of methods that implement more sophisticated tasks. In Python, expressions and built-in functions may work across a range of types, but methods are generally specific to object types — string methods, for example, work only on string objects. Methods are simply functions that are associated with and act upon particular objects. Technically, they are attributes attached to objects that happen to reference callable functions which always have an implied subject.

Method calls combine two operations at once — an attribute fetch using dot operator . and a call with brackets (). General syntax of calling method to process object with arguments looks like this:

object.method(arguments)

For example, to return a copy of the string with all the cased characters converted to uppercase call method upper on a string object.

"usa".upper() # returns "USA"
'USA'

Now lets look at the every core data type and investigate its methods and how it works with different operators.

### Numeric Types

In Python, numbers are not really a single object type, but a category of similar types:

• Integers that have no fractional part. Integers are written as strings of decimal digits: 123.
• Floating-point numbers have a decimal point and/or an optional signed exponent introduced by an e or E and followed by an optional sign: 1.23.

The other data types are used much less often:

• Complex. Numbers with real and imaginary parts.
• Fraction and Decimal for the best precision.
Some others also include booleans and sets into this category. there are reasons for this but I will regard them differently.
integer = 1234
integer_negative = -24
float_number = 1.23
float_engineer = 3.14e-10 # scientific notation
complex_num = 3 + 4j
print(type(complex_num), complex_num.real, complex_num.imag, sep=" "*5)
3.0 4.0

Python also allows us to write integers using decimal (base 10), hexadecimal (base 16), octal (base 8) or binary (base 2) literal:

octal = 0o177
binary = 0b101
How would you write the number 0b101 in decimal system?

#### Expression Operators for Numeric Types

Operators Description
x < y, x <= y, x > y, x >= y Comparison
x == y, x != y Equality
x + y Addition
x – y Subtraction
x * y Multiplication;
x % y Remainder
x / y, x // y Division: true and floor
−x Negation
x ** y Power

When you mix expressions in another expression, like 2 + 3 * 4^2, operators lower in the table have higher precedence. You can forget about precedence completely if you’re careful to group parts of expres- sions with parentheses: ((2 + 3) * 4)^2.

Besides mixing operators in expressions, you can also mix numeric types. For instance, you can add an integer to a floating-point number:

2 + 2.3
11.5

To execute this expression Python converts more simple types to more complex: integers are simpler than floating-point numbers, which are simpler than complex numbers.

Result of comparisons between number is a boolean value.

1 < 2 # Less than
True

### Boolean

Python Boolean type, bool, is numeric in nature because its two values, True and False, are just customized versions of the integers 1 and 0 that print themselves differently. Because True is just the integer 1 with a custom display format, True + 4 yields integer 5 in Python!

True + 4 # lolwut
5

You can make sure that numeric data type is really an ancestor of the boolean by calling isinstance function, which returns True if the specified object is of the specified type, otherwise False.

isinstance(True, int), issubclass(bool, int)
(True, True)
bool(0), bool(1)
(False, True)

#### Logical operators

Operators Description
x if y else z Ternary selection (x is evaluated only if y is true)
x or y Logical OR (y is evaluated only if x is false)
x and y Logical AND (y is evaluated only if x is true)
not x Logical negation
x in y, x not in y Membership (iterables, sets)
x is y, x is not y Object identity tests
x == y, x != y Value equality operators
x \| y Bitwise OR
x ^ y Value equality operators
x & y Bitwise AND

Most these operators are quite easy to understand. Быстро объяснить

Looking at this table you might ask some question.

True == 1 # equal values
True
True is 1 # but not the same
False
Determine whether the given year is a leap year. A year is a leap year if it is a multiple of 4, but not a multiple of 100, or a multiple of 400.
year = # type a year here
is_leap = # write logical expression here
print(is_leap) 

### String

Strings are defined as immutable ordered sequence of characters. Strings are used to record both textual information (your name, for instance) as well as arbitrary collections of bytes (such as an image file’s contents). They are our first example of what in Python we call a sequence—a positionally ordered collection of other objects. Sequences maintain a left-to-right order among the items they contain: their items are stored and fetched by their relative positions. Strictly speaking, strings are sequences of one-character strings; other, more general sequence types include lists and tuples, covered later.

The start and end of the string are defined with a pair of quotation marks. Around Python strings, single- and double-quote characters are interchangeable.

# BTW you can split the strings in code like this

s = "D'Artagnan, seeing him approach, drew his" + \
" sword a foot out of the scabbard." # a string
s = '"This horse is decidedly, or rather has been in his ' + \
'youth, a buttercup," resumed the stranger' # also a string
According to PEP8 the line length should be limited to 72 characters. To split long expression on the many lines you need to enclose it in any kind of brackets ((), [], {}), or use \ as delimiter.

Python also has a triple-quoted string literal format, sometimes called a block string, that is a syntactic convenience for coding multiline text data. This form begins with three quotes (of either the single or double variety), is followed by any number of lines of text, and is closed with the same triple-quote sequence that opened it. Single and double quotes embedded in the string’s text may be, but do not have to be, escaped.

s = '''
She walks in beauty, like the night
Of cloudless climes and starry skies;
And all that’s best of dark and bright
Meet in her aspect and her eyes;

Excerpt from the poem "She Walks in Beauty" by LORD BYRON
''' # multiline string

#### String as a Sequence: Indexing and Slicing

Because strings are sequences, we can access their components by position. In Python, characters in a string are fetched by indexing— providing the numeric offset of the desired component in square brackets after the string.

Indexes are coded as offsets from the front, and so start from 0: the first item is at index 0, the second is at index 1, and so on. Index ends at one less than the length of the string.

s = 'abcdefghijklmnop'
s[1] # second character
'b'

Python also lets you fetch items from sequences such as strings using negative offsets. Technically, a negative offset is added to the length of a string to derive a positive offset.

s[-2] # penultimate character
'o'

In addition to simple positional indexing, sequences also support a more general form of indexing known as slicing, which is a way to extract an entire section (slice) in a single step. The left offset is taken to be the lower bound (inclusive), and the right is the upper bound (noninclusive).

s[1:-2] # slice [start: end]
'bcdefghijklmn'

In a slice, the left bound defaults to zero, and the right bound defaults to the length of the sequence being sliced:

s[:3] # returns first the charasters
'abc'

Slice expressions support for an optional third index, used as a step (sometimes called a stride). The step is added to the index of each item extracted:

s[:5:2] # extract every second item in "s", from beginig through 4.
'ace'

Because strings are the sequences you can also use the other keywords with them: in, for and so on.

from string import punctuation

for char in punctuation[:5]:
print(f"Character {char}.")
Character !.
Character ".
Character #.
Character $. Character %. Print the string Mr. Owl ate my metal worm in the reverse order. How is this type of phrase called? #### String is an immutable type Every string operation is defined to produce a new string as its result, because strings are immutable in Python—they cannot be changed in place after they are created. In other words, you can never overwrite the values of immutable objects. For example, you can’t change a string by assigning to one of its positions, but you can always build a new one and assign it to the same name. To prove thi I will use id function, which returns unique and constant integer for the object: example_string = "Hello" print(id(example_string)) example_string = example_string + ", world!" print(id(example_string)) 4538087384 4538059696 #### Basic operators Operators Interpretation S1 + S2 Concatenate S * 3 Repeat S[i] Index S[i:j:k] Slice len(S) Length in Membership for Loop #### String Methods Methods Interpretation S.split() Split on delimiter S.rstrip() Remove whitespace S.replace('pa', 'xx') Replacement S.split(',') Split on delimiter S.isdigit() Content test S.lower(), S.upper() Case conversion S.startswith('spam') Start test S.endswith('spam') End test S.find('spam') Search. -1 if no, index if yes Execute help(str().replace) to how this method works. #### Escape characters As many other languages Python supports eascape characters this the strings. Escape character is a character which invokes an alternative interpretation on subsequent characters in a character sequence. An escape character may not have its own meaning, so all escape sequences are of two or more characters. The common escape characters are: • \' — single quote • \" — double quote • \\\\ — backslash • \n — new line • \r — carriage return • \t — tab • \b — backspace • \xFF — character represented by the hexadecimal byte "FF" print('Fifteen men on the dead man\'s chest—\n...\xFFo-ho-ho, and a bottle of rum!') Fifteen men on the dead man's chest— ...ÿo-ho-ho, and a bottle of rum! #### String Conversion One of Python’s design mottos is that it refuses the temptation to guess. As a prime example, you cannot add a number and a string together in Python, even if the string looks like a number, because + can mean both addition and concatenation, the choice of conversion would be ambiguous. Instead, Python treats this as an error. '2' + 2 TypeError: can only concatenate str (not "int") to str You need to employ conversion tools before you can treat a string like a number, or vice versa "2" + str(2), int("2") + 2 ('22', 4) Empty string is converted to the boolean False when necessary: bool("abs"), bool("") (True, False) It is very convenient. Otherwise we have to write less readable if name != "" at the lower statement. name = "" if not name: print("Fill the name, please") Fill the name, please #### String formatting The easiest way to format a string is to concatenate existing strings using the + operator. But if the strings are long and there are many of them, this approach will not work, and you will need to refer to the string formatting expressions. There are many ways to format strings in Python. Let consider two most common: string object’s format method and f-strings. The string object’s format method uses the subject string as a template, and takes any number of arguments that represent values to be substituted according to the template. Within the subject string, curly braces designate substitution targets and arguments to be inserted either by position (e.g., {1}), or keyword (e.g., {food}), or relative position ({}) 'Talk is cheap. Show me the code. ({})'.format('Linus Torvalds') 'Talk is cheap. Show me the code. (Linus Torvalds)' "{1}. ({0})".format( "Alan J. Perlis", "A language that doesn't affect the way you think about programming is not worth knowing" ) "A language that doesn't affect the way you think about programming is not worth knowing. (Alan J. Perlis)" quote = "What one programmer can do in {number} {period}, two programmers can do in {number} {period}s. - Fred Brooks" for num in range(3): print(quote.format(number=num + 1, period="month")) What one programmer can do in 1 month, two programmers can do in 1 months. - Fred Brooks What one programmer can do in 2 month, two programmers can do in 2 months. - Fred Brooks What one programmer can do in 3 month, two programmers can do in 3 months. - Fred Brooks f-strings are string literals that have an f at the beginning and curly braces containing expressions that will be replaced with their values. for num in range(3): period = "month" print(f"What one programmer can do in {num + 1} {period}, two programmers can do in {num + 1} {period}s. - Fred Brooks") What one programmer can do in 1 month, two programmers can do in 1 months. - Fred Brooks What one programmer can do in 2 month, two programmers can do in 2 months. - Fred Brooks What one programmer can do in 3 month, two programmers can do in 3 months. - Fred Brooks See more about string formatting in Python at the pyformat.info and read the docs on Format Specification Mini-Language. #### String Methods In Python, expressions and built-in functions may work across a range of types, but methods are generally specific to object types — string methods, for example, work only on string objects. Methods Interpretation S.split() Split on delimiter ','.join(strlist) Delimiter join S.strip() Return a copy of the string with the leading and trailing characters removed S.replace('pa', 'xx') Replacement S.isdigit() Content test S.lower(), S.upper() Case conversion S.startswith('spam') Start test S.endswith('spam') End test S.find('spam') Search. -1 if no, index if yes S.encode('CP1251') Unicode encoding B.decode('utf8') Unicode decoding #### Byte strings The computer does not work with characters, but with their byte representations. Bytes, not strings, are transmitted over the network and saved to disk. Often all this happens automatically, however, sometimes it is necessary to create byte strings manually. A byte string is an immutable sequence of numbers from 0 to 255. example_bytes = b"hello" print(type(example_bytes)) for element in example_bytes: print(element) 104 101 108 108 111 example_bytes = b"привет" SyntaxError: bytes can only contain ASCII literal characters. (<ipython-input-80-464a5586e9cf>, line 1) We can encode stings to bytes and decode from it with encode and decode methods. example_string = "привет" encoded_string = example_string.encode(encoding="utf-8") print(encoded_string) b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' See unicode-table.com to check if this string is a real unicode string represented in a byte form. decoded_string = encoded_string.decode() print(decoded_string) привет That is a song by Nirvana. Rape me, rape me my friend Rape me, rape me again I'm not the only one I'm not the only one I'm not the only one I'm not the only one Hate me Do it and do it again Waste me Rape me, my friend I'm not the only one I'm not the only one I'm not the only one I'm not the only one My favorite inside source I'll kiss your open sores Appreciate your concern You're gonna stink and burn Rape me, rape me my friend Rape me, rape me again I'm not the only one I'm not the only one I'm not the only one I'm not the only one Rape me (rape me) Rape me (rape me) Rape me (rape me) Rape me (rape me) Rape me (rape me) Rape me (rape me) Rape me (rape me) Rape me (rape me) Rape me • How many words have this song? • This song sounds a bit depressive, isn't it? Make it more positive by replacing phrase "rape me" to "kiss me" (regardless of case) • Print this song from end to begining. Try to sing it. 🎉Good job!🎉 Enjoy you prize! ### None Python also provides a special object called None. It is the only value of a special data type in Python and typically serves as an empty placeholder. None is always considered to be false but it is not the false. A variable with a value of None can come in handy when you need to distinguish it from zero. income = None if income is None: print("Have not started selling") elif not income: print("Have not earn anything") else: print(f"Earned {income}$")
Have not started selling

### Lists

The Python list object is the most general sequence provided by the language. Lists are positionally ordered collections of arbitrarily typed objects, and they have no fixed size. They are also mutable—unlike strings, lists can be modified in place by assignment to offsets as well as a variety of list method calls.

In Python lists are written with square brackets or you can create a list from the other object with list conctructor.

l = [] # An empty list
l = list('spam') # List of an iterable’s items
l
['s', 'p', 'a', 'm']

Lists support all the sequence operations we discussed for strings:

len(l), l[::-1]
(4, ['m', 'a', 'p', 's'])

Lists support arbitrary nesting — we can nest them as deeply as we like.

l = ['Sasha', 40.0, [ 'manager', 'analyst']] # create nested sublists
l[2][0] # grab the third element, then first
'manager'

To perform in-plase sorting use sort method.

l[2].sort() # 'manager', 'analyst' -> 'analyst', 'manager'
l
['Sasha', 40.0, ['analyst', 'manager']]

We can update list using index assignment ot special methods:

l[1] = 23 # Index assignment
l
['Sasha', 23, ['analyst', 'manager']]

The insert function takes two parameters: index - position where an element needs to be inserted, and item to be inserted.

l.insert(1, 32)
l
['Sasha', 32, 23, ['analyst', 'manager']]

append method adds a single item to the end of the list.

l.append([5,6,7])
l
['Sasha', 32, 23, ['analyst', 'manager'], [5, 6, 7]]

extend method adds items from another list (or any sequence) to the end.

l.extend([5,6,7])
l
['Sasha', 32, 23, ['analyst', 'manager'], [5, 6, 7], 5, 6, 7]

remove method removes item by literal.

l.remove(5)
l
['Sasha', 32, 23, ['analyst', 'manager'], [5, 6, 7], 6, 7]

pop method removes an individual item (last by default if no argument) and returns it:

print('removed: {} \nremained: {}'.format(l.pop(3), l))
removed: ['analyst', 'manager']
remained: ['Sasha', 32, 23, [5, 6, 7], 6, 7]

del keyword removes an individual item by index, or to remove all items identified by a slice.

del l[:3]
l
[[5, 6, 7], 6, 7]

It is also possible to use + and * with lists as the are sequences:

list('spam') + [5,6,7]
['s', 'p', 'a', 'm', 5, 6, 7]
[None] * 10 # predefined empty list
[None, None, None, None, None, None, None, None, None, None]

#### Practical assignment

1. Create a shopping list with apple, strawberry, carrot, banana.
2. What is the length of this list? Print it.
3. Add rice to the end of this list.
4. Sort shopping list alphabetically for a to z.
5. Print last two items of this list.
6. You just have remembered that you have allergy on strawberry. Replce it with orange.
7. Bon appétit!

### Dictionaries

Python dictionaries (also called associative arrays or hashes) are quite special kind of collections: they are not sequences, but mappings. Mappings are collections of other objects, like lists, but they store objects by key instead of by relative position. In fact, mappings don’t maintain any reliable left-to-right order; they simply map keys to associated values. Because dictionaries are unordered collections, operations that depend on a fixed positional order (e.g., concatenation, slicing) don’t make sense.

Dictionaries, the only mapping type in Python’s core objects set, are also mutable: like lists, they may be changed in place and can grow and shrink on demand.

To define a dictionary, you must use a literal brace or simply call dict function.

empty_dict = {}
empty_dict = dict()
collections_map = {
'mutable': ['list', 'set', 'dict'],
'immutable': ['tuple', 'frozenset', "numbers", "strings"]
}

Access to the value by key is carried out for a constant time, that is, does not depend on the size of the dictionary. This is achieved using a hashing algorithm. However, bacause of that dictionaries do not contain information about the order.

We can access the values of the dictionary much as we did for our list - using square brackets, but this time we need to place dictionary key inside, not list offsets.

collections_map['immutable']
['tuple', 'frozenset']

If you try to access by a key that does not exist, Python will generate a KeyError exception. However, it is often useful to return some default value if the key does not exist. There is a built-in get method for that purpose:

collections_map.get('irresistible', 'not found')

Lets create online cart for the delivery service. It could look like this:

cart = [
{
"items": [
{
"name": "pizza",
"amount": 2,
"price": 10
},
{
"name": "coca-cola",
"amount": 4,
"price": 2
}

],
"customer": {
"name": "Sam",
}
},
{
"items": [
{
"name": "sushi",
"amount": 5,
"price": 6
}

],
"customer": {
"name": "Kate",
}
}
]

What food Sam ordered?

sam_ordered = cart[0]["items"]
sam_ordered
[{'name': 'pizza', 'amount': 2, 'price': 10},
{'name': 'coca-cola', 'amount': 4, 'price': 2}]

How Sam can order one more pizza?

sam_ordered[0]["amount"] =+ 1

He also want to order vegetarian pizza. Lets add it as a new key:

sam_ordered[0].update({"vegeterian": True})
# cart[0]["items"][0]["vegeterian"] = True — will yield the same result
cart
[{'items': [{'name': 'pizza', 'amount': 1, 'price': 10, 'vegeterian': True},
{'name': 'coca-cola', 'amount': 4, 'price': 2}],
'customer': {'name': 'Sam', 'address': 'Kukuevo, 34'}},
{'items': [{'name': 'sushi', 'amount': 5, 'price': 6}],
'customer': {'name': 'Kate', 'address': 'Sedova, 55'}}]

To test if the key present in a dictionary use in operator:

"vegeterian" in sam_ordered[0]
True
sam_ordered[0].keys() # Method: all keys
dict_keys(['name', 'amount', 'price', 'vegeterian'])
sam_ordered[0].values() # Method: all values
dict_values(['pizza', 1, 10, True])
sam_ordered[0].items() # Method: all key+value tuples
dict_items([('name', 'pizza'), ('amount', 1), ('price', 10), ('vegeterian', True)])
del cart[0]["items"][0]["vegeterian"]
"vegeterian" in sam_ordered[0]
False

#### Practical assignment

Add the following order in the cart: Sasha Berg ordered a one pepperoni pizza and two bottles of Coca-cola.

### Files

The built-in open function creates a Python file object, which serves as a link to a file residing on your machine. After calling open, you can transfer strings of data to and from the associated external file by calling the returned file object’s methods.

Compared to the types you’ve seen so far, file objects are somewhat unusual. They are considered a core type because they are created by a built-in function, but they’re not numbers, sequences, or mappings, and they don’t respond to expression operators; they export only methods for common file-processing tasks.

To open a file, a program calls the built-in open function, with the external filename first, followed by a processing mode. The call returns a file object, which in turn has methods for data transfer:

========= ===============================================================
Character Meaning
--------- ---------------------------------------------------------------
'w'       open for writing, truncating the file first
'x'       create a new file and open it for writing
'a'       open for writing, appending to the end of the file if it exists
'b'       binary mode
't'       text mode (default)

file_obj = open("data.txt", "wt", encoding="utf8")
file_obj.write("First line\n") # Write a line of text: string
file_obj.write("Second line\n")
file_obj.close() # Close the file
file_obj = open("data.txt")
file_obj.readlines()
['First line\n', 'Second line\n']
file_obj.seek(0)
0
for line in file_obj:
print(line.upper(), end="")
FIRST LINE
SECOND LINE

At the end of the work we should not forget to close file connection:

file_obj.close()

The better way to open the files is to use context-manager with, which allows you not to worry about closing files. You can open the file with the with operator, write the file object to the variablefile_obj and then work with the file inside this context block. After exiting the block, the Python interpreter will close the file automatically.

with open("data.txt") as file_obj:
for line in file_obj:
print(line.upper(), end="")
FIRST LINE
SECOND LINE

## Statements

As we remember, programs written in the Python language are composed of statements and expressions. Expressions process objects and are embedded in statements. Statements code the larger logic of a program’s operation — they use and direct expressions to process the objects we studied in the preceding chapters. There are two types of statements: simple and compound.

name = "Yuri" # simple assignment statement

All Python compound statements — statements that have other statements nested inside them — follow the same general pattern of a header line terminated in a colon, followed by a nested block of code usually indented underneath the header line, like this:

Header line:
Nested statement block


The colon is required, and omitting it is probably the most common coding mistake among new Python programmers.

There is no universal standard on this: four spaces or one tab per level is common, but it’s generally up to you to decide how and how much you wish to indent, but you probably shouldn’t mix tabs and spaces.

Although statements normally appear one per line, it is possible to squeeze more than one statement onto a single line in Python by separating them with semicolons:

a = 1; b = 2; print(a + b) # Three statements on one line
3

This is the only place in Python where semicolons are required: as statement separators.

### if Statement

if statement selects actions to perform. It represents much of the logic a Python program.

General format:

if test1:          # if test
statements1
elif test2:        # Optional elifs
statements2
else:              # Optional else
statements3

i = 3

if i < 5:
print(True)
i = i + 1

To handle a false result, code the else:

if i < 5:
print(True)
i = i + 1
else:
print(False)
False
if i < 0:
print(i/5)
elif i > 0:
print(i/3)
else:
pass
Positive
if i < 0:
print(i/5)
else:
if i > 0:
print(i/3)
else:
print("error") # pass

### for loops

for can step through the items in any ordered sequence or other iterable object. The for statement works on strings, lists, tuples, and other iterables.

General format:

for target in object:
statements

names = ["Sasha Robinovich", "Bob Smith", "Sasha Grey", "Max"]

for name in names:
print(name)
Sasha Robinovich
Bob Smith
Sasha Grey
Max
names = ["Sasha Robinovich", "Bob Smith", "Sasha Grey", "Max"]

for name in names:
if "Sasha" in name:
print(name)
Sasha Robinovich

More complete format:

for target in object:
statements
else:                   # Optional else part
statements          # If we didn't hit a 'break'


Else statement executes if the loop exits without running into a break statement.

The break statement causes an immediate exit from a loop. Because the code that follows it in the loop is not executed if the break is reached, you can also sometimes avoid nesting by including a break.

The continue statement causes an immediate jump to the top of a loop. It also sometimes lets you avoid statement nesting.

The pass statement does nothing at all: it’s an empty statement placeholder.

#### Practical assignment 1

Create a list with odd numbers in a range from 0 to 50.

Hint: use function range() to create a range.

# write your code here

### Practical assignment 2

Write a for loop that will print the names of all ordered items in the card (which we created before)

# write your code here

### List Comprehensions

List comprehensions provide a concise way to create lists.

As list comprehension returns list, they consists of brackets containing the expression which needs to be executed for each element along with the for loop to iterate over each element.

#### Practical assignment

Rewrite "Practical assignment 1" above (about odd numbers) using list comprehensions

# write your code here

### while loop

It repeatedly executes a block of (normally indented) statements as long as a test at the top keeps evaluating to a true value.

while test:
statements
else:
statements

i = 0

while i != 5:
print(i)
i += 1
0
1
2
3
4

### Practical assignment

Some guys scraped tweets from 100+ pro-ISIS fanboys from all over the world since the November 2015 Paris Attacks.

Example of such tweet:

RT @maaj19: سَمِعْنَا وَ أطَعْنَا #gd #gd#fdfd @allah

I saved random sample of these tweets in a file "tweets_IS.txt", one tweet per line. Read the file and do the following tasks:

1. Calculate the distribution of hashtags. What is the most populat hashtag in these tweets?
2. Calculate the distribution of mentions. What is the most populat user mentioned in these tweets?
3. What is the longest tweet?
# write your code here

## Function

Function groups a set of statements so they can be run more than once in a programa packaged procedure invoked by name. Functions also can compute a result value and let us specify parameters that serve as function inputs and may differ each time the code is run.

Functions are also the most basic program structure Python provides for maximizing code reuse. As we’ll see, functions let us split complex systems into manageable parts. By implementing each part as a function, we make it both reusable and easier to code.

General format:

def name(arg1, arg2,... argN):
statements
return value # optional part


As with all compound Python statements, def consists of a header line followed by a block of statements, usually indented (or a simple statement after the colon). The statement block becomes the function’s body — that is, the code Python executes each time the function is later called.

The Python return statement can show up anywhere in a function body; when reached, it ends the function call and sends a result back to the caller.

Python has a lot og build in functions:

Lets define a function:

def times(x, y): # Create and assign function
return x * y # Body executed when called
times(2, 4) # Arguments in parentheses
8
x = times("lo", 4) # Save the result object
x
'lolololo'

Functions can accept default arguments. These arguments can either be specified by the caller or left blank to automatically receive a predefined value.

def power(x, power=2): # to the power of 2 by default
return x ** power # Body executed when called
power(3)
9
power(3, 1)
3

### Lambda functions

Besides the def statement, Python also provides an expression form that generates function objects, it’s called lambda.

Like def, this expression creates a function to be called later, but it returns the function instead of assigning it to a name. This is why lambdas are sometimes known as anonymous (i.e., unnamed) functions. In practice, they are often used as a way to inline a function definition.

The lambda’s general form is the keyword lambda, followed by one or more arguments (exactly like the arguments list you enclose in parentheses in a def header), followed by an expression after a colon:

lambda argument1, argument2,... argumentN : expression using arguments

def power(x, power=2):
return x ** power
power = lambda x, power=2: x**power

There are a few differences that make lambdas useful in specialized roles:

1. lambda is an expression, not a statement. Because of this, a lambda can appear in places a def is not allowed by Python’s syntax—inside a list literal or a function call’s arguments, for example. With def, functions can be referenced by name but must be created elsewhere. As an expression, lambda returns a value (a new func- tion) that can optionally be assigned a name. In contrast, the def statement always assigns the new function to the name in the header, instead of returning it as a result.

2. lambda’s body is a single expression, not a block of statements.

#### Why Use lambda?

Take a look at the sorted function. It returns a new list containing all items from the iterable in ascending order.

sorted()

Lets create a list of random numbers with module random.

import random
# Return a k sized list of population elements chosen with replacement.
random_list = random.choices(range(100), k=10)
random_list
[28, 61, 3, 11, 96, 73, 33, 28, 93, 32]
sorted(random_list)
[3, 11, 28, 28, 32, 33, 61, 73, 93, 96]

sorted function has an argument key, which accept a custom key function can be supplied to customize the sort order. It is useful when we want to sort by nested element.

orders = [
{
"name": "pizza pepperoni",
"price": 12,
"amount": 1
},
{
"name": "Coca-cola",
"price": 4,
"amount": 2
},
{
"name": "Cupcake",
"price": 3,
"amount": 10
}
]
sorted(orders, key=lambda el: el["price"])
[{'name': 'Cupcake', 'price': 3, 'amount': 10},
{'name': 'Coca-cola', 'price': 4, 'amount': 2},
{'name': 'pizza pepperoni', 'price': 12, 'amount': 1}]
# it is the same as
def sort_function(el):
return el["price"]

sorted(orders, key=sort_function)
[{'name': 'Cupcake', 'price': 3, 'amount': 10},
{'name': 'Coca-cola', 'price': 4, 'amount': 2},
{'name': 'pizza pepperoni', 'price': 12, 'amount': 1}]

## Modules

1. Programs are composed of modules.
2. Modules contain statements.
3. Statements contain expressions.
4. Expressions create and process objects.

Python module is the highest-level program organization unit, which packages program code and data for reuse, and provides self-contained namespaces that minimize variable name clashes across your programs.

import math # import lets a client (importer) fetch a module as a whole
math
math.pi # constants
3.141592653589793
math.cos(math.pi)
-1.0
import math as m # The as keyword is used for aliasing in Python.
from math import log, e # from allows clients to fetch particular names from a module
log(e)
1.0
from math import factorial as fct # import, as and from can be used together
fct(10)
3628800

### Practical assignment

Implement your own key-value storage. Your task is to write a program that accepts keys as an arguments and returns an associated values from a storage — json-file.

To write a value

storage.py --key key_name --val value

To get a value(s) by key

storage.py --key key_name

In this case result could look like this:

value

or

value_1, value_2

if more than one value was written.

If no values were associated with key return None.

To transfer arguments to the script with command line use argparse module. Onve again — your task will be to take the arguments passed to your program and write the corresponding key-value pair to the storage file or display the values if only the key was passed. You can store data in JSON format using the standard module json. Use json.load(open(storage_path, 'r')) to open json file and json.dump(storage, open(storage_path, 'w')) to save the data, see docs for more.

To create a file better use tempfile module.

import os
import tempfile
import argparse
import json

storage_path = os.path.join(tempfile.gettempdir(), 'storage1.data')
parser = argparse.ArgumentParser()
parser.add_argument("--key", help="Получение значения по ключу или запись")
parser.add_argument("--value", help="Запись значения, если указан ключ")
args = parser.parse_args()
# your turn