我正在尝试在python中编写一个类对象,它具有能够修改私有字符串的闭包函数的属性,我理解大多数情况下的闭包但我不能让它与多个一起工作。我试图返回一个函数数组但我得到了
local variable 'string' referenced before assignment
向我表明字符串变量被破坏或者函数没有保持其闭包状态并且能够访问它。 get_val函数似乎工作,我尝试添加全局声明,但这不是问题,或者我无法正常工作。
class StringUpdater:
def _(self):
string = "MI"
def get_val():
return string
def add_u():
if string.endswith("I"):
string+="U"
def add_two_through_last():
string+=string[1:]
def replace_III_with_U():
#global string
string.replace("III", "U")
def remove_UU():
#global string
string.replace("UU", "")
return [get_val,add_u,add_two_through_last,replace_III_with_U,remove_UU]
def __init__(self):
str_obj = self._()
self.get_val = str_obj[0]
self.add_u = str_obj[1]
self.add_two_through_last = str_obj[2]
self.replace_III_with_U = str_obj[3]
self.remove_UU = str_obj[4]
f = StringUpdater()
print f.add_two_through_last()
print f.get_val()
答案 0 :(得分:1)
以下是如何以FP方式执行OO封装的方法。请注意,fp是一种不变性的艺术:
def encap_str(s):
def get():
return s
def append(s_):
return encap_str(s + s_)
def replace(s1, s2):
return encap_str(s.replace(s1, s2))
def encap(fname):
return {'get': get,
'append': append,
'replace': replace}[fname]
return encap
试验:
>>> o=encap_str('12345678')
>>> o('append')('90')('get')()
'1234567890'
>>> encap_str('aaabbbcccddd')('replace')('bbb', 'zzz')('get')()
'aaazzzcccddd'
了解更多信息,请参阅SICP,http://mitpress.mit.edu/sicp/full-text/book/book.html
以下是我的一些意见
python似乎并不鼓励你执行FP。你可能知道,python中的lambda
被削弱了,它并不意味着具有与普通函数相同的能力。腿部范围是必要的,但很烦人。所以如果你想了解FP,python不是一个好的平台。
进行比较,Perl
完全支持FP。以下是Perl
中的演示:
package OOinPerl;
sub new{
my $self=shift;
my $type=ref $self || $self;
#... somehow fetch the parameters from @_ and save in $a, $b and $c.
my $data={a=>$a,b=>$b,c=>$c}; #this is a hash table reference
my $this=sub{
my $field=shift;
$data->{$field}=shift if @_;
$data->{$field}
};
bless $this, $type
}
#... other functions
这里,对象实际上是lambda,lambda允许修改内部数据($data
)。但是,Perl
中的真实OO,说实话,很糟糕。
亲自向您推荐SML/NJ。
答案 1 :(得分:1)
您收到错误string referenced before assignment
的原因是add_u
内部您尝试通过string
运算符写入名为+=
的变量,因此Python是在add_u
内创建一个新的局部变量,该变量与_
中的变量不同。
这可以通过Python 3中的nonlocal
解决,但是如果你遇到Python 2,我只需要包装"外部"数组中的string
。我想说这是一个在Python中使用的相当常见的模式,但大多数时候Python并没有真正用于函数方式,尽管它完全能够实现闭包。
为了说明这是如何工作的,我简化了一些事情并抛弃了class
,制作了一个使用封闭字符串的函数字典。为了写到那个字符串,我把它粘在一个数组中:
def _mu():
data = ["MI"]
def rule1():
if data[0].endswith('I'): data[0] += 'U'
def rule2():
data[0] += data[0][1:]
def rule3():
data[0] = data[0].replace('III', 'U')
def rule4():
data[0] = data[0].replace('UU', '')
return {
'value': lambda: data[0],
'rule1': rule1,
'rule2': rule2,
'rule3': rule3,
'rule4': rule4}
mu = _mu()
我称之为mu
,因为这些规则可以识别为MU-Puzzle。
现在你可以写:
mu['value']() # => 'MI'
mu['rule1']()
mu['value']() # => 'MIU'
答案 2 :(得分:0)
此解决方案与Ray Toal's相同,但避免使用dict['key']
符号表示我认为更清晰的function.attribute
表示法。你可以通过(ab)使用function.attribute = value
我将使用Ray Toal的例子,以便您可以看到差异。
def _mu():
data = ["MI"]
def rule1():
if data[0].endswith('I'): data[0] += 'U'
def rule2():
data[0] += data[0][1:]
def rule3():
data[0] = data[0].replace('III', 'U')
def rule4():
data[0] = data[0].replace('UU', '')
_mu.value = lambda: data[0]
_mu.rule1 = rule1
_mu.rule2 = rule2
_mu.rule3 = rule3
_mu.rule4 = rule4
return _mu
mu = _mu()
mu.value() # => 'MI'
mu.rule1()
mu.value() # => 'MIU'
您重用_mu
来为其分配变量或函数,将其视为容器。对我来说,它似乎类似于self
变量的OOP使用。另请注意,如果需要,_mu.__dict__
可以像访问字典一样访问属性。
我对这与字典方法的性能了解不多,但这种方法可能是等效的,因为afaik属性存储在字典中。
最后,我不知道将属性分配给_mu
本身是否会产生某种问题,但如果确实如此,你可以添加一个虚函数作为container
,然后而不是分配给_mu
,而是分配给container
:
container = lambda: None
container.value = lambda: data[0]
container.rule1 = rule1
container.rule2 = rule2
container.rule3 = rule3
container.rule4 = rule4
return container