Рубрики
Без рубрики

Arguments Opciones en python: ¿por Qué Нет сена que usar listas?

Arguments Opciones en python: ¿por Qué Нет сена que usar listas? Imaginemos Esta Función … Теги с Python, Listas, добавлением, Metable.

Imaginemos Esta Función (Que, Ustedes Dirán, ES Bastante Tonta) Que Agroga Un Elemento A UNA Lista Eniacy, Ambos ArgageS de La Función. Перо Адемас, Queremos que POR DEFECTO , La Lista Enibied Esté Vacía, Así Que Pasarle Sólo Un Элемент A La Función Implique Devolver Una Lista Con únicape Elemento:

def agregar_a_lista(elemento, inicial=[]):
    inicial.append(elemento)
    return inicial

Así que vamos usar nuestra humilde, Перо корректирует función!

>>> una_lista_larga = agregar_a_lista(5, [2, 3])
>>> print(una_lista_larga)
[2, 3, 5]
>>> una_lista_corta = agregar_a_lista(5)
>>> print(una_lista_corta)
[5]
>>> otra_lista_corta = agregar_a_lista(7)

Todo Parece Andar Bien, y otra_lista_corta Debería Dar [7] Отказ Sin Embargo …

>>> print(otra_lista_corta)
[5, 7]

Qué!? ¿ Qué Pasó? ¿ SE “Acuerda” de que Antes Le Había Agregado ООН 5?

ESTA ES La Primera Pregunta que nos va ayudar entender lo que está suciciendo. Para Eso, Vamos Usar: 1. Эль Методо __defaults__ que nos правда ver los valores por defecto de una función; Y 2. Эль встроенный ID que nos devualve una резингения única a cada objeto (es decir, dos objetos tienen el mismo ID Si Y Sólo Si Si Son El Mismo Objeto). Ahora Comenzamos de Cero Un

def agregar_a_lista(elemento, inicial=[]):
    inicial.append(elemento)
    return inicial


valores_por_defecto = agregar_a_lista.__defaults__
identidades = [id(valor) for valor in agregar_a_lista.__defaults__]
print(f"Valores por defecto: {valores_por_defecto}")
print(f"Identidades: {identidades}")

print("Ejecutando una_lista = agregar_a_lista(5)")
una_lista = agregar_a_lista(5)
print(f"Resultado: {una_lista}")

valores_por_defecto = agregar_a_lista.__defaults__
identidades = [id(valor) for valor in agregar_a_lista.__defaults__]
print(f"Valores por defecto: {valores_por_defecto}")
print(f"Identidades: {identidades}")

print("Ejecutando otra_lista = agregar_a_lista(7)")
otra_lista = agregar_a_lista(7)
print(f"Resultado: {otra_lista}")

Cuando Ejecutamos ESE Script, Obtenemos:

Valores por defecto: ([],)
Identidades: [140611099623168]
Ejecutando una_lista = agregar_a_lista(5)
Resultado: [5]
Valores por defecto: ([5],)
Identidades: [140611099623168]
Ejecutando otra_lista = agregar_a_lista(7)
Resultado: [5, 7]

Efectivamente, La Función SE acuerda de que legregamos un 5, Перо Порка El objeto es el mismo (fíjense que las addicidades concuerdan). La Primera Vez Que Ejecutamos La Función, Modificamos Su Valor; Обучению, La Segunda Vez Que Lo Usamos, LO Tomamos Con El Valor Modififado. La Primera Endución Sería: No Modifiquemos Los Valores Por Defecto Doctro de Una Función de Python O, Más General Y Más Seguro, NO USEMOS OBJETOS Turable Como Valores POR DEFECTO EN UNA FUNCION .

Буэно, Перо ¿Qué Está Pasando?

COMO PUEDEN VER, EL __defaults__ de la función. ya tiene un valor incluso antes de que la función se llame por primera vez. ESTO SE DEBE que los valores por defecto de la función se calculan cuando la función se define, no cuando se llama. Este Comportamiento SE LLAMA Ранний связывающий , Y SU CONTRAPARTE ( Поздние Обязательные ) Calcula Los Valores Por Defecto En Cada Ejecución.

PodeMos Poner Ezo A The Prueba Bastante Fácillemente: ¿Qué Pasa Si Entre llamada y lllamada volvemos a difrish la función tal como estaba?

def agregar_a_lista(elemento, inicial=[]):
    inicial.append(elemento)
    return inicial


valores_por_defecto = agregar_a_lista.__defaults__
identidades = [id(valor) for valor in agregar_a_lista.__defaults__]
print(f"Valores por defecto: {valores_por_defecto}")
print(f"Identidades: {identidades}")

print("Ejecutando una_lista = agregar_a_lista(5)")
una_lista = agregar_a_lista(5)
print(f"Resultado: {una_lista}")


def agregar_a_lista(elemento, inicial=[]):
    inicial.append(elemento)
    return inicial

valores_por_defecto = agregar_a_lista.__defaults__
identidades = [id(valor) for valor in agregar_a_lista.__defaults__]
print(f"Valores por defecto: {valores_por_defecto}")
print(f"Identidades: {identidades}")

print("Ejecutando otra_lista = agregar_a_lista(7)")
otra_lista = agregar_a_lista(7)
print(f"Resultado: {otra_lista}")

Al Ejecutar Este Script Obtenemos El Butterado Esperado:

Valores por defecto: ([],)
Identidades: [140438619595200]
Ejecutando una_lista = agregar_a_lista(5)
Resultado: [5]
Valores por defecto: ([],)
Identidades: [140438619595840]
Ejecutando otra_lista = agregar_a_lista(7)
Resultado: [7]

Нет Sólo Los Valores Por Defecto SE Vuelven Калькулярный, Sino Que Además Fíjense Que Tienen DOS отождествляет Distintas; Es Decir, сын Dos objetos Dantintos Отказ

ОК, Энтенддо. Перо ¿Cómo Lo Resualvo?

La Solución Cuanto No Qeremos Este Comportamiento (Que es es la mayoría de los casos) es utilizar lo que se llama un objeto Centinela , Para lo que hethermentree SE США Нет :

def agregar_a_lista_bien(elemento, inicial=None):
    if inicial is None:
        inicial = []
    inicial.append(elemento)
    return inicial

Fíjense la diferencia cuando usamos esta función, сравнение преданный спереди

una_lista = agregar_a_lista(5)
otra_lista = agregar_a_lista(7)
print(f"Identidades: {id(una_lista)}, {id(otra_lista)}")

una_lista_bien = agregar_a_lista_bien(5)
otra_lista_bien = agregar_a_lista_bien(7)
print(f"Identidades: {id(una_lista_bien)}, {id(otra_lista_bien)}")
Identidades: 139893270457152, 139893270457152
Identidades: 139893271721280, 139893270011200

RU agregar_a_lista Ambas Listas Son El Mismo Objeto (Sus Initedides Son Iguales), MientArs Que en agregar_a_lista_bien SE CREAN DOS LISTAS DINTINTAS: [5] y [7] . La Diferencia фундаментальный ES QUE EL USO DEL VALOR CENTINELA Нет nos permitió diforiar Исконированный Денго de la función y, así, es искренний = [] подавать CADA VEZ QUE LLAMAMOS LA FUNCION y Нет Sólo Al Commitio Como Antes.

Algunas Aclaraciones Extra (Quizás un Poco Más Avanzadas)

Sobre Los Centinelas

Нет quiero Ahondar Mucho en Este Tema, Перо сена Veces que, en la función que usamos, эль аргумент por defecto podría ser Нет Отказ EN ESE CASO, NUESTRA TÉCNICA DEL CENTINELA Interfiere Con Ese Valor, Privque Lo Meader Simplemente El RindaDor de “Acá va una lista vacía”. ¿La Solución? Usar Centinelas únicos. La Exprachación detallada Quedará Para Más Adelante, Перо La Idea Es Algo Así:

_CENTINELA = object()

def agregar_a_lista_bien_unico(elemento, inicial=_CENTINELA):
    if inicial is _CENTINELA:
        inicial = []
    inicial.append(elemento)
    return inicial

Собре Эль есть

Ла ключевое слово это EN Python ES PARA CHEQUEAR INDIEDDADES, без валов. Es Decir, А это Б. VA DAR Истинный si y sólo si ID (A) (B) ; ES DECIR, SI Y SOLO SI A y B Сын Эль Миссо Объето. ¿Por Qué Compasmos против это y Нет con == ? Porterque en python EL SHARTADOR ( == ) SE PUEDE DEASEIR PARA CADA CLASE Través del Método __eq__ ; Обучению, Si Crowsos Una Clase Que Parece Una Lista, Перо Devualve Siempre Правда RU SPARACIONES:

class MiLista(list):
    def __eq__(self, other):
        return True

подавать:

>>> lista_prueba = MiLista([1, 2, 3, 4])
>>> lista_prueba == None
True
>>> lista_prueba is None
False

Así que nunca, Nunca , Nunca Сравнить валов Centinela Con ==. . Lo que me lleva al tercer y último punto:

Сравнительные каравали

Python Tiene Conversions Dimícitas de Valores Booleanos ( True / Ложь , Ба). POR EJEMPLO, LAS Listas Vacías, Нет y los números iguales a 0 se evalúan como Ложь Отказ Así que, como Нет SE EVALúA A Ложь Uno Podría Tentarse Escribir:

...
if not inicial:
    inicial = []

en vez del chekeoo Ишенский это не Отказ

ESTO, Además del Flancea de Fromar Con == SE Le Suma Que Quizás Кермеос Pasar Una lista Vacía Y Modififarla (Con un Добавить ), Перо ESTE Código Nos Fuerza Crage Una Lista Nueva Исконированный Дендо дель Область de la función.

Entudiar Cómo Funciona El Lenguaje Nos Puede Ayudar a que comportamientos que Antes Nos Parecían Raros SE Vuelvan Más Intuitivos. EN ESTE CASO EN в частности:

  1. Нет упретиков Сообщения COMO Valores POR DEFECTO EN PYTHON.
  2. Нет Casi Siempre Es un Buen Valor Centinela
  3. CuAndo No Sirve Como Centinela, Hay que arrremargarse un poco; Перо Ла-Логика Е.С. Л.А. МИМСА.
  4. Los Centinelas Siempre SE Chquea Con это , нет кон ==. .

Оригинал: “https://dev.to/ninjaia/argumentos-opcionales-en-python-por-que-no-hay-que-usar-listas-3hok”