Passer au contenu

Programmation avancée

Informatique A-Level · Sujet 20

Entrainer
Leçon vidéo pour ce sujet Ouvrir la page vidéo
13:52

Paradigmes de programmation

Voici une tâche : lister tous les élèves ayant une note A. Un programmeur écrit une boucle — commencer au premier enregistrement, vérifier la note, ajouter le nom à une liste, avancer…

Narration en anglais · Sous-titres anglais + 中文 incrustés

20.1

Paradigmes de programmation

Programme
Les candidats doivent être capables de : Notes et orientations
Comprendre ce qu'on entend par un paradigme de programmation
Montrer la compréhension des caractéristiques de plusieurs paradigmes de programmation :
• Bas niveau Programmation bas niveau : • compréhension et capacité à écrire du code bas niveau utilisant divers modes d'adressage : immédiat, direct, indirect, indexé et relatif
• Impératif (Procédural) Programmation impérative (procédurale) : • Connaissances supposées et compréhension de la programmation structurée (voir détails dans la section contenu AS 11.3) • compréhension et capacité à écrire du code de programmation impératif (procédural) utilisant des variables, des structures, des procédures et des fonctions. Voir détails dans le contenu AS
• Orienté objet Programmation Orientée Objet (POO) : • compréhension de la terminologie associée à la POO (incluant objets, propriétés/attributs, méthodes, classes, héritage, polymorphisme, contenances (agrégation), encapsulation, getters, setters, instances) • compréhension de la façon de résoudre un problème en concevant des classes appropriées • compréhension et capacité à écrire du code démontrant l'utilisation de la POO
• Déclaratif Programmation déclarative : • compréhension et capacité à résoudre un problème en écrivant des faits et des règles appropriés basés sur les informations fournies • compréhension et capacité à écrire du code capable de satisfaire un objectif en utilisant des faits et des règles

Source : Programme Cambridge International

Un paradigme de programmation 编程范式 est un style de programmation — une façon de structurer les programmes, avec ses propres idées et fonctionnalités langagières. Quatre paradigmes de programmation figurent dans ce programme.

"Décrivez ce que signifie un langage impératif (procédural)" (deux points). Un langage dans lequel le programme est une séquence d'instructions exécutées dans l'ordre et qui modifient l'état du programme ; le programmeur dit comment la tâche est réalisée, en utilisant des procédures, une séquence, une sélection et une itération. "Décrivez ce que signifie un langage déclaratif" : *le programme énonce des faits et des règles (ce qui est connu et ce qui est souhaité) et le moteur d'inférence du langage détermine comment trouver la réponse ; le programmeur ne donne pas la séquence d'étapes.

Identifier le paradigme à partir d'un exemple de code (une question régulière de Paper 3) : LDD 200, ADD #5, STO 201 sont de bas niveau (mnémoniques, registres, adresses mémoire) ; FOR Count ← 1 TO 10 … NEXT Count avec procédures et affectations est impératif ; CLASS Dog … PRIVATE Name : STRING … PUBLIC PROCEDURE NEW(…) est orienté objet ; type(lion, wild). et dangerous(X) IF type(X, wild) est déclaratif (logique). Dans la question d'appariement : bas niveau correspond à « mnémoniques qui correspondent directement aux instructions machine », impératif à « une séquence d'instructions qui modifient l'état », POO à « objets qui combinent attributs et méthodes », déclaratif à « faits et règles, sans ordre d'exécution donné ».

Quatre paradigmes : bas niveau, impératif, orienté objet et déclaratif
Quatre paradigmes : bas niveau, impératif, orienté objet et déclaratif

Programmation bas niveau

Programmation proche du matériel en code machine 机器码 ou langage assembleur 汇编语言, où chaque instruction correspond à ce que le CPU exécute. Elle offre un accès direct aux registres 寄存器 et aux adresses mémoire 内存地址, en utilisant différents modes d'adressage 寻址方式 (immédiat, direct, indirect, indexé et relatif). C'est très rapide et compact, mais spécifique à l'architecture, fastidieux et difficile à maintenir. C'est la programmation bas niveau 低级, utilisée pour les pilotes, le firmware et les chargeurs de démarrage.

Les cinq modes d'adressage. Le programme demande du code bas niveau utilisant chaque mode d'adressage (l'ensemble d'instructions se trouve au Topic 4). L'oprande d'une instruction de chargement peut être lu de cinq façons, et l'examen donne le contenu de la mémoire et demande ce que contient l'accumulateur :

Un tableau mémoire avec les adresses 105, 106, 107, 27 et 145 et leurs contenus, à côté de cinq lignes montrant ce que reçoit l'accumulateur depuis LDM #105, LDD 105, LDI 105, LDX 105 avec IX = 2, et un saut relatif
Le même opmande, 105, lu de cinq façons : comme une valeur, comme une adresse, comme l'adresse d'une adresse, comme une adresse plus le registre indexé, et comme un décalage par rapport à l'instruction actuelle
  • immédiat (LDM #105) : l'oprande est la valeur ; ACC devient 105.
  • direct (LDD 105) : l'oprande est l'adresse de la valeur ; ACC devient le contenu de 105, ici 27.
  • indirect (LDI 105) : l'oprande est l'adresse d'une adresse ; ACC devient le contenu de 27, ici 91. Utilisé pour les pointeurs et pour les données dont la position est décidée à l'exécution.
  • indexé (LDX 105) : l'adresse est l'oprande plus le registre indexé IX ; avec IX = 2, ACC devient le contenu de 107. Utilisé pour parcourir un tableau en incrémentant IX.
  • relatif (JMR +65) : la cible est un décalage par rapport à l'adresse de l'instruction actuelle, ce qui rend le code relocalisable.

Exemple résolu. Mémoire : 105 contient 27, 106 contient 64, 200 contient 0. Écrire du code pour additionner les contenus de 105 et 106, stocker le résultat dans 200 et l'afficher. LDD 105 (ACC = 27), ADD 106 (ACC = 91), STO 200, OUT. Pour doubler la valeur dans 105 au lieu de cela : LDD 105, ADD 105, STO 105. Indiquer le contenu des registres après chaque ligne lorsqu'on demande de tracer l'exécution.

Programmation impérative (procédurale)

En programmation impérative 命令式编程, le programmeur écrit une série de commandes qui changent l'état du programme — affectations, conditions, boucles, appels de fonctions. Les variables 变量 stockent l'état ; les instructions le modifient ; le code est organisé en procédures et fonctions (aussi appelées programmation structurée ou structurale). C'est le style des Topics 9 et 11 (Python, C). Fort lorsque l'algorithme a des étapes séquentielles claires.

Programmation orientée objet (POO)

En programmation orientée objet 面向对象编程, les programmes sont construits à partir d'objets 对象 — des unités combinant des données (attributs 属性) et des opérations (méthodes 方法). Les objets sont des instances 实例 de classes 类. Les quatre piliers :

  • encapsulation 封装 — les données d'un objet sont cachées derrière ses méthodes ; le code extérieur n'utilise que les méthodes publiques, pas les données directement. Cela protège l'objet et permet de modifier son interne sans casser les appelants. Par exemple, un BankAccount cache ses balance ; vous ne les modifiez qu'à travers deposit() et withdraw(), ce qui peut imposer une règle comme "ne jamais descendre sous zéro".
  • héritage 继承 — un sous-classe 子类 spécialise une superclasse 父类, héritant de ses attributs et méthodes et ajoutant ou redéfinissant 重写 ces derniers. Modélise "est-un" ("un Manager est un Employee").
  • polymorphisme 多态 — différents objets répondent à la même appel de méthode différemment ; l'appelant ne doit pas connaître le type exact. Chaque Shape possède Area(), et un Circle et un Rectangle l'implémentent chacun à leur manière.
  • abstraction 抽象 — montrer une interface simple et cacher l'implémentation.

Autres termes :

  • non constructeur 构造函数 est une méthode spéciale exécutée lors de la création d'un objet, pour initialiser ses attributs.
  • les getters et setters lisent et écrivent les attributs d'un objet (ses propriétés) via des méthodes.
  • l'agrégation 聚合 et l'containment 包含 construisent un objet à partir d'autres objets (une relation "a-un").

La POO est utilisée pour les grands systèmes, les interfaces graphiques, les simulations et les jeux.

La même forme d'appel. Area() exécute du code différent pour chaque objet : un Circle calcule pi r carré, un Rectangle calcule largeur fois hauteur *Polymorphisme : le même appel de méthode exécute le code propre de chaque objet

Un diagramme de classes UML pour Shape : une boîte à trois parties avec le nom de la classe, les attributs privés (Name, Area, Perimeter, marqués d'un moins) et les méthodes publiques (SetShape, calculateArea, calculatePerimeter, marquées d'un plus) *Un diagramme de classes pour Shape : attributs privés et méthodes publiques

Un diagramme d'héritage UML : la superclasse Employé en haut, avec les sous-classes TempsPartiel et TempsPlein en dessous, chacune reliée à la superclasse par une flèche de généralisation à triangle creux et ajoutant ses propres attributs et méthodes *Héritage : partTime et fullTime sont des sous-classes de employee

Un objet BankAccount avec un solde privé accessible uniquement par les méthodes publiques deposit() et withdraw() ; le code extérieur ne peut pas toucher aux données directement *Encapsulation : les données d'un objet sont privées, atteintes uniquement via ses méthodes publiques

POO selon la correction de l'examineur

Définitions. Classe : non modèle (plan) qui définit les attributs et méthodes des objets de ce type. Objet : une instance d'une classe, créée à partir d'elle, avec ses propres valeurs pour les attributs ("une occurrence d'un objet" est l'expression de l'examen pour une instance). Attribut (propriété) : un élément de données appartenant à une classe. Méthode : une procédure ou fonction appartenant à une classe qui agit sur ses attributs. Encapsulation : combiner les attributs et méthodes dans une classe et restreindre l'accès externe aux données : les attributs sont privés et ne peuvent être lus ou modifiés que via des méthodes publiques. Héritage : une sous-classe acquiert les attributs et méthodes de sa classe parente (super) et peut ajouter les siennes ou les redéfinir. Polymorphisme : des méthodes avec le même nom qui se comportent différemment dans différentes classes ; typiquement une sous-classe redéfinit une méthode de son parent, et la bonne version s'exécute pour chaque objet. Containment : une classe possède un objet d'une autre classe comme attribut (une voiture a un moteur). "Identifier la caractéristique qui restreint l'accès externe aux données" est l'encapsulation ; "le terme pour une occurrence d'un objet" est l'instance.

"Esquisser la structure d'une classe" (trois points) : les attributs (propriétés) qui stockent les données de l'objet, généralement déclarés privés ; les méthodes (procédures et fonctions) qui agissent sur ces attributs, généralement publiques ; et un constructeur, une méthode qui s'exécute lors de la création d'un objet pour initialiser les attributs. "Donner trois avantages de la POO" : le code est réutilisé grâce à l'héritage ; les données sont protégées par l'encapsulation, donc elles ne peuvent être modifiées que par les méthodes propres à la classe ; un grand programme est divisé en classes écrites et testées indépendamment, ce qui facilite l'entretien et l'extension ; les classes modélisent des entités réelles, donc la conception est plus facile à comprendre ; le polymorphisme permet au même appel de fonctionner pour différents objets.

La classe en pseudocode, tel que défini par 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 objet est créé avec MyCar ← NEW Car("AB12 CDE", 2020) et utilisé avec MyCar.AddMileage(150) et OUTPUT MyCar.GetMileage(). Une sous-classe réutilise le constructeur parent via 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 même classe en Python, tel que attendu par Paper 4 : les attributs sont rendus privés avec un double underscore, le constructeur est __init__, et une sous-classe nomme son parent entre parenthèses et appelle 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, les mêmes concepts sont private/public champs, un constructeur portant le nom de la classe, extends et super(…) ; en VB.NET Private/Public, Sub New, Inherits et MyBase.New. Une méthode polymorphe est écrite dans la classe parente et redéfinie (override) dans la classe enfant avec le même nom ; un appel via une variable de type parent exécute la version de l'enfant.

Structures de données comme objets. Paper 4 construit une pile, une liste chaînée ou un arbre binaire à partir d'une classe Node dont les attributs sont les données et une ou deux références vers d'autres nœuds ; une classe Tree (ou LinkedList) contient la racine (ou le début) et les méthodes.

Un arbre binaire d'objets Node : la Root de l'objet Tree pointe vers le nœud 15, dont les références Left et Right pointent vers les nœuds 8 et 19, etc., avec None pour les références vides *Un arbre binaire construit à partir d'objets : chaque Node contient Data plus les références Left et Right, et Tree contient Root ; l'insertion parcourt les références

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

Une méthode find parcourt le même chemin et retourne TRUE lorsque Current.Data = Target, FALSE lorsqu'elle atteint NULL ; une méthode de sortie en ordre infixe est récursive : elle affiche le sous-arbre gauche, puis le nœud, enfin le sous-arbre droit. Pour une liste chaînée, le nœud possède une référence, Next, et la classe de liste détient Start ; pour une pile construite à partir d'une liste, les opérations push et pop s'effectuent toutes deux à Start.

Exemple résolu. Un jeu a des personnages. Chacun a un nom, une santé (commençant à 100) et une position donnée par X et Y. Écrire une classe Character avec un constructeur et une méthode Move(DX, DY) ; puis une sous-classe Wizard qui ajoute Mana (commençant à 50) et une méthode CastSpell() qui prend 10 mana et retourne TRUE s'il y en avait assez.

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

Les points sont pour les attributs privés, un constructeur qui définit chaque attribut, la ligne d'héritage, l'appel au constructeur parent, et une méthode qui utilise et modifie les données propres de l'objet. Quand la question demande un diagramme de classes, dessiner une boîte en trois parties (nom ; attributs avec - pour privé ; méthodes avec + pour public) et relier une sous-classe à son parent avec une flèche pointant vers le parent.

Programmation déclarative

En programmation déclarative 声明式编程, vous dites ce que calculer, pas comment — l'exécutant détermine les étapes. Deux sortes :

  • programmation fonctionnelle 函数式编程 — construite à partir de fonctions pures 纯函数 (pas d'effets secondaires 副作用 ; même entrée donne toujours même sortie) composées ensemble. Exemples : Haskell, Lisp.
  • programmation logique 逻辑编程 — définit des faits et des règles ; le moteur répond à un objectif (requête) par inférence. Exemple : Prolog.

Un exemple déclaratif familier est SQL 结构化查询语言 : SELECT * FROM Customer WHERE Country = 'UK' dit ce que vous voulez, pas comment parcourir les enregistrements.

Faits, règles et objectifs sont ce que l'examen teste dans le paradigme déclaratif. Étant donné ces faits 事实 (déclarations qui sont vraies) et une règle 规则 (une conclusion qui est vraie lorsque ses conditions sont remplies) :

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).

"Écrivez le résultat de l'objectif type(X, wild)" : X = leopard, X = lion. Le moteur fait correspondre l'objectif avec chaque fait à tour de rôle ; chaque correspondance est une solution, et une lettre majuscule est une variable que la correspondance remplit. "Écrivez un fait pour montrer qu'un guépard est sauvage" : type(cheetah, wild). "Expliquez ce que fait la ligne 07" : elle définit une règle dont la conclusion est dangerous(X), qui est vraie pour tout X qui est à la fois sauvage et grand, donc dangerous(A) retourne A = leopard, A = lion. "Écrivez une règle : une caractéristique F peut être disponible pour un style de carrosserie B si F est une caractéristique et B est un style de carrosserie et F n'est pas indisponible pour B" : may_be_available(F, B) IF feature(F) AND body_style(B) AND NOT unavailable(F, B). Copiez les noms de prédicat et l'ordre des arguments exacts utilisés dans les faits de la question ; un nouveau fait se termine par un point, et les conditions d'une règle sont jointes par AND.

Comparaison des paradigmes

Paradigme Force Langages typiques
Bas niveau contrôle maximal, vitesse assembleur
Impérative directe, intuitive C, Python
Orientée objet modulaire, modèle des entités Java, C#, Python
Fonctionnelle claire, sans effets secondaires Haskell, F#
Logique inférence, règles Prolog
Base de données requêtes sur données SQL

Les langages modernes mixent souvent les paradigmes — Python prend en charge tous ceux-ci : procédural, POO et fonctionnel. Le bon dépend du problème.

Explorer

Laboratoire de concepts de programmation

Reliez les exemples au concept de programmation qu'ils illustrent.

Vocabulaire Entrainer
Anglais Chinois 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ì
array/əˈreɪ/ 数组 shù zǔ
imperative programming/ɪmˈperətɪv ˈprəʊɡræmɪŋ/ 命令式编程 mìng lìng shì biān chéng
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

Traitement de fichiers

Programme
Les candidats doivent être capables de : Notes et orientations
Écrire du code pour effectuer des opérations de traitement de fichiers Ouvrir (en mode lecture, écriture, ajout) et fermer un fichier Lire un enregistrement depuis un fichier et écrire un enregistrement vers un fichier Effectuer des opérations de traitement de fichiers sur des fichiers série, séquentiels, aléatoires
Montrer la compréhension d'une exception et de l'importance de la gestion des exceptions Savoir quand il est approprié d'utiliser la gestion des exceptions Écrire du code de programme pour utiliser la gestion des exceptions

Source : Programme Cambridge International

Cela étend la gestion des fichiers 文件 depuis le Sujet 10, traitant des fichiers série, séquentiels et aléatoires (accès direct). Opérations en pseudocode : OPENFILE name FOR READ | WRITE | APPEND (READ ouvre un fichier existant, WRITE crée/supprime, APPEND ajoute à la fin) ; READFILE name, line ; WRITEFILE name, value ; CLOSEFILE name ; et EOF(name) qui est VRAI à la fin.

Lire un fichier entier :

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

Rechercher dans un fichier (s'arrêter quand trouvé) :

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"

Mise à jour d'un fichier in-place

La plupart des langages ne peuvent pas éditer un fichier texte in-place. Au lieu de cela : ouvrir l'original en READ et un fichier temporaire en WRITE ; pour chaque ligne, écrire la nouvelle version si elle doit changer, sinon l'originale ; fermer les deux ; puis remplacer l'original par le fichier temp. Ce même motif gère la suppression de lignes (les sauter) et l'insertion de lignes.

Mise à jour d'un fichier in-place : lire le fichier original, écrire les lignes modifiées vers un fichier temp, puis remplacer l'original par le fichier temp
Mise à jour d'un fichier in-place : lire l'original, écrire les modifications vers un fichier temp, puis remplacer l'original

Enregistrements et fichiers à accès aléatoire

Modes d'ouverture. READ : le fichier doit exister et la lecture commence au début. WRITE : un fichier nouveau est créé, et un fichier existant de ce nom est écrasé. APPEND : l'écriture ajoute à la fin d'un fichier existant. Tout fichier ouvert est fermé avec CLOSEFILE, et EOF(name) est TRUE quand le dernier élément a été lu.

Trois organisations de fichiers. Dans un fichier série, les enregistrements sont dans l'ordre où ils ont été ajoutés ; dans un fichier séquentiel, ils sont dans l'ordre de la clé ; les deux se lisent depuis le début. Un fichier aléatoire 随机文件 (fichier à accès direct) stocke chaque enregistrement à une adresse calculée à partir de sa clé via une fonction de hachage 哈希, donc un seul enregistrement est trouvé sans lire les autres. Les enregistrements sont déclarés comme un type défini par l'utilisateur :

TYPE AccountRecord
    DECLARE AccNo : INTEGER
    DECLARE Name : STRING
    DECLARE Balance : REAL
    DECLARE Active : BOOLEAN
ENDTYPE
Une clé 2317 hachée avec MOD 1000 vers l'adresse 317, puis SEEK et GETRECORD sur le fichier Acc.dat, représenté comme une rangée de cases d'enregistrement de taille égale avec la case 317 mise en évidence
Trouver un enregistrement dans un fichier aléatoire : la clé est hachée vers une adresse, le curseur du fichier saute directement vers cette case et l'enregistrement est lu ; aucun autre enregistrement n'est touché

Les opérations de fichier aléatoire en pseudocode sont OPENFILE "Acc.dat" FOR RANDOM, SEEK "Acc.dat", Address (déplacer le curseur du fichier vers cet enregistrement), GETRECORD "Acc.dat", Rec (lire l'enregistrement à cet endroit) et PUTRECORD "Acc.dat", Rec (écrire l'enregistrement à cet endroit). Trouver un client par numéro de compte, tel que défini dans 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"

Pour stocker un enregistrement, hachez sa clé, SEEK vers l'adresse et PUTRECORD, en passant devant toute case déjà occupée. Les marques vont au hachage, au SEEK avant le GET ou PUT, à la comparaison avec la cible, à la gestion d'une collision, et à la fermeture du fichier.

Exemple résolu. ActiveFile.dat contient AccountRecord enregistrements. Écrivez un pseudocode qui copie tous les enregistrements dont le champ Active est FALSE à la fin 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"

Fichiers texte en Python (Paper 4) : file = open("HighScore.txt", "r"), puis for line in file: avec line.strip() et line.split(",") pour séparer les champs, int(…) pour convertir une note, et file.close() ; pour écrire, open(name, "w") (ou "a" pour ajouter) et file.write(str(score) + "\n"). Une table des meilleurs scores est lue dans une liste d'enregistrements, la nouvelle note est insérée à sa place, et toute la liste est réécrite. L'examinateur marque l'ouverture avec le mode correct, une boucle qui lit chaque ligne, la conversion du texte en nombres, et la fermeture.

Pièges

Oublier de fermer un fichier (données peuvent être perdues) ; ouvrir en WRITE au lieu d'APPEND (écrase tout) ; lire au-delà de EOF ; chemins codés en dur — un chemin comme /Users/Admin/data.txt casse sur une autre machine, donc utilisez une constante relative telle que DataFile = "./data/scores.txt".

Explorer

Voie d'accès au fichier

Suivre un fichier depuis le stockage jusqu'au programme et retour en toute sécurité.

Vocabulaire Entrainer
Anglais Chinois 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

Gestion des exceptions

Une exception 异常 est une erreur ou une condition inattendue pendant l'exécution — division par zéro, fichier non trouvé, panne réseau, indice de tableau 数组 hors limites. La gestion des exceptions 异常处理 permet à un programme de la détecter et d'y répondre gracieusement au lieu de planter.

Cela importe parce que les vrais programmes font face à des erreurs qui ne peuvent pas être évitées à l'avance (fichiers déplacés, réseaux coupés, mauvaise saisie) ; sans cela, chaque opération nécessite sa propre vérification IF ; et cela sépare le flux normal de la gestion des erreurs, afin que le chemin principal reste clair. Par exemple, un fichier peut être supprimé par un autre utilisateur entre le moment où votre programme vérifie son existence et celui où il l'ouvre réellement — vous ne pouvez pas empêcher cela, seulement gérer l'échec quand il survient.

"Décrivez, avec un exemple, ce qu'est une exception (deux marks). Un événement inattendu ou une erreur qui survient pendant l'exécution d'un programme (à l'exécution) et interrompt son flux normal ; par exemple diviser par zéro, ouvrir un fichier qui n'existe pas, convertir une saisie non numérique en entier, un indice de tableau hors limites, ou épuiser la mémoire. "Identifier deux causes possibles d'exceptions" s'answer à partir de cette liste, plus "un périphérique ou un réseau n'est pas disponible" et "type de données invalide saisi".

"Énoncez les raisons d'inclure la gestion des exceptions (trois marks). Empêcher le programme de planter (se terminer inopinément) ; afficher un message significatif à l'utilisateur plutôt qu'une erreur système ; permettre au programme de se récupérer et de continuer, par exemple en demandant la saisie à nouveau, ou de fermer les fichiers en sécurité avant de se terminer ; et parce que certaines erreurs ne peuvent pas être prédites quand le programme est écrit. "Décrivez comment éviter la terminaison du programme due à une exception" : placer les instructions qui pourraient lever une exception dans un bloc TRY ; écrire un bloc EXCEPT (catch) pour cette exception qui la gère, par exemple en affichant un message, afin que l'exécution continue après le bloc au lieu de s'arrêter. "Expliquez ce qu'est la gestion des exceptions" : détecter une exception quand elle survient et exécuter du code (le gesteur) qui s'en occupe afin que le programme continue.

Motif

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

Le bloc TRY contient le code susceptible d'échouer ; le premier bloc EXCEPT correspondant s'exécute. Les vrais langages ont aussi un catch-all EXCEPT et un bloc FINALLY qui s'exécute qu'il y ait eu une exception ou non — utile pour le nettoyage (fermer les fichiers).

Flux d'exception : si le bloc TRY lève une exception, le contrôle passe au EXCEPT correspondant ; sans exception, il est ignoré. Dans les deux cas, le bloc FINALLY s'exécute, puis le programme continue
Flux d'exception : une exception passe au EXCEPT correspondant ; FINALLY s'exécute toujours avant que le programme ne continue

Lever une exception

Une sous-routine qui détecte une erreur peut lever 抛出 une exception afin que l'appelant la gère :

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

Où gérer les exceptions

Gérez-les près de l'erreur si la réponse est simple (un message, une rétentative), ou plus haut dans la pile d'appels 调用栈 si seul le code externe sait quoi faire (une boucle GUI de niveau supérieur log l'erreur et affiche une boîte de dialogue amicale). Ne jamais absorber silencieusement les exceptions — au moins loguez-les, sinon le débogage devient impossible.

Exceptions courantes : FileNotFound, IOError, DivisionByZero, IndexOutOfRange, InvalidArgument, NullReference, OutOfMemory. Envelopper chaque opération défaillante dans un TRY avec les gestionnaires EXCEPT appropriés permet d'obtenir un programme qui se dégrade gracieusement au lieu de planter.

Exemple résolu (Paper 4). Écrivez une fonction qui lit des nombres entiers, un par ligne, depuis un fichier dont le nom est passé en paramètre et les retourne dans une liste. Elle ne doit pas planter si le fichier n'existe pas ou si une ligne n'est pas un nombre entier.

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

Le bloc try contient le code susceptible de provoquer une erreur (l'ouverture et la conversion) ; chaque except nomme une exception spécifique et effectue une action utile ; la fonction retourne toujours une liste, permettant ainsi au programmeur appelant de poursuivre son exécution. En Java, la même structure correspond à try { … } catch (FileNotFoundException e) { … } catch (NumberFormatException e) { … } ; en VB.NET, elle correspond à Try … Catch ex As FileNotFoundException … End Try. Points attribués : les instructions risquées à l'intérieur du bloc try, les noms corrects des exceptions, un message pour chacune, et la poursuite de l'exécution du programme par la suite ; un bloc catch-all except: entraîne la perte de points pour le plantage, mais pas celle pour la mention « exception appropriée ».

Exemple résolu. Un fichier texte de membres nécessite la modification du numéro de téléphone d'un membre. Pourquoi le programme ne peut-il pas simplement écraser cette ligne, et quel est le motif ? Les lignes d'un fichier texte ont des longueurs différentes, et le fichier ne contient pas d'espaces pour absorber une différence : un remplacement plus long empiéterait sur l'enregistrement suivant, et un remplacement plus court laisserait une partie de l'ancienne ligne en arrière-plan. Le motif consiste donc à ouvrir l'original en mode READ (lecture) et un fichier temporary (temporaire) en mode WRITE (écriture), lire chaque ligne successivement, écrire la version new (nouvelle) pour la ligne modifiée et la ligne original (originale) pour toutes les autres, fermer les deux fichiers, puis replace (remplacer) l'original par le fichier temporaire. La même structure gère la suppression (sautez la ligne) et l'insertion (écrivez la ligne supplémentaire). Notez que every (chaque) ligne est écrite, pas seulement celle qui a changé - écrire uniquement le nouveau record et perdre le reste du fichier constitue une erreur classique.

Explorer

Comment la gestion des exceptions s'écoule

Passez en revue ce qui se passe quand le code échoue. L'exception saute hors du flux normal vers un handler, FINALLY nettoie des deux côtés, et le programme continue au lieu de planter.

Vocabulaire Entrainer
Anglais Chinois Pinyin
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

Définitions acceptées par l'examinateur

Une question de définition est notée selon un libellé fixe. Apprenez-les exactement et ne donnez qu'une seule réponse.

Terme Définition
paradigme de programmation un style ou une façon de programmer, avec sa propre méthode de structuration d'un programme
langage impératif le programme est une séquence d'instructions qui changent l'état du programme ; le programmeur décrit comment la tâche est réalisée
langage déclaratif le programme énonce des faits et des règles, et le moteur d'inférence détermine comment trouver la réponse
classe un modèle définissant les attributs et les méthodes des objets de ce type
objet (instance) une occurrence d'une classe, avec ses propres valeurs pour les attributs
attribut un élément de données appartenant à une classe
méthode une procédure ou une fonction appartenant à une classe et agissant sur ses attributs
encapsulation regrouper les attributs et les méthodes dans une classe et restreindre l'accès externe aux données, afin qu'elles soient modifiées uniquement via des méthodes publiques
héritage une sous-classe acquiert les attributs et les méthodes de sa classe parente et peut les ajouter ou les redéfinir
polymorphisme méthodes portant le même nom mais se comportant différemment selon les classes
constructeur une méthode qui s'exécute lors de la création d'un objet et initialise ses attributs
contenance une classe possède un objet d'une autre classe comme l'un de ses attributs
fait une affirmation dans un programme déclaratif qui est vraie
règle une conclusion qui est valide lorsque ses conditions sont remplies
fichier séquentiel, linéaire, aléatoire enregistrements dans l'ordre d'ajout ; enregistrements triés par clé ; chaque enregistrement à une adresse calculée à partir de sa clé
exception une erreur inattendue ou un événement pendant l'exécution qui interrompt le flux normal
gestion des exceptions détecter une exception lorsqu'elle survient et exécuter du code capable de la gérer afin que le programme poursuive son exécution
20.2

Conseils d'examen

  • Paradigmes : connaître la description en une ligne de chacun et être prêt à nommer le paradigme à partir d'un échantillon de code ; les questions de bas niveau portent sur les cinq modes d'adressage et ce que reçoit l'accumulateur.
  • Les définitions POO reviennent à chaque session : classe, objet, attribut, méthode, encapsulation, héritage, polymorphisme, constructeur. Écrire une classe en pseudocode avec des attributs PRIVATE (privés), un PUBLIC NEW (public) et des getters ; une sous-classe avec INHERITS (hérite) et SUPER.NEW.
  • Déclaratif : un objectif avec une variable retourne tous les faits correspondants ; une règle est une conclusion IF (si) les conditions sont réunies avec AND (et) ; copier exactement les noms de prédicat de la question.
  • Fichiers : les trois modes et ce que chacun fait à un fichier existant ; READFILE dans une boucle WHILE NOT EOF ; les fichiers aléatoires utilisent un hash, SEEK, GETRECORD et PUTRECORD, avec un risque de collision.
  • Exceptions : définition avec exemple, trois raisons de les gérer, et TRY avec un EXCEPT nommé permettant au programme de continuer.

Erreurs courantes

  • Décrire un programme déclaratif comme « une séquence d'étapes donnant la réponse » ; il énonce ce qui est vrai et ce qui est souhaité, pas comment.
  • Confondre un objet avec une classe, ou une instance avec un attribut ; la question « une occurrence d'un objet » attend « instance ».
  • Déclarer les attributs PUBLICS, ou y accéder depuis l'extérieur de la classe au lieu d'utiliser un getter, ce qui annule l'encapsulation.
  • Constructeur de sous-classe qui définit directement les attributs parents au lieu d'appeler SUPER.NEW.
  • Expliquer le polymorphisme comme « beaucoup d'objets » ; c'est le même nom de méthode se comportant différemment pour différentes classes.
  • Ouvrir un fichier FOR WRITE (pour écriture) pour ajouter un enregistrement, ce qui détruit le contenu existant ; utiliser APPEND (ajouter).
  • Lire un fichier aléatoire à partir du début ; faire un SEEK vers l'adresse hachée d'abord.
  • Placer le gestionnaire d'exception autour du code qui ne peut pas échouer, ou capturer tout sans message, ou décrire la gestion des exceptions comme « vérifier l'entrée avec IF ».

Leçons interactives sur ce sujet

Traversez-le étape par étape, avec des exercices à vérification instantanée.

Épreuves Passées

Plus de sujets dans Informatique A-Level

Se connecter ou créer un compte

IGCSE, A-Level & AP