Avez-vous déjà voulu échapper ** à la tâche d'écrire des vérifications et des conditions "None" pour toujours **?
None
en Python semble correspondre à null
et nil
dans d'autres langages, mais Python n'a pas d'opérateurs ou de méthodes qui facilitent la gestion ** Null, ce qui est courant dans d'autres langages ** ..
Puisqu'il n'y a aucune aide pour cela, j'ai décidé de remplacer les ** types standard 3 ** en écrivant ** fonctions **.
<détails> Je ne pouvais pas bien écrire et je me suis appuyé sur «N'importe» dans de nombreux endroits, mais j'ai aussi préparé un talon. <détails> "** Je veux récupérer la valeur d'une variable, mais si elle est Null, je veux donner une valeur par défaut **" L'opérateur ** Null coalescing ** répond à une telle demande. Dans les langages où l'opérateur de fusion Null peut être utilisé, il peut être écrit comme suit. Comme alternative à cela, j'ai créé une fonction ** Si vous essayez d'appeler directement un membre qui peut être Null (Nullable), vous obtiendrez une exception s'il est vraiment Null. "Je souhaite appeler un membre d'une instance ** Nullable. S'il est Null, la valeur de retour peut être Null **" Le ** opérateur d'appel sécurisé ** répond à une telle demande. Dans les langues où des opérateurs d'appels sécurisés sont disponibles, vous pouvez écrire: Comme alternative à cela, j'ai créé une fonction ** ** Si vous spécifiez plusieurs arguments **, donnez-les dans une liste, une touche ou un dictionnaire **. Lorsque vous appelez ** field ** au lieu de method, ** omettez ** le troisième argument. Si le troisième argument est omis pour une méthode, un objet fonction appelable est simplement renvoyé, donc lorsque vous appelez une méthode sans arguments, donnez une liste vide, un tapple ou un dictionnaire **. Selon la langue, la notation Les expressions qui prennent une valeur Nullable comme argument peuvent voler une exception si elle est vraiment Null. "Je veux évaluer une expression qui prend une valeur ** Nullable comme argument. Cette expression attend Non-Null, donc si elle est Null, la valeur de retour peut être Null **." Le ** système d'évaluation des expressions sûres ** répond à ces demandes. Dans le cas de Swift, les instances Nullable ont une méthode ** Dans le cas de Kotlin, il est réalisé en appelant en toute sécurité la méthode ** Comme alternative à ceux-ci, j'ai créé une fonction ** Bien entendu, la partie expression lambda peut être remplacée par une ** fonction définie **. Comme vous l'avez peut-être remarqué, la fonction Si l'argument positionnel et l'argument nom ne peuvent pas être donnés ensemble dans une liste ou un dictionnaire / si c'est difficile, la fonction S'il y a plusieurs variables Nullable, Tout d'abord, parce qu'il est implémenté de force par une fonction, ** le nombre de caractères augmentera inévitablement **. L'opérateur «??» est composé de 2 caractères, mais «qq (,)» est composé de 5 caractères. «?.» Etc. sont encore plus misérables à cause de citations inutiles. Une autre chose est que contrairement à l'opérateur **, il ne peut pas être incrusté **, donc la ** chaîne a l'air terrible **. Ci-dessous, un exemple de chaîne en Swift. C'est très rafraîchissant, mais quand j'essaye d'écrire la même chose avec la fonction que j'ai créée cette fois, ça devient comme ça. Ce n'est plus une chaîne mais un ** imbriqué, et je n'ai aucune idée de ce qui l'entoure. Trop terrible. Quand vous venez ici Ça a toujours l'air mieux. Si vous l'écrivez ainsi, c'est un peu plus facile à voir **.
Recommended Posts
nullutil.py
# Null Coalesce
# This means:
# lhs ?? rhs
def qq(lhs, rhs):
return lhs if lhs is not None else rhs
# Safty Access
# This means:
# instance?.member
# instance?.member(*params)
def q_(instance, member, params=None):
if instance is None:
return None
else:
m = getattr(instance, member)
if params is None:
return m
elif isinstance(params, dict):
return m(**params)
elif isinstance(params, list) or isinstance(params, tuple):
return m(*params)
else:
return m(params)
# This means:
# instance?[index]
def qL7(collection, index):
return collection[index] if collection is not None else None
# Safety Evalate (do Syntax)
# This means:
# params?.let{expression}
# do
# p0 <- params[0]
# p1 <- params[1]
# ...
# return expression(p0, p1, ...)
def q_let(params, expression):
if isinstance(params, dict):
for param in params.values():
if param is None:
return None
return expression(**params)
elif isinstance(params, list) or isinstance(params, tuple):
for param in params:
if param is None:
return None
return expression(*params)
else:
return expression(params) if params is not None else None
nullutil.pyi
from typing import TypeVar, Hashable, Mapping, MutableMapping, Sequence, MutableSequence, Any, Union, Optional, Callable, AnyStr
from typing import overload
T = TypeVar('T')
U = TypeVar('U')
H = TypeVar('H', Hashable)
SeqT = Union[Sequence[T], MutableSequence[T]]
MapT = Union[Mapping[H, T], MutableMapping[H, T]]
C = Union[list, tuple, dict]
# Null Coalesce
# This means:
# lhs ?? rhs
def qq(lhs: Optional[T], rhs: T) -> T: ...
# Safty Access
# This means:
# instance?.member
# instance?.member(*params)
def q_(instance: Optional[Any], member:AnyStr, params: Optional[Any]) -> Optional[Any]: ...
# This means:
# instance?[index]
@overload
def qL7(collection: Optional[SeqT], index: int) -> Optional[T]: ...
@overload
def qL7(collection: Optional[MapT], index: H) -> Optional[T]: ...
# Safety Evalate (do Syntax)
# This means:
# params?.let{expression}
# do
# p0 <- params[0]
# p1 <- params[1]
# ...
# return expression(p0, p1, ...)
@overload
def q_let(params: Optional[T], expression: Callable[[T], U]) -> Optional[U]: ...
@overload
def q_let(params: Optional[C], expression: Callable[..., T]) -> Optional[T]: ...
liste
Opérateur de coalescence nul
Pour Swift
foo = bar ?? default_value
Pour Kotlin
foo = bar ?: default_value
qq
**.guide = 'Mirai Hirano'
researcher = 'Kako Nanami'
curator = None
# print(guide ?? 'John Doe')
print(qq(guide, 'John Doe'))
# print(researcher ?? 'John Doe')
print(qq(researcher, 'John Doe'))
# print(curator ?? 'John Doe')
print(qq(curator, 'John Doe'))
Mirai Hirano
Kako Nanami
John Doe
Opérateur d'appel sécurisé
import numpy as np
import pandas as pd
np.random.seed(365)
score = np.clip(np.rint(np.random.normal(80., 15., 500)).astype(int), 0, 100)
mean = np.mean(score)
std = np.std(score)
mean_difference = score - mean
standard_score = mean_difference * (10. / std) + 50.
column_dict = {'Grades': score, 'Différence par rapport à la moyenne': mean_difference, 'Valeur d'écart': standard_score,}
column_list = ['Grades', 'Différence par rapport à la moyenne', 'Valeur d'écart',]
score_df = pd.DataFrame(column_dict)[column_list]
none_df = None
display(score_df.sort_values('Grades'))
display(none_df.sort_values('Grades'))
Grades
Différence par rapport à la moyenne
Valeur d'écart
249
34
-45.632
16.784097
82
36
-43.632
18.239913
89
36
-43.632
18.239913
372
41
-38.632
21.879453
112
42
-37.632
22.607361
...
...
...
...
197
100
20.368
64.826033
43
100
20.368
64.826033
337
100
20.368
64.826033
334
100
20.368
64.826033
280
100
20.368
64.826033
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-50-badfe23fbcf4> in <module>
1 display(score_df.sort_values('Grades'))
----> 2 display(none_df.sort_values('Grades'))
AttributeError: 'NoneType' object has no attribute 'sort_values'
Pour Swift
foo?.bar()
Pour Kotlin
foo?.bar()
q_
**.# display(score_df?.sortvalues('Grades'))
display(q_(score_df,'sort_values','Grades'))
# display(none_df?.sortvalues('Grades'))
display(q_(none_df,'sort_values','Grades'))
Grades
Différence par rapport à la moyenne
Valeur d'écart
249
34
-45.632
16.784097
82
36
-43.632
18.239913
89
36
-43.632
18.239913
372
41
-38.632
21.879453
112
42
-37.632
22.607361
...
...
...
...
197
100
20.368
64.826033
43
100
20.368
64.826033
337
100
20.368
64.826033
334
100
20.368
64.826033
280
100
20.368
64.826033
None
# score_df?.sort_values(by='Valeur d'écart', ascending=False)
q_(score_df, 'sort_values', {'by': 'Valeur d'écart', 'ascending': False})
# score_df?.index
q_(score_df, 'index')
# standard_score?.min()
q_(standard_score, 'min', ())
#Puisque None n'est pas appelable, la notation suivante peut provoquer des exceptions.
# q_(standard_score, 'min')()
? []
Existe également. J'ai également créé une fonction qL7
pour accéder aux éléments par des indices pour les listes, les dictionnaires et les tenseurs Numpy. ~~ J'ai rendu le nom de la fonction similaire à la notation générale, mais cela me donne l'impression qu'il est sur le point d'atteindre sa limite. ~~# standard_score?[5]
qL7(standard_score, 5)
Évaluation sûre des formules
import numpy as np
sequence = np.arange(0, 10)
none_array = None
print(sequence * 2)
print(none_array * 2)
[ 0 2 4 6 8 10 12 14 16 18]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-82-44094c5f4f90> in <module>
1 print(sequence * 2)
----> 2 print(none_array * 2)
TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'
map
**, qui peut être évaluée en toute sécurité en leur donnant une fermeture.Pour Swift
foo.map { $0 * 2 }
let
** de l'instance Non-Null.Pour Kotlin
foo?.let { it * 2 }
q_let
**.# print(sequence?.let { it * 2 } )
print(q_let(sequence, lambda it: it * 2))
# print(none_array?.let { it * 2 } )
print(q_let(none_array, lambda it: it * 2))
[ 0 2 4 6 8 10 12 14 16 18]
None
np.random.seed(365)
n01 = np.random.randn(10)
# n01?.let { np.mean(it) }
q_let(n01, np.mean)
q_let
est une alternative à ce que la fonction q_
peut faire.# score_df?.sort_values('Valeur d'écart', ascending=False)
# <=> score_df?.let { it.sort_values('Valeur d'écart', ascending=False) }
q_let(score_df, lambda it: it.sort_values('Valeur d'écart', ascending=False))
q_let
peut être utilisée à la place. Cependant, dans ce cas, la chaîne est très difficile à écrire, donc dans ce cas, il est plus facile d'utiliser la fonction q_
.map
et let
seront imbriquées et ce sera difficile. Haskell semble être capable d'écrire cela facilement en utilisant la notation do. Puisque la fonction q_let
est une fonction après tout, j'ai rendu possible de prendre une collection comme argument ** depuis le début.import math
r = 5
pi = math.pi
# r?.let { x -> pi?.let { y -> x**2 * y } }
q_let([r, pi,], lambda x, y: x**2 * y)
Faiblesses
foo?.bar()?.baz?.qux() ?? default_value
qq(q_(q_(q_(foo,'bar',()),'baz'),'qux',()), default_value)
if foo is None:
ret = default_value
else:
temp = foo.bar()
if temp is None:
ret = default_value
else:
temp = temp.baz
if temp is None:
ret = default_value
else:
temp = temp.qux()
ret = temp if temp is not None else default_value
qq(
q_(
q_(
q_(
foo, 'bar', ()
), 'baz'
), 'qux', ()
), default_value
)