Saltar al contenido

Programación avanzada

A-Level Ciencias de la Computación · Tema 20

Entrenar
Lección de video para este tema Abrir la página de video
13:52

Paradigmas de programación

Aquí hay un trabajo: listar a todos los estudiantes con nota A. Un programador escribe un bucle — empezar en el primer registro, verificar la nota, agregar el nombre a una lista, mover…

Narración en inglés · Subtítulos en inglés + 中文 quemados en pantalla

20.1

Paradigmas de programación

Syllabus
Los candidatos deben ser capaces de: Notas y orientación
Comprender lo que se entiende por un paradigma de programación
Demostrar comprensión de las características de varios paradigmas de programación:
• De bajo nivel Programación de bajo nivel: • comprensión y capacidad para escribir código de bajo nivel que utilice diversos modos de direccionamiento: inmediato, directo, indirecto, indexado y relativo
• Imperativa (Procedural) Programación Imperativa (Procedural): • Conocimiento previo y comprensión de la Programación Estructurada (ver detalles en la sección 11.3 del contenido AS) • comprensión y capacidad para escribir código de programación imperativa (procedural) que utilice variables, constructos, procedimientos y funciones. Ver detalles en el contenido AS
• Orientada a Objetos Programación Orientada a Objetos (POO): • comprensión de la terminología asociada con la POO (incluyendo objetos, propiedades/atributos, métodos, clases, herencia, polimorfismo, contención (agregación), encapsulamiento, getters, setters, instancias) • comprensión de cómo resolver un problema mediante el diseño de clases adecuadas • comprensión y capacidad para escribir código que demuestre el uso de la POO
• Declarativa Programación Declarativa: • comprensión y capacidad para resolver un problema escribiendo hechos y reglas apropiadas basadas en la información proporcionada • comprensión y capacidad para escribir código que pueda satisfacer un objetivo utilizando hechos y reglas

Fuente: Plan de estudios Cambridge International

Un paradigma de programación 编程范式 es un estilo de programación — una forma de estructurar programas, con sus propias ideas y características del lenguaje. Cuatro paradigmas de programación están incluidos en este plan de estudios.

"Describa lo que se entiende por un lenguaje imperativo (procedural)" (dos puntos). Un lenguaje en el que el programa es una secuencia de instrucciones que se ejecutan en orden y que cambian el estado del programa; el programador dice cómo se realiza la tarea, utilizando procedimientos, secuencia, selección e iteración. "Describa lo que se entiende por un lenguaje declarativo": el programa establece hechos y reglas (lo que se sabe y lo que se desea) y el motor de inferencia del lenguaje determina cómo encontrar la respuesta; el programador no da la secuencia de pasos.

Identificar el paradigma a partir de una muestra de código (una pregunta regular del Paper 3): LDD 200, ADD #5, STO 201 son de bajo nivel (mnemotécnicos, registros, direcciones de memoria); FOR Count ← 1 TO 10 … NEXT Count con procedimientos y asignaciones es imperativo; CLASS Dog … PRIVATE Name : STRING … PUBLIC PROCEDURE NEW(…) es orientado a objetos; type(lion, wild). y dangerous(X) IF type(X, wild) son declarativos (lógica). En la pregunta de emparejamiento: bajo nivel se empareja con "mnemotécnicos que corresponden directamente a instrucciones de máquina", imperativo con "una secuencia de sentencias que cambian el estado", POO con "objetos que combinan atributos y métodos", declarativo con "hechos y reglas, sin un orden de ejecución dado".

Cuatro paradigmas: de bajo nivel, imperativo, orientado a objetos y declarativo
Cuatro paradigmas: bajo nivel, imperativo, orientado a objetos y declarativo

Programación de bajo nivel

Programación cercana al hardware en código de máquina 机器码 o lenguaje ensamblador 汇编语言, donde cada instrucción se mapea a lo que ejecuta la CPU. Brinda acceso directo a registros 寄存器 y direcciones de memoria 内存地址, utilizando diferentes modos de direccionamiento 寻址方式 (inmediato, directo, indirecto, indexado y relativo). Es muy rápido y compacto, pero específico de la arquitectura, tedioso y difícil de mantener. Esta es la programación de bajo nivel 低级 programming, utilizada para controladores de dispositivos, firmware y cargadores de arranque.

Los cinco modos de direccionamiento. El plan de estudios solicita código de bajo nivel que utilice cada modo de direccionamiento (el conjunto de instrucciones está en el Tema 4). El operando de una instrucción de carga puede leerse de cinco formas, y el examen le da el contenido de la memoria y pregunta qué contiene el acumulador:

Una tabla de memoria con direcciones 105, 106, 107, 27 y 145 y sus contenidos, junto a cinco filas que muestran lo que recibe el acumulador de LDM #105, LDD 105, LDI 105, LDX 105 con IX = 2, y un salto relativo
Mismo operando, 105, leído de cinco formas: como valor, como dirección, como la dirección de una dirección, como dirección más el registro índice, y como desplazamiento desde la instrucción actual
  • inmediato (LDM #105): el operando es el valor; ACC se convierte en 105.
  • directo (LDD 105): el operando es la dirección del valor; ACC se convierte en el contenido de 105, aquí 27.
  • indirecto (LDI 105): el operando es la dirección de una dirección; ACC se convierte en el contenido de 27, aquí 91. Usado para punteros y para datos cuya posición se decide en tiempo de ejecución.
  • indexado (LDX 105): la dirección es el operando más el registro índice IX; con IX = 2, ACC se convierte en el contenido de 107. Usado para recorrer un array incrementando IX.
  • relativo (JMR +65): el destino es un desplazamiento desde la dirección de la instrucción actual, lo que hace que el código sea reubicable.

Ejemplo resuelto. Memoria: 105 contiene 27, 106 contiene 64, 200 contiene 0. Escriba código para sumar los contenidos de 105 y 106, almacenar el resultado en 200 y mostrarlo. LDD 105 (ACC = 27), ADD 106 (ACC = 91), STO 200, OUT. Para duplicar el valor en 105 en su lugar: LDD 105, ADD 105, STO 105. Indique el contenido de los registros después de cada línea cuando se pida rastrear.

Programación imperativa (procedural)

En la programación imperativa 命令式编程, el programador escribe una secuencia de comandos que cambian el estado del programa — asignaciones, condicionales, bucles, llamadas a funciones. Las variables 变量 almacenan el estado; las sentencias lo cambian; el código se organiza en procedimientos y funciones (también llamado programación estructurada o estructural). Este es el estilo de los Temas 9 y 11 (Python, C). Fuerte cuando el algoritmo tiene pasos secuenciales claros.

Programación orientada a objetos (POO)

En la programación orientada a objetos 面向对象编程, los programas se construyen a partir de objetos 对象 — unidades que combinan datos (atributos 属性) y operaciones (métodos 方法). Los objetos son instancias 实例 de clases 类. Los cuatro pilares:

  • encapsulamiento 封装 — los datos de un objeto están ocultos tras sus métodos; el código externo usa solo los métodos públicos, no los datos directamente. Esto protege el objeto y permite que sus internos cambien sin romper a los llamadores. Por ejemplo, un BankAccount oculta sus balance; usted los cambia solo a través de deposit() y withdraw(), que pueden imponer una regla como "nunca bajar de cero".
  • herencia 继承 — una subclase 子类 especializa una superclase 父类, heredando sus atributos y métodos y añadiendo o reemplazándolos 重写. Modela "es-un" ("un Gerente es un Empleado").
  • polimorfismo 多态 — diferentes objetos responden a la misma llamada de método de manera diferente; el llamador no necesita conocer el tipo exacto. Cada Shape tiene Area(), y un Circle y un Rectangle lo implementan cada uno a su manera.
  • abstracción 抽象 — mostrar una interfaz simple y ocultar la implementación.

Otros términos:

  • un constructor 构造函数 es un método especial que se ejecuta cuando se crea un objeto, para configurar sus atributos.
  • getters y setters leen y escriben los atributos de un objeto (sus propiedades) a través de métodos.
  • agregación 聚合 y contención 包含 construyen un objeto a partir de otros objetos (una relación "tiene-un").

La POO se utiliza para sistemas grandes, interfaces gráficas, simulaciones y juegos.

La misma forma de llamada.Area() ejecuta código diferente para cada objeto: un Círculo calcula pi r al cuadrado, un Rectángulo calcula ancho por alto
Polimorfismo: la misma llamada de método ejecuta el código propio de cada objeto
Un diagrama de clases UML para Shape: una caja de tres partes con el nombre de la clase, atributos privados (Name, Area, Perimeter, marcados con menos) y métodos públicos (SetShape, calculateArea, calculatePerimeter, marcados con más)
Un diagrama de clases para una Forma: atributos privados y métodos públicos
Un diagrama de herencia UML: la superclase employee en la parte superior, con las subclases partTime y fullTime debajo, cada una unida a la superclase mediante una flecha de generalización de triángulo hueco y añadiendo sus propios atributos y métodos
Herencia: partTime y fullTime son subclases de employee
Un objeto BankAccount con un saldo privado alcanzado solo a través de los métodos públicos deposit() y withdraw(); el código externo no puede tocar los datos directamente
Encapsulamiento: los datos de un objeto son privados, alcanzados solo a través de sus métodos públicos

Cómo califica la POO el examinador

Definiciones. Clase: una plantilla (plano) que define los atributos y métodos de los objetos de ese tipo. Objeto: una instancia de una clase, creada a partir de ella, con sus propios valores para los atributos ("una ocurrencia de un objeto" es la frase del examen para una instancia). Atributo (propiedad): un dato perteneciente a una clase. Método: un procedimiento o función perteneciente a una clase que actúa sobre sus atributos. Encapsulación: combinar los atributos y métodos en una sola clase y restringir el acceso externo a los datos: los atributos son privados y solo pueden leerse o modificarse a través de métodos públicos. Herencia: una subclase adquiere los atributos y métodos de su clase padre (super) y puede añadir los suyos propios u anularlos. Polimorfismo: métodos con el mismo nombre que se comportan diferentemente en diferentes clases; típicamente una subclase ** redefine** un método de su padre, y se ejecuta la versión correcta para cada objeto. Contención: una clase tiene un objeto de otra clase como atributo (un coche tiene un motor). "Identificar la característica que restringe el acceso externo a los datos" es encapsulación; "el término para una ocurrencia de un objeto" es instancia.

"Describir la estructura de una clase" (tres puntos): atributos (propiedades) que almacenan los datos del objeto, generalmente declarados como privados; métodos (procedimientos y funciones) que actúan sobre esos atributos, generalmente públicos; y un constructor, un método que se ejecuta cuando se crea un objeto para inicializar los atributos. "Dar tres beneficios de la POO": el código se reutiliza mediante herencia; los datos están protegidos por encapsulación, por lo que solo pueden ser modificados por los métodos de la propia clase; un programa grande se divide en clases que se escriben y prueban de forma independiente, lo que facilita el mantenimiento y la ampliación; las clases modelan entidades del mundo real, por lo que el diseño es más fácil de entender; el polimorfismo permite que la misma llamada funcione para diferentes objetos.

La clase en pseudocódigo, tal como lo establece Paper 3:

CLASS Car
    PRIVATE Registration : STRING
    PRIVATE Year : INTEGER
    PRIVATE Mileage : INTEGER
    PUBLIC PROCEDURE NEW(NewReg : STRING, NewYear : INTEGER)
        Registration ← NewReg
        Year ← NewYear
        Mileage ← 0
    ENDPROCEDURE
    PUBLIC FUNCTION GetMileage() RETURNS INTEGER
        RETURN Mileage
    ENDFUNCTION
    PUBLIC PROCEDURE AddMileage(Extra : INTEGER)
        Mileage ← Mileage + Extra
    ENDPROCEDURE
ENDCLASS

Un objeto se crea con MyCar ← NEW Car("AB12 CDE", 2020) y se utiliza con MyCar.AddMileage(150) y OUTPUT MyCar.GetMileage(). Una subclase reutiliza el constructor del padre a través de SUPER:

CLASS ElectricCar INHERITS Car
    PRIVATE BatteryCapacity : REAL
    PUBLIC PROCEDURE NEW(NewReg : STRING, NewYear : INTEGER, NewCapacity : REAL)
        SUPER.NEW(NewReg, NewYear)
        BatteryCapacity ← NewCapacity
    ENDPROCEDURE
ENDCLASS

La misma clase en Python, tal como lo espera Paper 4: los atributos se hacen privados con doble guion bajo, el constructor es __init__, y una subclase nombra a su padre entre corchetes y llama a super().__init__(…):

class Car:
    def __init__(self, reg, year):
        self.__registration = reg
        self.__year = year
        self.__mileage = 0
    def get_mileage(self):
        return self.__mileage
    def add_mileage(self, extra):
        self.__mileage = self.__mileage + extra

class ElectricCar(Car):
    def __init__(self, reg, year, capacity):
        super().__init__(reg, year)
        self.__capacity = capacity

cars = []
cars.append(Car("AB12 CDE", 2020))
cars.append(ElectricCar("EV21 XYZ", 2023, 75.0))
cars[1].add_mileage(150)
print(cars[1].get_mileage())

En Java las mismas ideas son private/public campos, un constructor con el nombre de la clase, extends y super(…); en VB.NET Private/Public, Sub New, Inherits y MyBase.New. Un método polimórfico se escribe en el padre y se anula en el hijo con el mismo nombre; una llamada a través de una variable de tipo padre ejecuta la versión del hijo.

Estructuras de datos como objetos. Paper 4 construye una pila, lista enlazada o árbol binario a partir de una Node clase cuyos atributos son los datos y una o dos referencias a otros nodos; una Tree (o LinkedList) clase contiene la raíz (o inicio) y los métodos.

Un árbol binario de objetos Node: la Root del objeto Tree apunta al nodo 15, cuyas referencias Left y Right apuntan a los nodos 8 y 19, y así sucesivamente, con None para referencias vacías
A un árbol binario construido a partir de objetos: cada Nodo contiene Datos además de referencias Izquierda y Derecha, y el Árbol contiene la Raíz; al insertar se recorre hacia abajo por las referencias
CLASS Node
    PUBLIC Data : INTEGER
    PUBLIC Left : Node          // NULL when there is no child
    PUBLIC Right : Node
    PUBLIC PROCEDURE NEW(NewData : INTEGER)
        Data ← NewData
        Left ← NULL
        Right ← NULL
    ENDPROCEDURE
ENDCLASS

CLASS Tree
    PRIVATE Root : Node
    PUBLIC PROCEDURE Insert(NewData : INTEGER)
        DECLARE NewNode, Current : Node
        DECLARE Placed : BOOLEAN
        NewNode ← NEW Node(NewData)
        IF Root = NULL THEN
            Root ← NewNode
        ELSE
            Current ← Root
            Placed ← FALSE
            WHILE NOT Placed
                IF NewData < Current.Data THEN
                    IF Current.Left = NULL THEN
                        Current.Left ← NewNode
                        Placed ← TRUE
                    ELSE
                        Current ← Current.Left
                    ENDIF
                ELSE
                    IF Current.Right = NULL THEN
                        Current.Right ← NewNode
                        Placed ← TRUE
                    ELSE
                        Current ← Current.Right
                    ENDIF
                ENDIF
            ENDWHILE
        ENDIF
    ENDPROCEDURE
ENDCLASS

Un método buscar recorre el mismo camino y retorna TRUE cuando Current.Data = Target, FALSE cuando llega a NULL; un método de salida en orden es recursivo: muestra el subárbol izquierdo, el nodo, luego el subárbol derecho. Para una lista enlazada el nodo tiene una referencia, Next, y la clase de la lista contiene Start; para una pila construida a partir de una lista, push y pop funcionan en Start.

Ejemplo resuelto. Un juego tiene personajes. Cada uno tiene un nombre, salud (que comienza en 100) y una posición dada por X e Y. Escribe una clase Character con un constructor y un método Move(DX, DY); luego una subclase Wizard que añada Mana (que comienza en 50) y un método CastSpell() que tome 10 maná y retorne TRUE si había suficiente.

CLASS Character
    PRIVATE Name : STRING
    PRIVATE Health : INTEGER
    PRIVATE X : INTEGER
    PRIVATE Y : INTEGER
    PUBLIC PROCEDURE NEW(NewName : STRING, StartX : INTEGER, StartY : INTEGER)
        Name ← NewName
        Health ← 100
        X ← StartX
        Y ← StartY
    ENDPROCEDURE
    PUBLIC PROCEDURE Move(DX : INTEGER, DY : INTEGER)
        X ← X + DX
        Y ← Y + DY
    ENDPROCEDURE
ENDCLASS

CLASS Wizard INHERITS Character
    PRIVATE Mana : INTEGER
    PUBLIC PROCEDURE NEW(NewName : STRING, StartX : INTEGER, StartY : INTEGER)
        SUPER.NEW(NewName, StartX, StartY)
        Mana ← 50
    ENDPROCEDURE
    PUBLIC FUNCTION CastSpell() RETURNS BOOLEAN
        IF Mana >= 10 THEN
            Mana ← Mana - 10
            RETURN TRUE
        ELSE
            RETURN FALSE
        ENDIF
    ENDFUNCTION
ENDCLASS

Los puntos son para atributos privados, un constructor que establece todos los atributos, la línea de herencia, la llamada al constructor del padre y un método que usa y cambia los datos propios del objeto. Cuando la pregunta pide un diagrama de clases, dibuja un cuadro en tres partes (nombre; atributos con - para privado; métodos con + para público) y une una subclase a su padre con una flecha apuntando al padre.

Programación declarativa

En la programación declarativa 声明式编程, usted dice qué calcular, no cómo; el entorno de ejecución determina los pasos. Dos tipos:

  • programación funcional 函数式编程 — construida a partir de funciones puras 纯函数 (sin efectos secundarios副作用; la misma entrada siempre produce la misma salida) compuestas entre sí. Ejemplos: Haskell, Lisp.
  • programación lógica 逻辑编程 — declara hechos y reglas; el motor responde a un objetivo (consulta) mediante inferencia. Ejemplo: Prolog.

Un ejemplo familiar de programación declarativa es SQL 结构化查询语言: SELECT * FROM Customer WHERE Country = 'UK' dice qué se desea, no cómo recorrer los registros.

Los hechos, las reglas y los objetivos son lo que el examen evalúa en el paradigma declarativo. Dado estos hechos 事实 (enunciados verdaderos) y una regla 规则 (una conclusión válida cuando se cumplen sus condiciones):

01 type(leopard, wild).
02 type(lion, wild).
03 type(tabby, domestic).
04 size(leopard, large).
05 size(lion, large).
06 size(tabby, small).
07 dangerous(X) IF type(X, wild) AND size(X, large).

"Escriba el resultado del objetivo type(X, wild)": X = leopard, X = lion. El engine empareja el objetivo con cada hecho a su vez; cada emparejamiento es una solución, y una letra mayúscula es una variable que el emparejamiento rellena. "Escriba un hecho para mostrar que un guepardo es salvaje": type(cheetah, wild). "Explique qué hace la línea 07": define una regla con la conclusión dangerous(X), la cual es verdadera para cualquier X que sea tanto salvaje como grande, por lo que dangerous(A) devuelve A = leopard, A = lion. "Escriba una regla: una característica F puede estar disponible para un estilo de carrocería B si F es una característica y B es un estilo de carrocería y F no está deshabilitado para B": may_be_available(F, B) IF feature(F) AND body_style(B) AND NOT unavailable(F, B). Copie los nombres de predicados y el orden de argumentos utilizados exactamente en los hechos de la pregunta; un nuevo hecho termina con un punto y las condiciones de una regla están unidas con AND.

Comparando paradigmas

Paradigma Fortaleza Lenguajes típicos
Bajo nivel máximo control, velocidad Ensamblador
Imperativo directo, intuitivo C, Python
Orientado a objetos modular, modela entidades Java, C#, Python
Funcional claro, sin efectos secundarios Haskell, F#
Lógico inferencia, reglas Prolog
Base de datos consultas de datos SQL

Los lenguajes modernos suelen combinar paradigmas — Python soporta todos los procedimental, POO y funcional. El adecuado depende del problema.

Explorar

Laboratorio de conceptos de programación

Conectar ejemplos con la idea de programación que muestran.

Vocabulario Entrenar
Inglés Chino Pinyin
programming paradigm/ˈprəʊɡræmɪŋ ˈpærədaɪm/ 编程范式 biān chéng fàn shì
facts/fækts/ 事实 shì shí
rule/ruːl/ 规则 guī zé
low-level/ləʊ ˈlevl/ 低级 dī jí
registers/ˈredʒɪstəz/ 寄存器 jì cún qì
memory addresses/ˈmeməri əˈdresɪz/ 内存地址 nèi cún dì zhǐ
objects/ˈɒbdʒekts/ 对象 duì xiàng
attributes/ˈætrɪbjuːts/ 属性 shǔ xìng
methods/ˈmeθədz/ 方法 fāng fǎ
machine code/məˈʃiːn kəʊd/ 机器码 jī qì mǎ
assembly language/əˈsemblɪ ˈlæŋɡwɪdʒ/ 汇编语言 huì biān yǔ yán
addressing modes/əˈdresɪŋ məʊdz/ 寻址方式 xún zhǐ fāng shì
Variables/ˈveərɪəblz/ 变量 biàn liàng
object-oriented programming/ˈɒbdʒekt ˈɔːrɪəntɪd ˈprəʊɡræmɪŋ/ 面向对象编程 miàn xiàng duì xiàng biān chéng
instances/ˈɪnstənsɪz/ 实例 shí lì
classes/ˈklæsɪz/ 类 lèi
encapsulation/ɪnˌkæpsjʊˈleɪʃn/ 封装 fēng zhuāng
inheritance/ɪnˈherɪtəns/ 继承 jì chéng
subclass/ˈsʌbklæs/ 子类 zi lèi
superclass/ˈsuːpəklæs/ 父类 fù lèi
overriding/ˌəʊvəˈraɪdɪŋ/ 重写 chóng xiě
polymorphism/ˈpɒlɪmɔːfɪzəm/ 多态 duō tài
abstraction/əbˈstrækʃn/ 抽象 chōu xiàng
constructor/kənˈstrʌktə/ 构造函数 gòu zào hán shù
aggregation/ˌæɡrɪˈɡeɪʃn/ 聚合 jù hé
containment/kənˈteɪnmənt/ 包含 bāo hán
declarative programming/dɪˈklærətɪv ˈprəʊɡræmɪŋ/ 声明式编程 shēng míng shì biān chéng
functional programming/ˈfʌŋkʃənl ˈprəʊɡræmɪŋ/ 函数式编程 hán shù shì biān chéng
pure functions/pjʊə ˈfʌŋkʃnz/ 纯函数 chún hán shù
side effects/saɪd ɪˈfekts/ 副作用 fù zuò yòng
logic programming/ˈlɒdʒɪk ˈprəʊɡræmɪŋ/ 逻辑编程 luó jí biān chéng
SQL/ˌes kjuː ˈel/ 结构化查询语言 jié gòu huà chá xún yǔ yán
20.2

Procesamiento de archivos

Syllabus
Los candidatos deben ser capaces de: Notas y orientación
Escribir código para realizar operaciones de procesamiento de archivos Abrir (en modo lectura, escritura, anexar) y cerrar un archivo Leer un registro de un archivo y escribir un registro en un archivo Realizar operaciones de procesamiento de archivos sobre archivos secuenciales, lineales y aleatorios
Demostrar comprensión de una excepción y la importancia del manejo de excepciones Saber cuándo es apropiado utilizar el manejo de excepciones Escribir código de programa para utilizar el manejo de excepciones

Fuente: Plan de estudios Cambridge International

Esto amplía el manejo de archivos 文件 del Tema 10, procesando archivos secuenciales, lineales y aleatorios (acceso directo). Operaciones pseudocódigo: OPENFILE name FOR READ | WRITE | APPEND (READ abre un archivo existente, WRITE crea/sobrescribe, APPEND añade al final); READFILE name, line; WRITEFILE name, value; CLOSEFILE name; y EOF(name) que es VERDADERO al final.

Leer un archivo completo:

OPENFILE "names.txt" FOR READ
WHILE NOT EOF("names.txt") DO
    READFILE "names.txt", thisName
    OUTPUT thisName
ENDWHILE
CLOSEFILE "names.txt"

Buscar en un archivo (detenerse al encontrarlo):

found ← FALSE
OPENFILE "people.txt" FOR READ
WHILE NOT EOF("people.txt") AND NOT found DO
    READFILE "people.txt", line
    IF line = target THEN
        found ← TRUE
    ENDIF
ENDWHILE
CLOSEFILE "people.txt"

Actualizar un archivo in situ

La mayoría de los lenguajes no pueden editar un archivo de texto in situ. En cambio: abrir el original para READ y un archivo temporal para WRITE; para cada línea, escribir la nueva versión si debe cambiar, de lo contrario la original; cerrar ambos; luego reemplazar el original con el archivo temporal. El mismo patrón maneja la eliminación de líneas (omitarlas) e inserción de líneas.

Actualizar un archivo in situ: leer el archivo original, escribir las líneas cambiadas en un archivo temporal, luego reemplazar el original con el archivo temporal
Actualizar un archivo in situ: leer el original, escribir cambios en un archivo temporal, luego reemplazar el original

Registros y archivos de acceso aleatorio

Modos de apertura. READ: el archivo debe existir y la lectura comienza desde el principio. WRITE: se crea un archivo nuevo, y un archivo existente con ese nombre queda sobrescrito. APPEND: la escritura añade al final de un archivo existente. Todo archivo abierto se cierra con CLOSEFILE, y EOF(name) es TRUE cuando se ha leído el último elemento.

Tres organizaciones de archivos. En un archivo serial los registros están en el orden en que fueron añadidos; en un archivo secuencial están en orden de clave; ambos se leen desde el inicio. Un archivo aleatorio 随机文件 (direct-access file) almacena cada registro en una dirección calculada a partir de su clave mediante una función de hashing 哈希, por lo que se encuentra un registro sin leer los demás. Los registros se declaran como un tipo definido por el usuario:

TYPE AccountRecord
    DECLARE AccNo : INTEGER
    DECLARE Name : STRING
    DECLARE Balance : REAL
    DECLARE Active : BOOLEAN
ENDTYPE
Una clave 2317 hashada con MOD 1000 hasta la dirección 317, luego SEEK y GETRECORD en el archivo Acc.dat, mostrado como una fila de ranuras de registro de tamaño igual con la ranura 317 resaltada
Encontrar un registro en un archivo aleatorio: la clave se hashea a una dirección, el puntero del archivo busca directamente en esa ranura y se lee el registro; ningún otro registro es tocado

Las operaciones de archivos aleatorios en pseudocódigo son OPENFILE "Acc.dat" FOR RANDOM, SEEK "Acc.dat", Address (mover el puntero del archivo a ese registro), GETRECORD "Acc.dat", Rec (leer el registro allí) y PUTRECORD "Acc.dat", Rec (escribir el registro allí). Encontrar un cliente por número de cuenta, según Paper 3:

DECLARE Rec : AccountRecord
DECLARE Target, Address : INTEGER
INPUT Target
Address ← Target MOD 1000              // the hashing function
OPENFILE "Acc.dat" FOR RANDOM
SEEK "Acc.dat", Address
GETRECORD "Acc.dat", Rec
WHILE Rec.AccNo <> Target AND Rec.AccNo <> 0    // 0 marks an empty slot
    Address ← Address + 1               // a collision: try the next slot
    SEEK "Acc.dat", Address
    GETRECORD "Acc.dat", Rec
ENDWHILE
IF Rec.AccNo = Target THEN
    OUTPUT Rec.Name, Rec.Balance
ELSE
    OUTPUT "No such account"
ENDIF
CLOSEFILE "Acc.dat"

Para almacenar un registro, hashear su clave, SEEK a la dirección y PUTRECORD, avanzando sobre cualquier ranura ya ocupada. Las marcas van al hashing, al SEEK antes del GET o PUT, a la comparación con el objetivo, al manejo de colisiones y al cierre del archivo.

Ejemplo resuelto. ActiveFile.dat contiene AccountRecord registros. Escribe pseudocódigo que copie cada registro cuyo campo Active mar FALSE al final de ArchiveFile.dat.

DECLARE Rec : AccountRecord
OPENFILE "ActiveFile.dat" FOR READ
OPENFILE "ArchiveFile.dat" FOR APPEND
WHILE NOT EOF("ActiveFile.dat")
    READFILE "ActiveFile.dat", Rec
    IF Rec.Active = FALSE THEN
        WRITEFILE "ArchiveFile.dat", Rec
    ENDIF
ENDWHILE
CLOSEFILE "ActiveFile.dat"
CLOSEFILE "ArchiveFile.dat"

Archivos de texto en Python (Papel 4): file = open("HighScore.txt", "r"), luego for line in file: con line.strip() y line.split(",") para separar los campos, int(…) para convertir una puntuación, y file.close(); para escribir, open(name, "w") (o "a" para añadir) y file.write(str(score) + "\n"). Una tabla de mejores puntuaciones se lee en una lista de registros, se inserta la nueva puntuación en su lugar, y se escribe toda la lista de nuevo. El examinador califica la apertura con el modo correcto, un bucle que lee cada línea, la conversión de texto a números y el cierre.

Trampas

Olvidar cerrar un archivo (puede haber pérdida de datos); abrirlo en modo WRITE cuando se pretendía APPEND (sobrescribe todo); leer más allá de EOF; rutas codificadas en rígido —una ruta como /Users/Admin/data.txt falla en otra máquina, así que usa una constante relativa como DataFile = "./data/scores.txt".

Explorar

Ruta de acceso al archivo

Seguir un archivo desde el almacenamiento hasta el programa y de vuelta de forma segura.

Vocabulario Entrenar
Inglés Chino Pinyin
file/faɪl/ 文件 wén jiàn
random file/ˈrændəm faɪl/ 随机文件 suí jī wén jiàn
hashing/ˈhæʃɪŋ/ 哈希 hā xī
20.2

Manejo de excepciones

Una excepción 异常 es un error o condición inesperada durante la ejecución: división por cero, archivo no encontrado, fallo de red, índice de array 数组 fuera de rango. El manejo de excepciones 异常处理 permite a un programa detectarlo y responder con elegancia en lugar de colgarse.

Importa porque los programas reales enfrentan errores que no pueden evitarse de antemano (archivos movidos, redes caídas, entrada incorrecta); sin él, cada operación necesitaría su propia IF comprobación; y separa el flujo normal del manejo de errores, haciendo que el camino principal se lea con claridad. Por ejemplo, un archivo puede ser eliminado por otro usuario entre que tu programa verifica que existe y lo abre realmente: no puedes evitar eso, solo manejar el fallo cuando ocurra.

"Describe, con un ejemplo, qué significa una excepción" (dos marcas). Un evento o error inesperado que ocurre durante la ejecución de un programa (en tiempo de ejecución) e interrumpe su flujo normal; por ejemplo, dividir por cero, abrir un archivo que no existe, convertir una entrada no numérica a entero, un índice de array fuera de rango, o quedarse sin memoria. "Identifica dos causas posibles de excepciones" se responde con esa lista, además de "un dispositivo o red no está disponible" e "entrada de tipo de dato inválido".

"Indica las razones para incluir manejo de excepciones" (tres marcas). Para evitar que el programa se colgue (terminando inesperadamente); para mostrar un mensaje significativo al usuario en lugar de un error del sistema; para permitir que el programa recupere y continúe, por ejemplo pidiendo la entrada de nuevo, o cerrando archivos de forma segura antes de terminar; y porque algunos errores no pueden predecirse cuando se escribe el programa. "Describe cómo se puede evitar la terminación del programa debido a una excepción": pon las sentencias que podrían generar una excepción dentro de un bloque TRY; escribe un bloque EXCEPT (catch) para esa excepción que la maneje, por ejemplo mostrando un mensaje, de modo que la ejecución continúe después del bloque en lugar de detenerse. "Explica qué significa el manejo de excepciones": detectar una excepción cuando ocurre y ejecutar código (el manejador) que la gestione para que el programa continúe.

Patrón

TRY
    OPENFILE "data.txt" FOR READ
    READFILE "data.txt", line
    OUTPUT line
    CLOSEFILE "data.txt"
EXCEPT FileNotFound
    OUTPUT "Sorry, the file does not exist."
EXCEPT ReadError
    OUTPUT "Sorry, error reading the file."
ENDTRY

El bloque TRY contiene el código que podría fallar; se ejecuta el primer bloque EXCEPT coincidente. Los lenguajes reales también tienen un catch-all EXCEPT y un bloque FINALLY que se ejecuta haya ocurrido o no una excepción —útil para limpieza (cerrar archivos).

Flujo de excepciones: si el bloque TRY genera una excepción, el control salta al EXCEPT coincidente; sin excepción se omite. De cualquier manera, el bloque FINALLY se ejecuta, luego el programa continúa
Flujo de excepción: una excepción salta al EXCEPT coincidente; FINALLY siempre se ejecuta antes de que el programa continúe

Levantar una excepción

Una subrutina que detecta un error puede levantar 抛出 una excepción para que el llamador la maneje:

PROCEDURE Divide(a : INTEGER, b : INTEGER) RETURNS INTEGER
    IF b = 0 THEN
        RAISE DivideByZero
    ENDIF
    RETURN a DIV b
ENDPROCEDURE

Dónde manejar excepciones

Manéjalas cerca del error si la respuesta es sencilla (un mensaje, un reintentar), o más arriba en la pila de llamadas 调用栈 si solo el código externo sabe qué hacer (un bucle GUI de nivel superior registra el error y muestra un diálogo amigable). No tragues las excepciones en silencio —al menos regístralas, o la depuración será imposible.

Excepciones comunes: FileNotFound, IOError, DivisionByZero, IndexOutOfRange, InvalidArgument, NullReference, OutOfMemory. Envolver cada operación fallida en un TRY con los manejadores EXCEPT adecuados da a un programa que degrada con gracia en lugar de colgarse.

Ejemplo resuelto (Papel 4). Escribe una función que lea números enteros, uno por línea, de un archivo cuyo nombre se pasa como parámetro y los devuelva en una lista. No debe colgarse si el archivo no existe o una línea no es un número entero.

def read_scores(filename):
    scores = []
    try:
        file = open(filename, "r")
        for line in file:
            scores.append(int(line))
        file.close()
    except FileNotFoundError:
        print("The file", filename, "does not exist")
    except ValueError:
        print("A line in the file was not a whole number")
    return scores

El bloque try contiene el código que puede fallar (la apertura y la conversión); cada except nombra una excepción y realiza algo útil; la función todavía devuelve una lista, por lo que el llamador continúa. En Java, la misma estructura es try { … } catch (FileNotFoundException e) { … } catch (NumberFormatException e) { … }; en VB.NET es Try … Catch ex As FileNotFoundException … End Try. Puntuación: las declaraciones de riesgo dentro del try, los nombres correctos de las excepciones, un mensaje para cada una, y el programa continuando después; un catch-all except: obtiene la puntuación de colapso pero no la de "excepción apropiada".

Ejemplo resuelto. Un archivo de texto de miembros necesita cambiar el número de teléfono de un miembro. ¿Por qué el programa no puede simplemente sobrescribir esa línea y cuál es el patrón? Las líneas de un archivo de texto tienen longitudes diferentes, y el archivo no tiene espacios en blanco para absorber una diferencia: una sustitución más larga chocaría con el siguiente registro, y una más corta dejaría parte de la línea antigua. Por lo tanto, el patrón es abrir el original para LEER y un archivo temporal para ESCRIBIR, leer cada línea a su vez, escribiendo la versión nueva para la línea que cambia y la línea original para todas las demás, cerrar ambos, y luego reemplazar el original con el archivo temporal. La misma estructura maneja la eliminación (saltar la línea) y la inserción (escribir la línea adicional). Tenga en cuenta que todas las líneas se escriben, no solo la cambiada; escribir solo el nuevo registro y perder el resto del archivo es el error clásico.

Explorar

Flujo del manejo de excepciones

Paso a paso de lo que ocurre cuando falla el código. La excepción salta del flujo normal hacia un manejador, FINALLY limpia en cualquier caso, y el programa continúa en lugar de fallar.

Vocabulario Entrenar
Inglés Chino Pinyin
array/əˈreɪ/ 数组 shù zǔ
imperative programming/ɪmˈperətɪv ˈprəʊɡræmɪŋ/ 命令式编程 mìng lìng shì biān chéng
exception/ekˈsepʃn/ 异常 yì cháng
exception handling/ekˈsepʃn ˈhændlɪŋ/ 异常处理 yì cháng chǔ lǐ
raise/reɪz/ 抛出 pāo chū
call stack/kɔːl stæk/ 调用栈 diào yòng zhàn
20.2

Definiciones aceptadas por el examinador

Una pregunta de definición se califica según un texto fijo. Aprende estas definiciones exactamente, y da solo una respuesta.

Término Definición
paradigma de programación un estilo o forma de programar, con su propia manera de estructurar un programa
lenguaje imperativo el programa es una secuencia de sentencias que cambian el estado del programa; el programador dice cómo se hace la tarea
lenguaje declarativo el programa establece hechos y reglas y el motor de inferencia determina cómo encontrar la respuesta
clase una plantilla que define los atributos y métodos de los objetos de ese tipo
objeto (instancia) una ocurrencia de una clase, con sus propios valores para los atributos
atributo un elemento de datos que pertenece a una clase
método un procedimiento o función que pertenece a una clase y actúa sobre sus atributos
encapsulación mantener los atributos y métodos juntos en una clase y restringir el acceso externo a los datos, de modo que solo se cambien a través de métodos públicos
herencia una subclase adquiere los atributos y métodos de su clase padre y puede agregarlos o reemplazarlos
polimorfismo métodos con el mismo nombre que se comportan de manera diferente para diferentes clases
constructor un método que se ejecuta cuando se crea un objeto e inicializa sus atributos
contención una clase tiene un objeto de otra clase como uno de sus atributos
hecho una afirmación en un programa declarativo que es verdadera
regla una conclusión que se cumple cuando sus condiciones son verdaderas
archivo serial, secuencial, aleatorio registros en el orden en que se agregaron; registros en orden de clave; cada registro en una dirección calculada a partir de su clave
excepción un error o evento inesperado durante la ejecución que interrumpe el flujo normal
manejo de excepciones detectar una excepción cuando ocurre y ejecutar código que la maneje para que el programa continúe
20.2

Consejos para el examen

  • Paradigmas: conozca la descripción de una sola línea de cada uno y esté preparado para nombrar el paradigma a partir de una muestra de código; las preguntas de bajo nivel piden los cinco modos de direccionamiento y lo que recibe el acumulador.
  • Las definiciones de POO aparecen en cada sesión: clase, objeto, atributo, método, encapsulación, herencia, polimorfismo, constructor. Escriba una clase en pseudocódigo con atributos PRIVADOS, un PÚBLICO NEW y getters; una subclase con INHERITA y SUPER.NEW.
  • Declarativo: una meta con una variable devuelve todos los hechos coincidentes; una regla es una conclusión SI condiciones unidas con Y; copie los nombres de predicados de la pregunta exactamente.
  • Archivos: los tres modos y qué hace cada uno con un archivo existente; READFILE en un bucle WHILE NOT EOF; los archivos aleatorios usan un hash, SEEK, GETRECORD y PUTRECORD, con un paso sobre para colisiones.
  • Excepciones: definición con un ejemplo, tres razones para manejarlas, y TRY con un EXCEPT nombrado que permite que el programa continúe.

Errores comunes

  • Describir un programa declarativo como "una secuencia de pasos que da la respuesta"; establece qué es verdadero y qué se desea, no cómo.
  • Confundir un objeto con una clase, o una instancia con un atributo; la pregunta "una ocurrencia de un objeto" busca instancia.
  • Declarar los atributos PÚBLICOS, o acceder a ellos desde fuera de la clase en lugar de a través de un getter, lo que pierde la puntuación de encapsulación.
  • Un constructor de subclase que establece directamente los atributos del padre en lugar de llamar a SUPER.NEW.
  • Explicar el polimorfismo como "muchos objetos"; es el mismo nombre de método que se comporta de manera diferente para diferentes clases.
  • Abrir un archivo FOR WRITE para agregar un registro, lo que destruye el contenido existente; use APPEND.
  • Leer un archivo aleatorio desde el principio; busque primero en la dirección hasheada.
  • Colocar el manejador de excepciones alrededor de código que no puede fallar, o capturar todo sin mensaje, o describir el manejo de excepciones como "comprobar la entrada con IF".

Lecciones interactivas sobre este tema

Trátalo paso a paso, con ejercicios de verificación instantánea.

Exámenes Anteriores

Más temas en A-Level Ciencias de la Computación

Iniciar sesión o crear cuenta

IGCSE, A-Level & AP