2014-12-10 3 views
2

Я пытаюсь написать объект класса в python, который имеет атрибуты, которые являются функциями закрытия, способными модифицировать приватную строку, я понимаю, что закрытие по большей части, но я не могу заставить его работать с более чем один. Я пытаюсь вернуть массив функции, но я получаюЗакрытие с несколькими методами в 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

Вы считаете правильным закрыть. ваш код обычно должен работать на языках fp. эта раздражающая проблема вводится с помощью python legb scoping. – HuStmpHrrr

+0

см. Http://embrangler.com/2011/01/python-scoping-understading-legb/. точно такая же проблема. – HuStmpHrrr

+0

спасибо за статью, но я не думаю, что его решение работает для моей проблемы, его все еще не удается изменить исходную переменную – FFF

ответ

1

Причина вы получаете ошибку string referenced before assignment что внутри add_u вы пытаетесь записать в переменную с именем string через оператора +=, поэтому Python создает новую локальную переменную внутри add_u, которое отличается от переменной в _.

Это может быть разрешено nonlocal в Python 3, но если вы застряли с 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' 
+0

Что вы думаете об этом подход? https://stackoverflow.com/a/47766679/2647672 – JDG

1

следующее способ, как вы можете выполнить инкапсуляцию 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


Ниже некоторые из моих opnion

python, похоже, не рекомендует вам выполнять FP. как вы знаете, lambda в python ослаблен, он не должен иметь такую ​​же мощность, как и обычные функции. и прицеливание ногами является необходимым, но раздражающим. поэтому, если вы хотите понять FP, питон не является хорошей платформой.

сделать сравнение, 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 

здесь, объект на самом деле является лямбда, и лямбда позволяет модификацию внутренних данных ($data). но реальный OO в Perl, если честно, сосет.

лично рекомендует вам SML/NJ.

0

Это решение так же, как Ray Toal's, но сторонится dict['key'] обозначения для того, что я чувствую себя чище function.attribute нотации. Вы делаете это с помощью (ab), используя тот факт, что функциям python могут быть присвоены атрибуты с помощью function.attribute = value.

Я буду использовать пример Рэй Тоала, чтобы вы могли видеть разницу.

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. Также обратите внимание, что _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 
Смежные вопросы