Creando nuevos objetos con clase

PythonPythonBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Esta sección introduce la declaración de clase y la idea de crear nuevos objetos.

Programación Orientada a Objetos (POO)

Una técnica de programación en la que el código se organiza como una colección de objetos.

Un objeto consta de:

  • Datos. Atributos
  • Comportamiento. Métodos que son funciones aplicadas al objeto.

Ya has estado usando algo de POO durante este curso.

Por ejemplo, manipular una lista.

>>> nums = [1, 2, 3]
>>> nums.append(4)      ## Método
>>> nums.insert(1,10)   ## Método
>>> nums
[1, 10, 2, 3, 4]        ## Datos
>>>

nums es una instancia de una lista.

Los métodos (append() e insert()) están adjuntos a la instancia (nums).

La declaración class

Utiliza la declaración class para definir un nuevo objeto.

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.health = 100

    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def damage(self, pts):
        self.health -= pts

En resumen, una clase es un conjunto de funciones que realizan diversas operaciones sobre los llamados instancias.

Instancias

Las instancias son los verdaderos objetos que manipulas en tu programa.

Se crean llamando a la clase como si fuera una función.

>>> a = Player(2, 3)
>>> b = Player(10, 20)
>>>

a y b son instancias de Player.

Enfatiza: La declaración de clase es solo una definición (no hace nada por sí misma). Similar a la definición de una función.

Datos de instancia

Cada instancia tiene sus propios datos locales.

>>> a.x
2
>>> b.x
10

Estos datos se inicializan por el método __init__().

class Player:
    def __init__(self, x, y):
        ## Cualquier valor almacenado en `self` es datos de instancia
        self.x = x
        self.y = y
        self.health = 100

No hay restricciones sobre el número total o el tipo de atributos almacenados.

Métodos de instancia

Los métodos de instancia son funciones aplicadas a las instancias de un objeto.

class Player:
  ...
    ## `move` es un método
    def move(self, dx, dy):
        self.x += dx
        self.y += dy

El objeto mismo siempre se pasa como primer argumento.

>>> a.move(1, 2)

## hace coincidir `a` con `self`
## hace coincidir `1` con `dx`
## hace coincidir `2` con `dy`
def move(self, dx, dy):

Por convención, la instancia se llama self. Sin embargo, el nombre real utilizado no es importante. El objeto siempre se pasa como primer argumento. Es simplemente un estilo de programación de Python llamar a este argumento self.

Alcance de clase

Las clases no definen un ámbito de nombres.

class Player:
 ...
    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def left(self, amt):
        move(-amt, 0)       ## NO. Llama a una función global `move`
        self.move(-amt, 0)  ## SI. Llama al método `move` de arriba.

Si quieres operar sobre una instancia, siempre la referenciar explícitamente (por ejemplo, self).

A partir de este conjunto de ejercicios, comenzamos a realizar una serie de cambios en el código existente de secciones anteriores. Es fundamental que tengas una versión funcional del Ejercicio 3.18 para comenzar. Si no la tienes, por favor trabaja a partir del código de solución que se encuentra en el directorio Solutions/3_18. Está bien copiarlo.

Ejercicio 4.1: Objetos como estructuras de datos

En las secciones 2 y 3, trabajamos con datos representados como tuplas y diccionarios. Por ejemplo, una posesión de acciones podría representarse como una tupla así:

s = ('GOOG',100,490.10)

o como un diccionario así:

s = { 'name'   : 'GOOG',
    'shares' : 100,
     'price'  : 490.10
}

Incluso puedes escribir funciones para manipular estos datos. Por ejemplo:

def cost(s):
    return s['shares'] * s['price']

Sin embargo, a medida que tu programa crece, es posible que desees crear una mejor sensación de organización. Por lo tanto, otra forma de representar datos sería definir una clase. Crea un archivo llamado stock.py y define una clase Stock que represente una sola posesión de acciones. Haz que las instancias de Stock tengan atributos name, shares y price. Por ejemplo:

>>> import stock
>>> a = stock.Stock('GOOG',100,490.10)
>>> a.name
'GOOG'
>>> a.shares
100
>>> a.price
490.1
>>>

Crea algunos más objetos Stock y manipúlalos. Por ejemplo:

>>> b = stock.Stock('AAPL', 50, 122.34)
>>> c = stock.Stock('IBM', 75, 91.75)
>>> b.shares * b.price
6117.0
>>> c.shares * c.price
6881.25
>>> stocks = [a, b, c]
>>> stocks
[<stock.Stock object at 0x37d0b0>, <stock.Stock object at 0x37d110>, <stock.Stock object at 0x37d050>]
>>> for s in stocks:
     print(f'{s.name:>10s} {s.shares:>10d} {s.price:>10.2f}')

... mira la salida...
>>>

Una cosa que hay que enfatizar aquí es que la clase Stock actúa como una fábrica para crear instancias de objetos. Básicamente, la llamas como si fuera una función y te crea un nuevo objeto. Además, hay que enfatizar que cada objeto es distinto: cada uno tiene sus propios datos que son separados de otros objetos que se hayan creado.

Un objeto definido por una clase es algo similar a un diccionario, solo con una sintaxis un poco diferente. Por ejemplo, en lugar de escribir s['name'] o s['price'], ahora se escribe s.name y s.price.

✨ Revisar Solución y Practicar

Ejercicio 4.2: Agregando algunos métodos

Con las clases, puedes adjuntar funciones a tus objetos. Estas se conocen como métodos y son funciones que operan sobre los datos almacenados dentro de un objeto. Agrega un método cost() y sell() a tu objeto Stock. Deberían funcionar así:

>>> import stock
>>> s = stock.Stock('GOOG', 100, 490.10)
>>> s.cost()
49010.0
>>> s.shares
100
>>> s.sell(25)
>>> s.shares
75
>>> s.cost()
36757.5
>>>
✨ Revisar Solución y Practicar

Ejercicio 4.3: Creando una lista de instancias

Intenta estos pasos para crear una lista de instancias de Stock a partir de una lista de diccionarios. Luego, calcula el costo total:

>>> import fileparse
>>> with open('portfolio.csv') as lines:
...     portdicts = fileparse.parse_csv(lines, select=['name','shares','price'], types=[str,int,float])
...
>>> portfolio = [ stock.Stock(d['name'], d['shares'], d['price']) for d in portdicts]
>>> portfolio
[<stock.Stock object at 0x10c9e2128>, <stock.Stock object at 0x10c9e2048>, <stock.Stock object at 0x10c9e2080>,
 <stock.Stock object at 0x10c9e25f8>, <stock.Stock object at 0x10c9e2630>, <stock.Stock object at 0x10ca6f748>,
 <stock.Stock object at 0x10ca6f7b8>]
>>> sum([s.cost() for s in portfolio])
44671.15
>>>

Ejercicio 4.4: Usando tu clase

Modifica la función read_portfolio() en el programa report.py de modo que lea una cartera en una lista de instancias de Stock como se mostró en el Ejercicio 4.3. Una vez que hayas hecho eso, corrige todo el código en report.py y pcost.py para que funcione con instancias de Stock en lugar de diccionarios.

Pista: No deberías tener que hacer cambios importantes en el código. Principalmente estarás cambiando el acceso a los diccionarios como s['shares'] a s.shares.

Deberías poder ejecutar tus funciones como antes:

>>> import pcost
>>> pcost.portfolio_cost('portfolio.csv')
44671.15
>>> import report
>>> report.portfolio_report('portfolio.csv', 'prices.csv')
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84
>>>
✨ Revisar Solución y Practicar

Resumen

¡Felicitaciones! Has completado el laboratorio de Clases. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.