08 Functions 2

image.png Երևան, լուսանկարի հղումը, Հեղինակ՝ Gor Davtyan

Open In Colab (ToDo)

Quote: ToDo

🎦 Տեսադասեր + լրացուցիչ ToDo

ToDo 1. Տեսություն 2025
2. Տեսություն 2023 (ToDo)
3. Գործնական 2025
4. Գործնական 2023 (ToDo)
5. Որոշ տնայինների լուծումներ (ToDo)

Google Forms ToDo

📚 Նյութը

Docstrings

help(sum)
Help on built-in function sum in module builtins:

sum(iterable, /, start=0)
    Return the sum of a 'start' value (default: 0) plus an iterable of numbers
    
    When the iterable is empty, return the start value.
    This function is intended specifically for use with numeric values and may
    reject non-numeric types.
https://pandas.pydata.org/docs/reference/api/pandas.Series.values.html

https://github.com/pandas-dev/pandas/blob/v2.0.0/pandas/core/series.py#L681-L721
def calculate_square_root(x): # documentation string -> docstring
    """Function calculates the square root of an input

    Note:
        If the input is a negative number, will return a warning message

    Args:
        x (float): Number to calculate the square root of

    Returns:
        sqrt_x (float or str): if applicable will return square root of the input
                               otherwise will return an error message

    Examples:
        >>>calculate_square_root(4)
        2
    """
    if x < 0:
        sqrt_x = 'նո նո նո, չի կարելի'
    else:
        sqrt_x = x**0.5

    return sqrt_x
calculate_square_root(1)
1.0
help(calculate_square_root)
Help on function calculate_square_root in module __main__:

calculate_square_root(x)
    Function calculates the square root of an input
    
    Note:
        If the input is a negative number, will return a warning message
    
    Args:
        x (float): Number to calculate the square root of
    
    Returns:
        sqrt_x (float or str): if applicable will return square root of the input
                               otherwise will return an error message
    
    Examples:
        >>>calculate_square_root(4)
        2
calculate_square_root.__doc__
'Function calculates the square root of an input\n\n    Note:\n        If the input is a negative number, will return a warning message\n\n    Args:\n        x (float): Number to calculate the square root of\n\n    Returns:\n        sqrt_x (float or str): if applicable will return square root of the input\n                               otherwise will return an error message\n\n    Examples:\n        >>>calculate_square_root(4)\n        2\n    '
type(calculate_square_root)
function
import random
random # hover on random
<module 'random' from 'c:\\Users\\hayk_\\.conda\\envs\\thesis\\lib\\random.py'>
print(help(random))

Կարանք նաև երբ օրինակներ ենք գրում, իրանց որպես թեստեր օգտագործենք Doctest գրադարանի միջոցով Վիդյո

Նյութեր 1. Ընդհանուր լավ նյութ, ու օրինակներ docstringների ֆորմատների link 2. Documentation ստեղծել Sphinx

Type hints (տեսակի հուշում)

Pythonը dynamically typed (փոփոխականը կարա տեսակը հանգիստ փոխի) լեզու ա, բայց երբեմն հստակ իմանում ենք թե ինչ տեսակի պետք ա լինի փոփոխականը, կամ թե օրինակ ինչ տեսակի արժեքա վերադարձնում ֆունկցին, լավ կլինի կարանանք հուշենք դա մարդակց որ մեր կոդի հետ աշխատալու են (նաև մեզ)

x: int = "աաաա"
a :str = 'պանիր'
print(x)
print(a)
աաաա
պանիր
# բայց դե կարանք հանգիստ խախտենք էլ
x: float = 'պանիր'
print(x)
պանիր

Ֆունկցիաններում

gner: dict[str, int] = {
    'chocolate': 130, # իրականում բայց պետքա լինի՝ "չունենք"
    'vanilla': 120
}

def ponchiki_calculator(qanak: int, tesak: str, pudrayov: bool) -> float: # եթե բան չվերադարձներ կգրեինք -> None
    """Function calculates how much eating ponchiks will cost us

    Args:
        qanak (int): number of ponchiks we are going to buy and then eat, am nyam nyam
        tesak (str): either chocolate or vanilla
        pudrayov (bool): of course pudrayov, I have to spill it all over my shirt

    Returns:
        gin (float): how much this paradise for stomach will cost
    """
    gin = qanak * gner[tesak]
    
    return gin

ponchiki_calculator(3, 'vanilla', True)
'panir'
def count_number_of_occurances(lst: list, element):
    """Function counts how many times a given element appears in the given list

    Args:
        ...
        ալարում եմ ես գրեմ, դուք բայց մի ալարեք :)
    """
    return lst.count(element) # wait to see the suggestions after adding the hint

Նյութեր

  1. Documentation
  2. կարճ ու լավ վիդյո
  3. երկար ու լավ վիդյո (սա խորհուրդ կտամ նայել էս երեք ռեսուրների մեջից)
  4. Pydantic, mypy

Scopes (LEGB rule)

Local Enclosing Global Builtin

Լավ վիդեո

ValueError
print
<function print>
# L -> E -> G -> B
heghuk = 'ջուր' # global

def tun():
    heghuk = 'չայ' # local
    print(heghuk)

tun()
print(heghuk)
չայ
ջուր
# ֆունկցիաներից դուրս ամենինչ globalա, ու բոլորը տեղյալ են էդ փոփոխականից, ֆունկցիայի ներսը ոնց-որ առանձնացված տուն լինի

a = 'global'

def tun():
    a = 'local'
    print(a)

tun()
print(a)
local
global
# ֆունկցիաներից դուրս ամենինչ globalա, ու բոլորը տեղյալ են էդ փոփոխականից, ֆունկցիայի ներսը ոնց-որ առանձնացված տուն լինի
a = 'panir'

def tun():
    # global a
    a = 'local'
    print(a)

tun()
print(a)
  Input In [30]
    global a
    ^
SyntaxError: name 'a' is parameter and global
# L E G B
a = 'global'
def tun():
    a = 'enclosed'
    def senyak():
        a = 'local'
        print("senyak",a)

    senyak()
    print("tun", a)

tun()
print("durs", a)
senyak global
tun global
durs global
a = 'global'
def tun():
    a = 'enclosed'
    def senyak():
        # nonlocal a
        a = 'local'
        print(a)

    senyak()
    print(a)

tun()
print(a)
local
enclosed
global
import builtins

print(dir(builtins))
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EncodingWarning', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'aiter', 'all', 'anext', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'enumerate', 'eval', 'exec', 'execfile', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed', 'round', 'runfile', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

Mutuble objects as arguments

regular arguments

def avelacru_element(lst):
    lst.append('panir')
    return lst
lst_1 = list(range(10))
print(lst_1)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
lst_avelacrac = avelacru_element(lst_1)
print(lst_avelacrac)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir']
print(lst_1)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir']
print(lst_avelacrac)
print(lst_1)
# վայ
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir']
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir']
print(id(lst_avelacrac))
print(id(lst_1))
2321052600704
2321052600704
def avelacru_element():
    print(id(lst))
    lst.append('panir')
    return lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir']
lst_avelacrac = avelacru_element(lst_1)
print(lst_avelacrac)
2321052600704
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir', 'panir']
print(lst_1)
print(lst_1.copy())

print(id(lst_1))
print(id(lst_1.copy()))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir', 'panir']
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir', 'panir']
2321052600704
2321074452096
lst_1 = list(range(10))

lst_avelacrac_okay_klini_senc = avelacru_element(lst_1.copy())

print(lst_1.copy())
print(lst_avelacrac_okay_klini_senc)
print(lst_1)
2321052166464
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'panir']
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(id(lst_1.copy()))
print(id(lst_avelacrac_okay_klini_senc))
132371578933952
132371593482112

Mutable objects as default arguments

def create_album(album_name, songs=[]):
    return {'artist_name': album_name,
            'songs': songs}

# print(create_album("Կոմիտաս"))
# 
print(create_album("Կոմիտաս", ["Գարուն ա"]))
{'artist_name': 'Կոմիտաս', 'songs': ['Գարուն ա']}
def create_album(album_name: str, songs=[]):
    print(id(songs))
    return {'album_name': album_name,
            'songs': songs}

def add_song(album: dict, song: str):
    print(song)
    album['songs'].append(song)
    return album

pf = create_album('Pink Floyd')
rh = create_album('Radiohead')

print(f"{pf =}")
print(f"{rh = }")
# print()

print(add_song(pf, 'Breathe'))
print(add_song(rh, 'Reckoner'))
2321052170240
2321052170240
pf ={'album_name': 'Pink Floyd', 'songs': []}
rh = {'album_name': 'Radiohead', 'songs': []}
Breathe
{'album_name': 'Pink Floyd', 'songs': ['Breathe']}
Reckoner
{'album_name': 'Radiohead', 'songs': ['Breathe', 'Reckoner']}
հիշողությոն պահել create_album,
1233 -> album_name
1234 -> songs, value -> []
pf = {"artist_name": "Pink Floyd", "songs": են ինչ պահված ա 1234} # []
rf = {"artist_name": "Radiohead", "songs": են ինչ պահված ա 1234} # []

print(add_song(pf, 'Breathe'))
# 1234 [] -> ["Breathe"]
print(add_song(rh, 'Reckoner'))
# 1.
# հիշողությոն պահել create_album,
# 1233 -> album_name
# 1234 -> songs, value -> []

# pf = {"Pink Floyd", "songs": են ինչ պահված ա 1234}
# rf = {"Radiohead", "songs": են ինչ պահված ա 1234}

# 1234 [] -> ["Breathe"]
# 1234 ["Breathe"] -> ["Breathe", "Reckoner"]

կարանք ուղղենք գրելով

def create_album(album_name, songs=None):
    if songs is None: # ուռաաա, հազիվ is-ը օգտագործեցինք
        songs = []
    print(id(songs))
    return {'album_name': album_name,
            'songs': songs}

def add_song(album, song):
    # print(song)
    album['songs'].append(song)
    return album

pf = create_album('Pink Floyd')
rh = create_album('Radiohead')
# pf = {'album_name': 'Pink Floyd', 'songs': []}
# rh = {'album_name': 'Radiohead', 'songs': []}

print(pf)
print(rh)
print()

print(add_song(pf, 'Breath'))
print(add_song(rh, 'Reckoner'))
2321051439168
2321047237952
{'album_name': 'Pink Floyd', 'songs': []}
{'album_name': 'Radiohead', 'songs': []}

{'album_name': 'Pink Floyd', 'songs': ['Breath']}
{'album_name': 'Radiohead', 'songs': ['Reckoner']}

Lambdas (anonymous functions) (ոտի վրա ֆունկցիաներ)

Syntax-ը

lambda արգումենտներ: ինչ-որ բան որ պետքա վերադարձնենք
def xoranard(x):
    return x**3

print(xoranard(4))
64
xoranard = lambda x: x**3

print(xoranard(4))
64

Մի քանի արգումենտով lambda

def bardzarcru_astican(x, y):
    return x**y

print(bardzarcru_astican(2, 4))

bardzarcru_astican = lambda x, y: x**y
print(bardzarcru_astican(2,4))
16
16

default argumentով lambda

def bardzarcru_astican(x, y=3):
    return x**y

print(bardzarcru_astican(2))
print(bardzarcru_astican(2, 4))

bardzarcru_astican = lambda x, y=3: x**y
print(bardzarcru_astican(2))
print(bardzarcru_astican(2, 4))
8
16
8
16

մի քանի բան վերադարձնել

def bardzarcru_astican(x, y=3):
    return x**y, x

print(bardzarcru_astican(2, 3))
(8, 2)
bardzarcru_astican = lambda x, y: x**y, x
print(bardzarcru_astican(2, 3))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [77], in <cell line: 2>()
      1 bardzarcru_astican = lambda x, y: x**y, x
----> 2 print(bardzarcru_astican(2, 3))

TypeError: 'tuple' object is not callable
bardzarcru_astican = lambda x, y: (x**y, x, y)
print(bardzarcru_astican(2, 3))
(8, 2, 3)

Higher order functions (բարձրակարգ ֆունկցիաներ)

կալդո ֆունկցիաներ (զուտ են ռեկլամն էի հիշել “բարձրակարգ” բառի պատճառով, լուրջ անուն չի)

# ֆունկցիա որը մուտքում ընդունումա ֆունկցիա
def ispanakan(anun):
    return f"Բարև {anun}իտո"

# ispanakan = lambda anun: f"Բարև {anun}իտո"

def vracakan(anun):
    return f"Բարև {anun}իձե"
anun = 'Հայկ'
print(ispanakan(anun))
print(vracakan(anun))
Բարև Հայկիտո
Բարև Հայկիձե
def barevel(anun, style):
    if style == "vracakan":
        func = vracakan
        # return vracakan(anun)
    elif style == "ispanakan":
        func = ispanakan
        # return ispanakan(anun)
    return func(anun)    
barevel("Hayk", "ispanakan")
'Բարև Haykիտո'
def barevel(anun, specific_barev_func):
    return specific_barev_func(anun) # vracakan(anun)
anun = 'Հայկ'
print(type(ispanakan))
print(barevel(anun, ispanakan))

print(barevel(anun, vracakan))
<class 'function'>
Բարև Հայկիտո
Բարև Հայկիձե

քանի որ եսիմինչ բան չենք անում, չարժի առանձին ֆունկցիա սարքենք ինչ-որ տեղ անուն դնենք իրան, հետո կանչենք
Ավելի լավա ուղղակի ոտի վրա արագ սարքենք իրան, հետո մոռանանք որ գոյություն ունի

print(barevel(anun, lambda anun: f"Բարև {anun}իսիմո"))
print(barevel(anun, lambda anun: f"Բարև {anun} ջան")) # одноразовый
Բարև Հայկիսիմո
Բարև Հայկ ջան

Մեզ հայտնի ֆունկցիաներից

tver = [1, 11, 509, 32, 231, 1132, 111]

print(max(tver))
1
help(max)
Help on built-in function max in module builtins:

max(...)
    max(iterable, *[, default=obj, key=func]) -> value
    max(arg1, arg2, *args, *[, key=func]) -> value
    
    With a single iterable argument, return its biggest item. The
    default keyword-only argument specifies an object to return if
    the provided iterable is empty.
    With two or more arguments, return the largest argument.
print(max(tver, key=lambda x: str(x).count('1'))) # նենց անենք որ ըստ մեկերի քանակի սորտավորի
111
tveri_zueger = ((1,10), (2,24), (3, 2), (4, 2))
print(max(tveri_zueger))

# x = (1, 10)
# lambda x: x[0] * x[1]
(4, 2)
print(max(tveri_zueger, key=lambda x: x[0]*x[1]))
(2, 24)
def count_ones(x):
    return str(x).count('1')
print(tver)

tver.sort(key=count_ones)
print(tver)
[1, 11, 509, 32, 231, 1132, 111]
[509, 32, 1, 231, 11, 1132, 111]

Map, filter, reduce

Map

map(ինչ-որ ֆունկցիա, հավաքածու)
  File "<ipython-input-58-9aa394208246>", line 1
    map(ինչ-որ ֆունկցիա, հավաքածու)
        ^
SyntaxError: invalid syntax. Perhaps you forgot a comma?
range(1,4)
range(1, 4)
map(lambda x: x**2, [5,0,9])
<map at 0x21c69723550>
list(map(lambda x: x**2, [5,0,9]))
[25, 0, 81]
def qarakusi(x):
    return x**2

list(map(qarakusi, [5,0,9]))
[25, 0, 81]
[qarakusi(i) for i in [5, 0, 9]]
[25, 0, 81]
list(map(bool, [1, '', 3, -1, 0]))
[True, False, True, True, False]

# "1 3 4"
# [1, 3, 4]
[int(i) for i in input().split()]
list(map(int, input().split()))
[1, 3, 4]

Ինչի՞ ուղղակի list comprehension չօգտագործենք https://stackoverflow.com/questions/1247486/list-comprehension-vs-map

Filter

[i for i in [5, 0, 9] if i % 2 == 0]
[0]
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))

# for i in numbers:
#     if func(i):
#         a.append(i)
[2, 4, 6]
print(filter(lambda x: x % 2 == 0, numbers))
<filter object at 0x78513db7f790>
[i for i in numbers if i % 2 == 0]
[2, 4, 6]
# ստանալ բառերը որոնք մեծատառով են սկսվում
barer = ['Պանիր', "բարև", "պոնչիկ"]
list(filter(lambda x: x[0].isupper(), barer))
['Պանիր']
[x for x in barer if x[0].isupper()]
['Պանիր']

Reduce

from functools import reduce

numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x*y, numbers)
print(product)
120
1*2 = 2
[1, 2, 3, 4, 5] -> [2, 3, 4, 5]

2*3 = 6
[2, 3, 4, 5] -> [6, 4, 5]

6 * 4 = 24
[6, 4, 5] -> [24, 5]

24*5 = 120

🛠️ Գործնական (ToDo)

Գաղտնաբառի ստեղծում

Գրել ֆունկցիա որը ստեղծում ա տրված երկարության (default 10), ու բարդության (easy, medium, harc) գաղտնաբառ:

Հեշտ գաղտնաբառը մենակ թվեր ա պարունակում, միջինը նաև տառեր իսկ դժվարը սիմվոլներ էլ։

import string
import random

numbers = string.digits
letters = string.ascii_letters
symbols = ")(*&^%$$%^&*())(*&^%$%^&*)"

def generate_password(difficulty: str, password_length: str=10) -> str:
    """Returns of a ....
    
    Args:
        difficulty (str): one of ["easy", "medium"] ...
        
    Return:
    ...
    """
    char_option = {
        "easy": numbers, 
        "medium": numbers + letters,
        "hard": numbers + letters + symbols
    }
    
    if difficulty not in char_option:
        print("Սխալ մուտք")
        return None
    
    chars = char_option[difficulty]
        
    password = ""
    for _ in range(password_length):
        password += random.choice(chars)
        
    return password + chars


generate_password("medum")


"".join(random.sample(letters, 5))
Սխալ մուտք
'ISyTG'

Կոպեկ քցել

(Կոդը մաքուր չի)

NUM_ITER = 10_000

def flip_coin_n_times(n: int, return_percentage: bool = True) -> int:
    """Func..

    Args:
        n (int): _description_

    Returns:
        int: _description_
    """
    flip_coin = lambda : random.choice([0, 1])
    
    results = []
    for _ in range(n):
        results.append(flip_coin())
    
    num_1s = sum(results)
    
    if return_percentage:
        return num_1s / n
    
    return num_1s

def get_distribution(num_iter: int = NUM_ITER, return_percentage: bool = True):
    count_dict = {}

    for _ in range(num_iter):
        num_1s = flip_coin_n_times(5, False)
        
        if num_1s not in count_dict:
            count_dict[num_1s] = 1
        else:
            count_dict[num_1s] += 1
          
    
    items_sorted = sorted(count_dict.items(), key=lambda x: x[1])
    count_dict = dict(items_sorted)
    print(count_dict)
    
    if return_percentage:
        def get_perc(x):
            return (x, count_dict[x] / num_iter * 100)
        
        count_dict = dict(map(get_perc, count_dict))

    return count_dict
NUM_ITER = 1_000

percentages = []
for i in range(1, NUM_ITER+1):
    percentages.append(flip_coin_n_times(i))
# import matplotlib.pyplot as plt

# plt.plot(percentages)
import plotly.express as px 

px.line(x=range(1, NUM_ITER+1), y=percentages)
# add horizontal line at 50%

Bernuli distribution 
Unable to display output for mime type(s): application/vnd.plotly.v1+json
get_distribution(100_000)
{5: 3033, 0: 3152, 1: 15405, 4: 15873, 2: 31103, 3: 31434}
{5: 3.033,
 0: 3.152,
 1: 15.405,
 4: 15.873000000000001,
 2: 31.102999999999998,
 3: 31.434}

🏡Տնային

Հիմնական տնային

  1. Profound բաժին 28 (Lambda և բարձր կարգի ֆունկցիաներ) - լրիվ
  2. Կարող եք նաև անել տնայիններ Profound-ի միջին մակարդակի դասընթացի համապատասխան բաժնից

Լուծումներ

🎲 8

Flag Counter