In ruby, local variable references are only within the defined scope.
ruby
a = 1
def func
puts a
end
func #=> error (undefined local variable)
In python it can also be referenced from the offspring scope.
python
a = 1
def func():
print(a)
func() #=> 1
Furthermore, even if the defined scope disappears, the local variable will not be deleted as long as it is referenced from the offspring scope. You can also apply this property to create something like a class with instance variables. This class-like instance method-like is called a closure.
python
def cls(): #Class-like
x = {} #Instance variable-like
def a(): #Closure
x['a'] = 1
def b(): #Closure
x['b'] = 1
def g(): #Closure
return x
return a, b, g
#The scope of x disappears when the function call ends
a, b, g = cls()
a(); b();
print(g()) #=> {'a': 1, 'b': 1}
Even with ruby, if it is a constant, there is a closure. Before giving an example, let me explain a little about ruby.
In ruby, constants and variables are managed in completely different ways. The scope of variables changes depending on the function definition (not including do syntax etc.) and class definition. On the other hand, the scope of constants changes only in module definitions (including class definitions). And the search for constants
If a nest exists, this constant is searched sequentially within the elements of that nest. (From Automatic loading and reloading of constants)
It is done like this (however, in the case of open class, it is not searched). That is, the constant can also be referenced from the offspring scope.
You can use this property to make closures.
ruby
module A
X = 'x' #Instance variable-like
module B #Class-like
def show #Closure
puts X
end
end
end
class C #Instance-like
extend A::B
end
C.show #=> x
A reference to a local variable whose definition is missing may actually be an instance method call with no arguments. I meet really often.
ruby
class C
def hoge #Instance method
return "hoge"
end
def show
fuga = "fuga"
puts hoge #Instance method call
puts fuga #Local variable reference
end
end
In addition, the class macros attr_accessor, attr_reader, and attr_writer make it easy to create instance methods that look like local variables. The substance of the variable is an instance variable whose name is prefixed with @ in the argument symbol.
ruby
class C
attr_accessor :hoge #Instance variables@hoge is an entity
def initialize
self.hoge = "hoge" #Instance method hoge=Call
end
def show
fuga = "fuga" #Define local variable fuga&Initialization
puts hoge #Call instance method hoge
puts fuga #See local variable fuga
end
end
C.new.methods.include?(:hoge) #=> true
C.new.methods.include?(:hoge=) #=> true
In the case of python, it is easy to distinguish because the instance method call has self attached and the parentheses of the function call cannot be omitted. Instead, it's harder to distinguish between instance method calls and class method calls.
python
class C:
def hoge(self):
return "hoge"
@classmethod
def piyo(cls):
return "piyo"
def show(self):
fuga = "fuga"
print(self.hoge()) #Instance method call
print(fuga) #Local variable reference
print(self.piyo()) #Class method call
(Added based on comments from scivola)
When calling the instance method hoge = in the previous example, we specified self as the receiver.
ruby (repost)
class C
attr_accessor :hoge
def initialize
self.hoge = "hoge" #here
end
...
This is because if self is not specified, it will be treated as the definition of the local variable hoge.
ruby
class C
attr_accessor :hoge
def initialize
hoge = "hoge" #Definition of local variable hoge
end
def show
puts hoge
end
end
C.new.show #=> nil
The same can happen with python. For example, in the case of the class-like introduced earlier, the instance variable-like cannot be updated.
python
def cls():
x = {} #Behave like an instance variable
def u():
x = 'updated' #Actually, the definition of the local variable x
def g():
return x
return u, g
#The scope of x disappears when the function call ends
u, g = cls()
u();
print(g()) #=> {}
You can't omit self in python, so you won't make a mistake when updating instance variables.
python
class C:
def __init__(self):
self.hoge = "not updated"
def wrong(self):
hoge = "updated" #Easy to notice mistakes
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
You can do something similar with python.
python
class S:
def show(self):
print(self.message)
class C(S):
def __init__(self):
self.message = "accessible"
C().show() #=> accessible
In ruby, you can omit the parentheses of the function call. Therefore, you cannot assign a function to a variable.
ruby
def func
return "called"
end
a = func #Calling the function func
puts a #=> called
Object # method You can use an instance method to convert a function to a Method object and assign it to a variable.
ruby
def func
return "called"
end
a = method(:func) #Method object assignment
puts a #=> #<Method: main.func>
puts a.call #=> called
On the other hand, in python you can assign a function to a variable.
python
def func():
return "called"
a = func #Substitution of function func
print(func) #=> <function func at 0x...>
Recommended Posts