Cet article est l'article du 9ème jour du DSL Advent Calendar 2019. Dans la continuité de l'article du 8ème jour, nous parlerons de la conférence "Introduction à la programmation" dans notre université.
Je fais de l'AT dans cette conférence, mais en bref, il y a des devoirs, comme des devoirs hebdomadaires aux étudiants et la fin de la conférence de la semaine prochaine. Les assistants techniques sont chargés de noter le devoir chaque semaine. Au début, le contenu de la tâche est simple avec seulement un programme simple, mais à mesure que le nombre de fois augmente, le contenu et la comparaison avec la sortie deviennent plus compliqués, j'ai donc créé un système de notation qui fonctionne sur Python.
"** Laissez Python faire les choses ennuyeuses **".
Il est possible de répondre aux affectations avec jupyter notebook. Il est distribué au format .ipynb et contient des cellules pour les questions et réponses, vous pouvez donc y écrire le code et vérifier si le résultat est correct. Fondamentalement, il vous dit de ne modifier que le contenu de la cellule de code et de vérifier le résultat, afin que vous puissiez toujours obtenir des points simplement en vérifiant la sortie d'une cellule spécifique.
Vous trouverez ci-dessous une image qui reproduit facilement la tâche afin que vous puissiez avoir une image.
J'ai rendu le problème très simple, mais il ressemble à ceci.
Tout d'abord, sur les critères de notation. Cela changera en fonction de chaque tâche et problème, mais il y a trois critères généraux ci-dessous.
Les premier et deuxième critères restent les mêmes, mais le troisième "grammaire et syntaxe spécifiées" est le "pour" et le "si" que vous avez appris cette semaine. (La structure du programme n'est pas spécifiée à chaque fois)
Les réponses aux affectations et aux critères de notation seront distribuées à l'AT à l'avance. Environ 20 personnes ont répondu à ipynb pour chaque TA, l'ouvrent sur le notebook Jupyter, vérifient chaque code source, sortent le résultat et la réexécution, et écrivent le résultat de la notation dans la colonne d'évaluation. Actuellement, le score maximum est de 4, et vous pouvez en vérifier environ 4 pour chacun, mais je n'ai pas pu faire ce travail, j'ai donc créé un script. (Parce que le système d'un certain II n'est pas un laboratoire mais un cahier, il était difficile d'ouvrir beaucoup d'onglets, d'attendre la communication et de réévaluer la cellule)
Voici quoi faire
re
et l'évaluation ʻexec ()`Je vais expliquer chacun d'eux avec le code source.
Utilisez pathlib, un module Python standard.
import pathlib
# path to notebook(.ipynb)
p_nb = pathlib.Path("../path/to/notebook/")
Puisque le contenu d'ipynb est json, vous pouvez l'analyser avec json.load ()
.
Il utilise également la méthode glob, qui gère bien pathlib lors de la boucle sur tout ipynb.
import json
# notebooks(.ipynb)
for _nb in p_nb.glob("*.ipynb"):
# load json (*.ipynb)
with open(_nb, "r")as f:
nb = json.load(f)
cells = nb["cells"]
Je vais omettre l'explication détaillée de la structure d'ipynb, mais puisque les informations de cellule sont comme {" cellule ": [cellule1, cellule2, cellule3], ...}
, nb [" cellules "] Vous pouvez obtenir la liste avec
.
Veuillez noter que le code source après cela est dans un état où le retrait est abaissé d'une étape, mais il est omis.
Le contenu de la cellule est à peu près comme suit.
--cell_type: 'markdown', 'code', etc. --source: texte de démarque, code source, etc. (liste ligne par ligne) --outputs: résultats de sortie du code source (y compris les erreurs)
D'autres informations sont incluses, mais les trois ci-dessus sont utilisées dans ce système.
Maintenant, spécifiez la cellule de la réponse. ** Cette fois, le code source est écrit pour être comparable à l'ipynb donné ci-dessus à titre d'exemple. ** ** Puisqu'il est utilisé jusqu'à 4 fois en un seul scoring, il est fonctionnalisé.
def identify_cell(sentence, cells, cell_type='markdown'):
"""Renvoie les numéros de cellule qui correspondent aux conditions de toutes les cellules"""
for i,_cell in enumerate(cells):
if _cell['cell_type'] == cell_type \
and _cell['source'][0] == sentence:
_cell_num = i
break
return _cell_num
# identify cell
_cn = identify_cell(sentence="##question 1\n",
cells=cells)
ans_cell = cells[_cn + 1]
ʻIdentify_cell () `vérifie Le cell_type est markdown et la première ligne de la source est "## Q1 \ n". Le numéro de cellule qui correspond aux conditions ci-dessus est renvoyé par retour.
De là, il est bon de vérifier le contenu de la cellule en utilisant pprint ()
etc.
Il convient de noter que la réponse est le code source et son résultat de sortie, de sorte que la cellule suivante, la cellule _cn + 1
th, est stockée dans la variable en tant que cellule de réponse.
Envoyez la première question "Hello World!". Vérifions l'exactitude du problème. Cette fois, il vous suffit de vérifier si le résultat de la sortie est correct, c'est donc comme suit.
try:
result = ans_cell['outputs'][0]["text"][0]
if result == "Hello World!":
score += 1
except:
pass
Au fait, try-except est utilisé car il correspond au cas où la tâche est sans réponse. (Il n'y a pas de contenu dans les sorties) C'était correct de le gérer si, mais quand j'ai vu de nombreuses réponses, des erreurs ont été lancées à divers endroits, alors j'ai fait un compromis avec cela.
Dans le code source actuel qui est réellement en fonctionnement, cela fonctionne simplement en changeant le chemin et cette partie chaque semaine. Les modèles de réponse et les notes sont répertoriés séparément au bas de l'article.
À l'origine, il est correct d'écrire autre chose que le score parfait, mais j'ai fait les spécifications telles qu'elles sont maintenant parce que j'ai fait un commentaire séparé pour ceux qui ont une mauvaise réponse vérifier la réponse ipynb juste au cas où.
if score == 2: #Score parfait=En cas de 2 points
# identify cell
_cn = identify_cell(sentence="##Évaluation\n",
cells=cells)
#Écraser la cellule de score
cells[_cn + 1] = {'cell_type': 'code',
'execution_count': None,
'metadata': {},
'outputs': [],
'source': [str(2)]}
#Dump sur ipynb pour réponse(Écraser)
json.dump(nb, _nb.open("w"))
Cela a été fourni par une personne qui fait également de l'AT dans notre laboratoire (@y_k).
Quant au contenu du programme, seulement lorsque le score est parfait, la cellule où le résultat de l'évaluation est entré est écrasée par le numéro de score parfait, et ipynb est sauvegardé. Cependant, si vous écrasez le mauvais, ce sera gênant, donc dans l'environnement de production, nous avons également un script pour sauvegarder l'ipynb d'origine.
Voici quelques éléments à garder à l'esprit lors de la vérification de la réponse. En plus de ceux listés, si vous êtes débutant en programmation, vous lancerez diverses balles à langer, donc c'est plutôt difficile.
print ()
et la sortie avec seulement des variables qui peuvent être utilisées avec ipython.Même avec cela seul, le contenu des "sorties" est différent, donc le programme changera considérablement, donc c'est assez difficile.
C'est également assez difficile, et quand il y a quelque chose qui doit être réévalué dans les critères d'évaluation
J'utilise ʻexec (script) (script est le code source de str) pour vérifier le résultat, mais
print () ʻin script n'est pas affiché sur le notebook jupyter, et il est assez difficile d'obtenir la sortie. J'ai écrit un programme qui écrase la sortie standard, mais je ne le recommande pas beaucoup (car print () à l'heure normale n'est pas non plus affiché). Je publierai le code source pour le moment.
import sys
import io
import contextlib
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = io.StringIO()
sys.stdout = stdout
yield stdout
sys.stdout = old
#Courir
try:
with stdoutIO() as s:
exec(script)
#Imprimer ci-dessous()Obtenez la sortie de
output = s.getvalue().split()
except:
#En cas d'erreur de script sauf
pass
S'il y a un symbole ou un nombre pleine largeur dans la réponse, il ne correspondra pas à la bonne réponse et sera traité de manière incorrecte. Par conséquent, ce sera un peu plus facile si vous convertissez le résultat de sortie en demi-largeur à l'avance.
def trans_hankaku(sentence: str) -> str:
"""Fonction pour convertir les caractères pleine largeur en caractères demi-largeur"""
return sentence.translate(
str.maketrans(
{chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}
))
Il peut être plus facile de définir une fonction qui se convertit en demi-largeur comme décrit ci-dessus.
Cette fois, j'ai pu pratiquer "Laisser Python faire les choses ennuyeuses"! (Je n'ai jamais lu) J'espère que l'article d'aujourd'hui aidera quelqu'un ainsi que celui d'hier article DSL Advent Calendar Day 8.
Le code source et ipynb utilisés cette fois sont ici. https://github.com/liseos-x140/scoring_ipynb
La structure d'ipynb générée peut différer selon la version et le type de jupyter, je vous serais donc reconnaissant de bien vouloir l'utiliser comme référence uniquement. De plus, le code source est encore au stade de développement, j'espère donc le mettre à jour à nouveau dès qu'il sera organisé dans une certaine mesure.
https://www.oreilly.co.jp/books/9784873117782/
Recommended Posts