这是我前几天解决的随机问题。给定以秒为单位的年龄,必须计算某人在特定星球上的年龄。我试图动态地向我的类添加新方法,并提出了这个解决方案:
class MyClass(object):
year_in_seconds_on_earth = 31557600
planets = {
'earth': 1,
'mercury': 0.2408467,
'venus': 0.61519726,
'mars': 1.8808158,
'jupiter': 11.862615,
'saturn': 29.447498,
'uranus': 84.016846,
'neptune': 164.79132
}
def __init__(self, seconds):
self.seconds = seconds
for planet in self.planets:
func = lambda: self._on_planet(planet)
self.__setattr__('on_' + planet, func)
# self._add_method(planet)
# def _add_method(self, planet):
# func = lambda: self._on_planet(planet)
# self.__setattr__('on_' + planet, func)
def _on_planet(self, planet):
return round(self.seconds / self.year_in_seconds_on_earth / self.planets[planet], 2)
print(MyClass(2134835688).on_mercury())
因此,当我从单独的方法(注释部分(调用lambda
和setattr
时,它工作得很好。但是当它们从__init__
调用时,只有最后一个值,海王星,在调用on_mercury
、on_mars
或其他类似方法时被使用。
我知道在__init__
中,它从外部函数的闭包中获取值,并且planet
s 的值在循环中更改。但我不太明白这两种情况下到底发生了什么。以下是一些问题:
- 它是传递给
_add_method
的行星变量的副本吗? - 为什么传递给
_add_method
的值没有改变,而是在直接在循环中传递时发生变化?
class MyClass(object):
year_in_seconds_on_earth = 31557600
planets = {
'earth': 1,
'mercury': 0.2408467,
'venus': 0.61519726,
'mars': 1.8808158,
'jupiter': 11.862615,
'saturn': 29.447498,
'uranus': 84.016846,
'neptune': 164.79132
}
def __init__(self, seconds):
self.seconds = seconds
for planet in self.planets:
func = lambda planet=planet: self._on_planet(planet)
self.__setattr__('on_' + planet, func)
def _on_planet(self, planet):
return round(self.seconds / self.year_in_seconds_on_earth / self.planets[planet], 2)
print(MyClass(2134835688).on_mercury())
可以在此处阅读为什么这样做的详细信息:Python lambda 与本地值的绑定
总之,python lambda只包含对外部变量的引用。如果值更改,变量也会更改。
通过使用外部变量的值定义局部变量(在本例中为 planet=planet
(,您可以在定义时将该值绑定到 lambda。