<! - * Génère également automatiquement le code source (Python) pour recevoir l'entrée->
Ceux qui veulent utiliser la fonction de génération automatique, ainsi que ceux qui veulent en savoir plus sur la programmation qui va un peu plus loin du pro de la concurrence Je pense que ce contenu peut être lu par ceux qui étudient l'orientation objet. Le code source complet peut être trouvé à [ici] 1.
Si vous préparez une telle macro d'entrée →
Int(N,2,5)
Float(a,1,100,5) Perm(1,N+4)
Str([a-z]{3,2*N})
*N(2)
L'entrée sortira →
output:
4
54.81887 3 2 4 7 1 8 5 6
yyl
4.32497 4 1 6 5 3 8 7 2
yziuqiac
42.84603 3 2 4 7 8 6 5 1
vsjajs
65.07176 7 5 8 3 4 6 1 2
rbq
Diverses autres choses
Graphique pondéré:
Int(N,3,5) Int(M,N-1,N*(N-1)//2)
Graph1(N,M,0,1000)
↓
output:
4 5
1 2 392
1 3 328
1 4 891
2 3 264
3 4 227
Chaîne:
Int(N,4,6) Int(M,4,6)
Str([.#]{M})
*N(1)
↓
output:
4 5
###.#
#.#.#
#..##
.###.
etc.
Si vous êtes intéressé par la fonction elle-même, vous pouvez trouver une liste dans [ici] 1.
<! - ## Ce que vous pouvez faire: générer automatiquement le code source pour recevoir l'entrée
Au lieu de cracher des entrées, vous pouvez également utiliser la fonction input () de Python pour générer du code source qui reçoit des entrées:
``` -->
* Puisque nous n'avons défini que la classe interne jusqu'à présent, si vous souhaitez générer un grand nombre de cas de test à la fois ou l'écrire dans un fichier, vous devez coder Python en utilisant cette classe.
## Méthode de réalisation
Il a une implémentation orientée objet.
Grossièrement
1. Classe responsable du chargement de la macro entière (LineCollection)
1. Classe (Ligne) responsable de la lecture de la macro ligne par ligne
1. La classe (Item et ses sous-classes) qui est responsable du délimiteur d'espace sur une ligne de la macro
Il est divisé en. C'est une image que je gère i + 1 et jette le travail nécessaire (i = 1,2).
Toutes les classes ont les méthodes suivantes en commun:
1. from_str (): Analyse la chaîne de macro d'entrée et initialise la classe.
1. generate (): génère un cas de test d'entrée aléatoire pour la plage qu'il gère.
En résumé, cela ressemble au tableau ci-dessous:
||LineCollection|Line|Item|
|---|---|---|---|
|from_str()|Chargement de la macro entière|Lire une ligne|Lire un mot|
|generate()|Génération de sortie pour toute la macro|Génération de sortie pour une ligne|Génération de sortie pour un mot|
<!-- |generate()/generate_source()|Génération de sortie pour toute la macro|Génération de sortie pour une ligne|Génération de sortie pour un mot| -->
Le point est
* Pour utiliser l'ensemble, LineCollection.from_str (macro d'entrée) → generate ()
<! - * Pour utiliser le tout, LineCollection.from_str (macro d'entrée) → generate () / generate_source () ->
* Si vous souhaitez augmenter le nombre de nouveaux types de macros, définissez simplement une sous-classe de la classe Item qui a les trois méthodes ci-dessus (pas besoin de changer Line ou LineCollection).
Quel endroit, comme.
## Code source
Plus précisément, nous vérifierons le code source.
LineCollection
||<font color=green> LineCollection|Line|Item|
|---|---|---|---|
|from_str()|<font color=green>Chargement de la macro entière</font>|Lire une ligne|Lire un mot|
|generate()|<font color=green>Génération de sortie pour toute la macro|Génération de sortie pour une ligne|Génération de sortie pour un mot|
<!-- |generate()/generate_source()|<font color=green>Génération de sortie pour toute la macro|Génération de sortie pour une ligne|Génération de sortie pour un mot| -->
self.ls a une liste de lignes pour chaque ligne de la macro.
C'est un peu compliqué de supporter des macros comme "* N (1)", mais ce que nous faisons est
* from_str () = Charger toute la macro: Initialisez la ligne correspondant à chaque ligne et mettez-la dans self.ls
* generate () = Générer une sortie pour toute la macro: Générer une sortie pour chaque ligne dans self.ls et la renvoyer avec un caractère de saut de ligne
seulement.
```python
class LineCollection:
def __init__(self, ls, s=None):
"""ls: list of Line
"""
self.ls = ls
self.s = s
@classmethod
def from_str(cls, s):
lines = s.split("\n")
i = 0
ls = []
for i in range(len(lines)):
if lines[i].startswith("*"):
name, num = lines[i][1:].split("(",1)
num = int(num[:-1])
ls.append((name, num))
else:
l = Line.from_str(lines[i])
ls.append(l)
return cls(ls, s)
def generate(self):
i = 0
prv = 0
output = []
while i<len(self.ls):
while i<len(self.ls) and not isinstance(self.ls[i], tuple):
i += 1
if i<len(self.ls) and isinstance(self.ls[i], tuple):
m, num = self.ls[i]
i += 1
else:
m = 0
num = 0
for j in range(prv, i-num-1):
if isinstance(self.ls[j], tuple):
continue
output.append(self.ls[j].generate())
if num!=0:
try:
m = Item.names[m]
except KeyError:
raise ValueError("Nombre indéfini de cas de test:La spécification du nombre de lignes à voir ci-dessus n'est-elle pas fausse?")
for _ in range(m):
for j in range(i-num-1, i-1):
if isinstance(self.ls[j], tuple):
continue
output.append(self.ls[j].generate())
prv = i
return "\n".join(output)
Line
LineCollection | Line | Item | |
---|---|---|---|
from_str() | Chargement de la macro entière | Lire une ligne | Lire un mot |
generate() | Génération de sortie pour toute la macro | Génération de sortie pour une ligne | Génération de sortie pour un mot |
self.l gère une liste d'éléments qui existent dans la ligne que vous regardez. Similaire à LineCollection,
Je fais ça. Là où nous lisons le nom de la classe et initialisons l'élément, nous obtenons l'objet de classe à partir de la fonction intégrée Python globals ().
def evaluate_item(ss):
cc, tmp = ss.split("(", 1)
vv = tmp[:-1]
return globals()[cc].from_str(vv)
class Line:
def __init__(self, l, s=None):
"""
correspond to a line of input file
l: list of Item
"""
self.l = l
self.s = s
@classmethod
def from_str(cls, s):
l = []
for ss in s.split():
l.append(evaluate_item(ss))
return cls(l)
def generate(self):
return " ".join([item.generate() for item in self.l])
Item
LineCollection | Line | Item | |
---|---|---|---|
from_str() | Chargement de la macro entière | Lire une ligne | Lire un mot |
generate() | Génération de sortie pour toute la macro | Génération de sortie pour une ligne | Génération de sortie pour un mot |
Enfin, Item, qui est défini pour chaque macro que vous souhaitez prendre en charge. Dans un tel cas, créer une classe de base et en hériter est supérieur en termes de lisibilité, maintenabilité et efficacité de codage. Nous avons préparé la classe Item comme classe de base comme suit:
class Item:
names = {}
def __init__(self, s=None, **keys):
self.s = s
@classmethod
def from_str(cls, s):
pass
def evaluate(self, s):
for k in Item.names.keys():
if k in s:
s = s.replace(k, str(Item.names[k]))
return eval(s)
def generate(self):
pass
def __str__(self):
if hasattr(self, "s"):
return self.s
L'objet est une classe qui ne peut pas être utilisée telle quelle, il est donc préférable de mettre un sort magique pour le représenter, mais cette fois, il est omis. Le simple fait de déclarer que vous disposez de ces méthodes présente de grands avantages, par exemple en facilitant la compréhension des autres lors de l'ajout de fonctionnalités.
En dessous, créez une classe pour chaque macro que vous souhaitez réaliser. Par exemple, Int
class Int(Item):
def __init__(self, name, low, high, s=None, **keys):
"""
correspond to the input value between two spaces
name: str
name of variable
low/high : str
min / max (inclusive)
"""
self.name = name
self.low = low
self.high = high
self.keys = keys
Item.__init__(self, s)
@classmethod
def from_str(cls, s):
name, low, high = s.split(",")
return cls(name, low, high, s=s)
def generate(self):
low, high = self.evaluate(self.low), self.evaluate(self.high)
value = utils.rng.integers(low, high+1)
Item.names[self.name] = value
return str(value)
Si l'ordre est 1 ... N
class Perm(Item):
"""permutation of [low, low+1, ..., high-1, high]
"""
def __init__(self, low, high, s=None):
self.low = low
self.high = high
self.s = s
@classmethod
def from_str(cls, s):
low, high = s.split(",")
return cls(low, high, s=s)
def generate(self):
low, high = self.evaluate(self.low), self.evaluate(self.high)
return " ".join(map(str, (utils.rng.permutation(high-low+1) + low).tolist()))
Il a la forme. Lorsque des nombres aléatoires sont nécessaires, ils sont jetés dans un randomiseur défini en externe:
utils.py
import numpy as np
SEED = 0
rng = np.random.default_rng(SEED)
Lors de l'utilisation de nombres aléatoires, il est correct de ne pas appeler la fonction à chaque fois, mais de préparer des correcteurs d'aléa (multiples si nécessaire) et de les utiliser correctement en fonction de la portée. Cependant, dans ce cas, cela dépend s'il est souhaitable de fixer le nombre aléatoire (pour obtenir la reproductibilité) ou de changer le résultat pour chaque exécution, il peut donc être nécessaire de le réécrire en fonction du cas d'utilisation. ..
Les autres macros seront prises en charge une par une de la même manière. Par exemple, s'il s'agit d'un graphe, il est réalisé à l'aide de fonctions telles que la génération de graphes aléatoires networkx, et s'il s'agit d'une chaîne de caractères, il est réalisé en utilisant des fonctions telles que la génération aléatoire d'une chaîne de caractères qui correspond au modèle d'expression régulière de rstr. Que faire de toute façon
C'est juste une question de mise en œuvre, donc l'effort pour ajouter des fonctions est réduit!
<! - * Génère également automatiquement le code source (Python) pour recevoir l'entrée->
TODO