MC-102 — Aula 12
2a passagem por funçoes

Parametros default

é possivel definir funções que terão parametros que não precissam ser passados na chamada da função, e neste caso eles terão valores default espeficicados

def soma(a, b=1):
    return a+b
print(soma(4,5))
print(soma(4))

É pouco prvavel que os programa gerado pelo co-pilot usem parametros default, mas se voce quiser ler a especificação de uma função criada numa biblioteca, quase certamente ela terá parametros default

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html

Na chamada dessas funções com parametros, voce pode passar os parametros default usando o nome deles, em qualquer ordem.

def soma1(a, b=0, c=1.0 ):
    return c*a+b
print(soma(4,5))       ==> b=5 c=1
print(soma(4,b=4,c=2))
print(soma(4,c=9, b=0))

outro tipos de parametros *args e **kwargs

Uma funçao pode receber um numero qualquer de parametros quando for chamada. (tipo o print)

Na declaração, use o parametro *args para indicar que havera um numero quaquer de argmentos. Na chamada dessa função, toto esses parametros serao coletados numa lista chamada args

def soma2(a, *args):
    s = a
    for i in args:
        s += i
    return s
print(soma2(4))
print(soma2(1,2,3,4,5,6))

**kwargs

uma funçao pode receber um numero qualquer de parametros passados com o nome

func1(a=1, b="pare", velocidade=67.8)

Na declaracao use o parametro **kwargs para indicar que haverá nomes e valores passados como argumentos (alem dos ja definidos). Na chamada da função esses pares nome/valor passados serao coletados num dicionário.

https://requests.readthedocs.io/en/latest/api/

Funcoes sao “valores”/objetos tambem

O “programa”/corpo da função é um tipo de dado do Python, que pode ser atribuido a outras variáveis

def func1(a,b):
    c = 2*a-b
    return c
    
func(5,4)   -> 6

qq = func1

qq(5,4)    -> 6

Funçoes como parametros de outras funções

Atribuir uma função a outra variavel não é muito util. Mas passar uma função como parametro de outra função é bem util.

lembrando

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

sorted tem outros 2 argumentos

>>> sorted([5, 2, 3, 1, 4], reverse=True)
[5, 4, 3, 2, 1]

Ordenado uma lista de tuplas.

>>> sorted([("Joao",4), ("Pedro", 2), ("Maria", 3)])
[('Joao', 4), ('Maria', 3), ('Pedro', 2)]

sorted ordena pelo operador < e

>>> ("Joao",4) <  ("Pedro", 2)
True

mas eu quero ordernar pelo valor numérico. O argumento key é uma função que sera aplicada nos elementos da lista e a ordenação será pelos valores retornados pela função key

def segundo(x):
    return x[1]
    
sorted([("Joao",4), ("Pedro", 2), ("Maria", 3)], key=segundo)

lambda

mas criar uma função só para acessar o 2o elemento de uma tupla é chato.

Funçoes anonimas - só o corpo da funcão sem dar nome para ela

`sordted([('Pedro', 2), ('Maria', 3), ('Joao', 4)], key=lambda x: x[1])

pacote operator

operator tem a função itemgetter que dado um inteiro retorna uma funçao que espera uma lista e retorna o elemento da lista com o indice igual ao inteiro

from operator import itemgetter

x = [10,20,30,40,50]
itemgetter(2)(x) 
x[2]
sorted([('Pedro', 2), ('Maria', 3), ('Joao', 4)], key=itemgetter(1))

Um programa que a gente ja viu

def plot_frequency(string):
    string = string.lower()
    string = string.translate(str.maketrans('', '', string.punctuation + string.whitespace))
    letter_counts = Counter(string)
    sorted_letter_counts = sorted(letter_counts.items(), key=lambda x: x[1], reverse=True)
    letters = [item[0] for item in sorted_letter_counts]
    counts = [item[1] for item in sorted_letter_counts]
    # Plotando o gráfico de barras
    plt.bar(letters, counts)
    plt.xlabel('Letras')
    plt.ylabel('Frequência')
    plt.title('Frequência de Letras (Ordenado)')
    plt.show()

Variaveis locais e globais

Nós vimos que vc pode mexer nos valores dos parametros e em variavieis na função que isso nao causa problemas fora da função

def func2(a,b)
    a=2*a
    b=b-1
    x=a+b
    return x
    
x=-44
a=10
b=20
print(func2(a,b))
print(a)
print(b)
print(x)

a variavel x (e a e b) são variaveis locais da função func2

Uma função pode usar mas nao modificar uma variavel de fora da função. Essas são chamadas variáveis globais

z = 99
def func3(a):
    a = a+z
    print(z)
    return a
    
b=1
func3(b)
print(b)
print(z)

Se eu tentar modificar o z vai dar problema. Por exemplo:

z = 99
def func3(a):
    z = a+z
    print(z)
    return z
    
b=1
func3(b)
print(b)
print(z)

O erro é :

UnboundLocalError: local variable 'z' referenced before assignment

porque vc tem um comando para modificar z, e isso torna ela local. Como variavel local, ela ainda não tem valor no comando z = a+z

Modificando variaveis globais

é possivel modificar variaveis globais usando a declaração global

z = 99
def func4(a):
    global z
    z = a+z
    return z

func4(10)
print(z)
    

Agora z é a variavel global e o comando z = a+z tanto usa como modifica ela.