Dans ruby, les références de variables locales sont uniquement dans la portée définie.
ruby
a = 1
def func
puts a
end
func #=> error (undefined local variable)
En python, il peut également être référencé à partir de la portée descendante.
python
a = 1
def func():
print(a)
func() #=> 1
De plus, même si la portée définie disparaît, la variable locale ne sera pas supprimée tant qu'elle est référencée à partir de la portée descendante. Vous pouvez également appliquer cette propriété pour créer quelque chose comme une classe avec des variables d'instance. Cette instance semblable à une méthode s'appelle une fermeture.
python
def cls(): #Comme une classe
x = {} #Instance de type variable
def a(): #Fermeture
x['a'] = 1
def b(): #Fermeture
x['b'] = 1
def g(): #Fermeture
return x
return a, b, g
#La portée de x disparaît lorsque l'appel de fonction se termine
a, b, g = cls()
a(); b();
print(g()) #=> {'a': 1, 'b': 1}
Même avec le rubis, si c'est une constante, il y a une fermeture. Avant de donner un exemple, laissez-moi vous expliquer un peu rubis.
Dans ruby, les constantes et les variables sont gérées de manière complètement différente. La portée des variables change en fonction de la définition de la fonction (sans inclure la syntaxe do, etc.) et de la définition de la classe. D'autre part, la portée des constantes ne change que dans les définitions de module (y compris les définitions de classe). Et la recherche de constantes
Si un nid existe, cette constante sera recherchée séquentiellement dans les éléments de ce nid. (Depuis Chargement et rechargement automatique des constantes)
C'est fait comme ça (cependant, dans le cas d'une classe ouverte, elle n'est pas recherchée). Autrement dit, les constantes peuvent également être référencées à partir de la portée descendante.
Vous pouvez utiliser cette propriété pour effectuer une fermeture.
ruby
module A
X = 'x' #Instance de type variable
module B #Comme une classe
def show #Fermeture
puts X
end
end
end
class C #Comme une instance
extend A::B
end
C.show #=> x
Une référence à une variable locale dont la définition est manquante peut en fait être un appel de méthode d'instance sans argument. Je me rencontre très souvent.
ruby
class C
def hoge #Méthode d'instance
return "hoge"
end
def show
fuga = "fuga"
puts hoge #Appel de méthode d'instance
puts fuga #Référence de variable locale
end
end
De plus, les macros de classe attr_accessor, attr_reader et attr_writer facilitent la création de méthodes d'instance qui ressemblent à des variables locales. La substance de la variable est une variable d'instance dont le nom est précédé de @ dans le symbole d'argument.
ruby
class C
attr_accessor :hoge #Variable d'instance@hoge est la substance
def initialize
self.hoge = "hoge" #Méthode d'instance hoge=Appel
end
def show
fuga = "fuga" #Définir la variable locale fuga&Initialisation
puts hoge #Appelez la méthode d'instance hoge
puts fuga #Voir la variable locale fuga
end
end
C.new.methods.include?(:hoge) #=> true
C.new.methods.include?(:hoge=) #=> true
Dans le cas de python, il est facile de le distinguer car l'appel de méthode d'instance est auto-attaché et les parenthèses de l'appel de fonction ne peuvent pas être omises. Au lieu de cela, il est plus difficile de faire la distinction entre les appels de méthode d'instance et les appels de méthode de classe.
python
class C:
def hoge(self):
return "hoge"
@classmethod
def piyo(cls):
return "piyo"
def show(self):
fuga = "fuga"
print(self.hoge()) #Appel de méthode d'instance
print(fuga) #Référence de variable locale
print(self.piyo()) #Appel de méthode de classe
(Ajouté en fonction des commentaires de scivola)
Lors de l'appel de la méthode d'instance hoge = dans l'exemple précédent, self a été spécifié comme récepteur.
rubis (republier)
class C
attr_accessor :hoge
def initialize
self.hoge = "hoge" #ici
end
...
En effet, si vous ne spécifiez pas self, il sera traité comme la définition de la variable locale hoge.
ruby
class C
attr_accessor :hoge
def initialize
hoge = "hoge" #Définition de la variable locale hoge
end
def show
puts hoge
end
end
C.new.show #=> nil
La même chose peut arriver avec python. Par exemple, dans le cas du type de classe introduit précédemment, le type de variable d'instance ne peut pas être mis à jour.
python
def cls():
x = {} #Se comporter comme une variable d'instance
def u():
x = 'updated' #En fait, la définition de la variable locale x
def g():
return x
return u, g
#La portée de x disparaît lorsque l'appel de fonction se termine
u, g = cls()
u();
print(g()) #=> {}
Vous ne pouvez pas vous omettre en python, vous ne ferez donc pas d'erreur lors de la mise à jour des variables d'instance.
python
class C:
def __init__(self):
self.hoge = "not updated"
def wrong(self):
hoge = "updated" #Erreurs faciles à remarquer
def correct(self):
self.hoge = "updated"
def show(self):
#print(hoge) #=> error (name 'hoge' is not defined)
print(self.hoge)
c = C()
c.wrong(); c.show(); #=> not updated
c.correct(); c.show(); #=> updated
ruby
module M
def show
puts @message
end
end
class C
include M
def initialize
@message = "accessible"
end
end
C.new.show #=> accessible
Vous pouvez faire quelque chose de similaire avec python.
python
class S:
def show(self):
print(self.message)
class C(S):
def __init__(self):
self.message = "accessible"
C().show() #=> accessible
Dans ruby, vous pouvez omettre les parenthèses de l'appel de fonction. Par conséquent, il n'est pas possible d'affecter une fonction à une variable.
ruby
def func
return "called"
end
a = func #Appelez la fonction func
puts a #=> called
Méthode Object # Vous pouvez utiliser la méthode d'instance pour convertir une fonction en objet Method et l'assigner à une variable.
ruby
def func
return "called"
end
a = method(:func) #Affectation d'objet de méthode
puts a #=> #<Method: main.func>
puts a.call #=> called
D'autre part, en python, vous pouvez affecter des fonctions à des variables.
python
def func():
return "called"
a = func #Affectation de la fonction func
print(func) #=> <function func at 0x...>
Recommended Posts