<jupyter_start><jupyter_text>Control Logics and FunctionsCode adapted from: https://github.com/jerry-git/learn-python3  Conditionals  Testing truth value  `bool`<jupyter_code>print('type of True and False: {}'.format(type(True)))
print('0: {}, 1: {}'.format(bool(0), bool(1)))
print('empty list: {}, list with values: {}'.format(bool([]), bool(['woop'])))
print('empty dict: {}, dict with values: {}'.format(bool({}), bool({'Python': 'cool'})))<jupyter_output>0: False, 1: True
empty list: False, list with values: True
empty dict: False, dict with values: True<jupyter_text>`==, !=, >, =, <=`<jupyter_code>print('1 == 0: {}'.format(1 == 0))
print('1 != 0: {}'.format(1 != 0))
print('1 > 0: {}'.format(1 > 0))
print('1 > 1: {}'.format(1 > 1))
print('1 < 0: {}'.format(1 < 0))
print('1 < 1: {}'.format(1 < 1))
print('1 >= 0: {}'.format(1 >= 0))
print('1 >= 1: {}'.format(1 >= 1))
print('1 <= 0: {}'.format(1 <= 0))
print('1 <= 1: {}'.format(1 <= 1))<jupyter_output>1 == 0: False
1 != 0: True
1 > 0: True
1 > 1: False
1 < 0: False
1 < 1: False
1 >= 0: True
1 >= 1: True
1 <= 0: False
1 <= 1: True<jupyter_text>You can combine these:<jupyter_code>print('1 <= 2 <= 3: {}'.format(1 <= 2 <= 3))<jupyter_output>1 <= 2 <= 3: True<jupyter_text>`and, or, not`<jupyter_code>python_is_cool = True
java_is_cool = False
empty_list = []
secret_value = 3.14
print('Python and java are both cool: {}'.format(python_is_cool and java_is_cool))
print('secret_value and python_is_cool: {}'.format(secret_value and python_is_cool))
print('Python or java is cool: {}'.format(python_is_cool or java_is_cool))
print('1 >= 1.1 or 2 < float("1.4"): {}'.format(1 >= 1.1 or 2 < float('1.4')))
print('Java is not cool: {}'.format(not java_is_cool))<jupyter_output>Java is not cool: True<jupyter_text>You can combine multiple statements, execution order is from left to right. You can control the execution order by using brackets.<jupyter_code>print(bool(not java_is_cool or secret_value and  python_is_cool or empty_list))
print(bool(not (java_is_cool or secret_value and  python_is_cool or empty_list)))<jupyter_output>True
False<jupyter_text>`if`<jupyter_code>statement = True
if statement:
    print('statement is True')
    
if not statement:
    print('statement is not True')
empty_list = []
# With if and elif, conversion to `bool` is implicit
if empty_list:
    print('empty list will not evaluate to True')  # this won't be executed
val = 3
if 0 <= val < 1 or val == 3:
    print('Value is positive and less than one or value is three')<jupyter_output>Value is positive and less than one or value is three<jupyter_text>`if-else`<jupyter_code>my_dict = {}
if my_dict:
    print('there is something in my dict')
else:
    print('my dict is empty :(')<jupyter_output>my dict is empty :(<jupyter_text>`if-elif-else`<jupyter_code>val = 88
if val >= 100:
    print('value is equal or greater than 100')
elif val > 10:
    print('value is greater than 10 but less than 100')
else:
    print('value is equal or less than 10')<jupyter_output>value is greater than 10 but less than 100<jupyter_text>You can have as many `elif` statements as you need. In addition, `else` at the end is not mandatory.<jupyter_code>greeting = 'Hello fellow Pythonista!'
language = 'Italian'

if language == 'Swedish':
    greeting = 'Hejsan!'
elif language == 'Finnish':
    greeting = 'Latua perkele!'
elif language == 'Spanish':
    greeting = 'Hola!'
elif language == 'German':
    greeting = 'Guten Tag!'
    
print(greeting)<jupyter_output>Hello fellow Pythonista!<jupyter_text>For more detailed overview about conditionals, check this [tutorial from Real Python](https://realpython.com/python-conditional-statements/).  [`for` loops](https://docs.python.org/3/tutorial/controlflow.htmlfor-statements)  Looping lists<jupyter_code>my_list = [1, 2, 3, 4, 'Python', 'is', 'neat']
for item in my_list:
    print(item)<jupyter_output>1
2
3
4
Python
is
neat<jupyter_text>`break`Stop the execution of the loop.<jupyter_code>for item in my_list:
    if item == 'Python':
        break
    print(item)<jupyter_output>1
2
3
4<jupyter_text>`continue`Continue to the next item without executing the lines occuring after `continue` inside the loop.<jupyter_code>for item in my_list:
    if item == 1:
        continue
    print(item)<jupyter_output>2
3
4
Python
is
neat<jupyter_text>`enumerate()`In case you need to also know the index:<jupyter_code>for idx, val in enumerate(my_list):
    print('idx: {}, value: {}'.format(idx, val))<jupyter_output>idx: 0, value: odd
idx: 1, value: odd
idx: 2, value: even
idx: 3, value: even
idx: 4, value: odd
idx: 5, value: five even
idx: 6, value: five even
idx: 7, value: five odd<jupyter_text>Looping dictionaries<jupyter_code>my_dict = {'hacker': True, 'age': 72, 'name': '<NAME>'}
for val in my_dict:
    print(val)
for key, val in my_dict.items():
    print('{}={}'.format(key, val))<jupyter_output>hacker=True
age=72
name=<NAME><jupyter_text>`range()`<jupyter_code>for number in range(5):
    print(number)
for number in range(2, 5):
    print(number)
for number in range(0, 10, 2):  # last one is step
    print(number)<jupyter_output>0
2
4
6
8<jupyter_text>Idiomatic loops  Looping in general<jupyter_code>data = ['John', 'Doe', 'was', 'here']<jupyter_output><empty_output><jupyter_text>Don't do it like this. While loops are actually really rarely needed.<jupyter_code>idx = 0
while idx < len(data):
    print(data[idx])
    idx += 1<jupyter_output>John
Doe
was
here<jupyter_text>Don't do like this either.<jupyter_code>for idx in range(len(data)):
    print(data[idx])<jupyter_output>John
Doe
was
here<jupyter_text>Do it like this!<jupyter_code>for item in data:
    print(item)<jupyter_output>John
Doe
was
here<jupyter_text>If you need the index as well, you can use enumerate.<jupyter_code>for idx, val in enumerate(data):
    print('{}: {}'.format(idx, val))<jupyter_output>0: John
1: Doe
2: was
3: here<jupyter_text>Looping over a range of numbers Don't do this.<jupyter_code>i = 0
while i < 6:
    print(i)
    i += 1<jupyter_output>0
1
2
3
4
5<jupyter_text>Don't do this either.<jupyter_code>for val in [0, 1, 2, 3, 4, 5]:
    print(val)<jupyter_output>0
1
2
3
4
5<jupyter_text>Do it like this!<jupyter_code>for val in range(6):
    print(val)<jupyter_output>0
1
2
3
4
5<jupyter_text>Reversed looping<jupyter_code>data = ['first', 'to', 'last', 'from']<jupyter_output><empty_output><jupyter_text>This is no good.<jupyter_code>i = len(data) - 1
while i >= 0:
    print(data[i])
    i -= 1<jupyter_output>from
last
to
first<jupyter_text>Do it like this!<jupyter_code>for item in reversed(data):
    print(item)<jupyter_output>from
last
to
first<jupyter_text>Looping over __n__ collections simultaneously<jupyter_code>collection1 = ['a', 'b', 'c']
collection2 = (10, 20, 30, 40, 50)
collection3 = ['John', 'Doe', True]<jupyter_output><empty_output><jupyter_text>Oh boy, not like this.<jupyter_code>shortest = len(collection1)
if len(collection2) < shortest:
    shortest = len(collection2)
if len(collection3) < shortest:
    shortest = len(collection3)
    
i = 0
while i < shortest:
    print(collection1[i], collection2[i], collection3[i])
    i += 1<jupyter_output>a 10 John
b 20 Doe
c 30 True<jupyter_text>This is getting better but there's even a better way!<jupyter_code>shortest = min(len(collection1), len(collection2), len(collection3))
for i in range(shortest):
    print(collection1[i], collection2[i], collection3[i])<jupyter_output>a 10 John
b 20 Doe
c 30 True<jupyter_text>Do it like this!<jupyter_code>for first, second, third in zip(collection1, collection2, collection3):
    print(first, second, third)<jupyter_output>a 10 John
b <NAME>
c 30 True<jupyter_text>You can also create a dict out of two collections!<jupyter_code>my_dict = dict(zip(collection1, collection2))
print(my_dict)<jupyter_output>{'a': 10, 'b': 20, 'c': 30}<jupyter_text>`for - else` - Checking for a match in a collectionLet's say we want to verify a certain condition is met by at least one element in a collection. Let's consider the following relatively naive example where we want to verify that at least one item is "python" (case insensitive) in `data`. If not, we'll raise a ValueError.<jupyter_code>data = [1, 2, 3, 'This', 'is', 'just', 'a', 'random', 'Python', 'list']<jupyter_output><empty_output><jupyter_text>Don't do it like this<jupyter_code>found = False
for val in data:
    if str(val).lower() == 'python':
        found = True
        break
if not found:
    raise ValueError("Nope, couldn't find.")<jupyter_output><empty_output><jupyter_text>Do it like this!<jupyter_code>for val in data:
    if str(val).lower() == 'python':
        break
else:
    raise ValueError("Nope, couldn't find.")<jupyter_output><empty_output><jupyter_text>Functions<jupyter_code>def my_first_function():
    print('Hello world!')

print('type: {}'.format(my_first_function))
my_first_function()  # Calling a function
# whether given x is even or odd 
def evenOdd(x): 
    if (x % 2 == 0): 
        print("even")
    else: 
        print("odd")
evenOdd(2) 
evenOdd(3)<jupyter_output>even
odd<jupyter_text>Arguments<jupyter_code>def greet_us(name1, name2):
    print('Hello {} and {}!'.format(name1, name2))
greet_us('<NAME>', 'Superman')
# Function with return value
def strip_and_lowercase(original):
    modified = original.strip().lower()
    return modified
uggly_string = '  MixED CaSe '
pretty = strip_and_lowercase(uggly_string)
print('pretty: {}'.format(pretty))<jupyter_output>pretty: mixed case<jupyter_text>Keyword arguments<jupyter_code>def my_fancy_calculation(first, second, third):
    return first + second - third 

print(my_fancy_calculation(3, 2, 1))

print(my_fancy_calculation(first=3, second=2, third=1))

# With keyword arguments you can mix the order
print(my_fancy_calculation(third=1, first=3, second=2))

# You can mix arguments and keyword arguments but you have to start with arguments
print(my_fancy_calculation(3, third=1, second=2))<jupyter_output>4
4
4
4<jupyter_text>Default arguments<jupyter_code>def create_person_info(name, age, job=None, salary=300):
    info = {'name': name, 'age': age, 'salary': salary}
    
    # Add 'job' key only if it's provided as parameter
    if job:  
        info.update(dict(job=job))
        
    return info

person1 = create_person_info('<NAME>', 82)  # use default values for job and salary
person2 = create_person_info('<NAME>', 22, 'hacker', 10000)
print(person1)
print(person2)<jupyter_output>{'name': '<NAME>', 'age': 82, 'salary': 300}
{'name': '<NAME>', 'age': 22, 'salary': 10000, 'job': 'hacker'}<jupyter_text>**Don't use mutable objects as default arguments!**<jupyter_code>def append_if_multiple_of_five(number, magical_list=[]):
    if number % 5 == 0:
        magical_list.append(number)
    return magical_list

print(append_if_multiple_of_five(100))
print(append_if_multiple_of_five(105))
print(append_if_multiple_of_five(123))
print(append_if_multiple_of_five(123, []))
print(append_if_multiple_of_five(123))<jupyter_output>[100]
[100, 105]
[100, 105]
[]
[100, 105]<jupyter_text>Here's how you can achieve desired behavior:<jupyter_code>def append_if_multiple_of_five(number, magical_list=None):
    if not magical_list:
        magical_list = []
    if number % 5 == 0:
        magical_list.append(number)
    return magical_list

print(append_if_multiple_of_five(100))
print(append_if_multiple_of_five(105))
print(append_if_multiple_of_five(123))
print(append_if_multiple_of_five(123, []))
print(append_if_multiple_of_five(123))<jupyter_output>[100]
[105]
[]
[]
[]<jupyter_text>DocstringsStrings for documenting your functions, methods, modules and variables.<jupyter_code>def print_sum(val1, val2):
    """Function which prints the sum of given arguments."""
    print('sum: {}'.format(val1 + val2))

print(help(print_sum))
def calculate_sum(val1, val2):
    """This is a longer docstring defining also the args and the return value. 

    Args:
        val1: The first parameter.
        val2: The second parameter.

    Returns:
        The sum of val1 and val2.
        
    """
    return val1 + val2

print(help(calculate_sum))<jupyter_output>Help on function calculate_sum in module __main__:

calculate_sum(val1, val2)
    This is a longer docstring defining also the args and the return value. 
    
    Args:
        val1: The first parameter.
        val2: The second parameter.
    
    Returns:
        The sum of val1 and val2.

None<jupyter_text>[`pass`](https://docs.python.org/3/reference/simple_stmts.htmlthe-pass-statement) statement`pass` is a statement which does nothing when it's executed. It can be used e.g. a as placeholder to make the code syntatically correct while sketching the functions and/or classes of your application. For example, the following is valid Python.<jupyter_code>def my_function(some_argument):
    pass

def my_other_function():
    pass<jupyter_output><empty_output><jupyter_text>Quiz 1. Calculate the sum of dict values Calculate the sum of the values in `magic_dict` by taking only into account numeric values (hint: see [isinstance](https://docs.python.org/3/library/functions.htmlisinstance)).<jupyter_code>magic_dict = dict(val1=44, val2='secret value', val3=55.0, val4=1)
# Your implementation using for loop
sum_of_values = 
assert sum_of_values == 100<jupyter_output><empty_output><jupyter_text>Quiz 2. Create a list of strings based on a list of numbersThe rules:* If the number is a multiple of five and odd, the string should be `'five odd'`* If the number is a multiple of five and even, the string should be `'five even'`* If the number is odd, the string is `'odd'`* If the number is even, the string is `'even'`<jupyter_code>numbers = [1, 3, 4, 6, 81, 80, 100, 95]
#Your implementations
my_list = []

assert my_list == ['odd', 'odd', 'even', 'even', 'odd', 'five even', 'five even', 'five odd']<jupyter_output><empty_output><jupyter_text>Quiz 3. Fill the missing pieces to create `count_even_numbers` functionFill `____` pieces of the `count_even_numbers` implemention in order to pass the assertions. You can assume that `numbers` argument is a list of integers.<jupyter_code>____ count_even_numbers(numbers):
    count = 0
    for num in ____:
        if ____ % 2 == ____:
            count += ____
    _____ _____
assert count_even_numbers([1, 2, 3, 4, 5, 6]) == 3
assert count_even_numbers([1, 3, 5, 7]) == 0
assert count_even_numbers([-2, 2, -10, 8]) == 4<jupyter_output><empty_output><jupyter_text>Quiz 4. Searching for wanted peopleImplement `find_wanted_people` function which takes a list of names (strings) as argument. The function should return a list of names which are present both in `WANTED_PEOPLE` and in the name list given as argument to the function.<jupyter_code>WANTED_PEOPLE = ['<NAME>', '<NAME>', '<NAME>']
# Your implementation here

people_to_check1 = ['<NAME>', '<NAME>', '<NAME>', '<NAME>']
wanted1 = find_wanted_people(people_to_check1)
assert len(wanted1) == 2
assert '<NAME>' in wanted1
assert '<NAME>'in wanted1

people_to_check2 = ['<NAME>', '<NAME>', 'Zorro', 'Superman', '<NAME>']
wanted2 = find_wanted_people(people_to_check2)
assert wanted2 == []<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13458745874587458, 'fraction_numerical': 0.02957095709570957, 'mean_word_length': 5.286721991701245, 'pattern_counts': {'":': 0, '<': 198, '<?xml version=': 0, '>': 188, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '46', 'dir': 'jupyter-structured-clean-dedup', 'id': '631876', 'license': 'MIT', 'n_tokens_mistral': 5695, 'n_tokens_neox': 5332, 'n_words': 1541, 'path': 'tutorials/Ch3. Control Logics and Functions.ipynb', 'repo_name': 'ahnchive/python-workshop', 'size': '15226'}