Как связать общие переменные Python, такие как объекты переменных, между классами? - PullRequest
2 голосов
/ 13 августа 2011

У меня вопрос по поводу связывания переменных между объектами. Поскольку я изучаю программирование на Python самостоятельно, у меня могут быть вредные привычки ...

Я программирую модуль, который сэкономит мне много труда благодаря самостоятельному управлению стандартным модулем configparser. Я просто должен передать ему в качестве аргумента список переменных приложения и просто сказать ему «load ()» и «save ()», чтобы позволить ему выполнять всю работу автоматически (создать новый файл конфигурации, загрузить значения в переменные, проверять обновления и т.д…). Он отлично работает с «истинными объектами», такими как переменные tkinter, но с переменными, содержащими простое числовое или строковое значение, копируется только значение, а не «адрес» объекта.

Вот пример, это чрезвычайно упрощенный скрипт, фокусирующий проблемную часть, но сохраняющий архитектуру моего модуля:

class Sauce:
    """Consider this class a Python standard module, so don't modify it."""
    def __init__(self, ingredient):
        self.ingredient = ingredient

    def set(self, result):
        self.ingredient = result

    def get(self):
        return self.ingredient

class Heater:
    def __init__(self, ingredients_list):
        self.ingredients_list = ingredients_list

    def heat(self):
        for item in self.ingredients_list:
            if item['type'] == 'sauce':
                item['ingredient'].set('caramel')
            elif item['type'] == 'cereal':
                item['ingredient'] = 'popcorn'

class Cooking:
    def __init__(self):
        self.cereal = 'corn'
        self.sauce = Sauce('sugarAndWater')
        print('We will cook these ingredients: {0} and {1}'.format(self.cereal, self.sauce.get()))
        print('After cooking we should theorically get "popcorn" and "caramel"')

        self.heater = Heater([{'type':'cereal', 'ingredient':self.cereal}, {'type':'sauce', 'ingredient':self.sauce}])
        self.heater.heat()

        print('But in reality we\'ve got:', self.cereal, self.sauce.get())

if __name__ == '__main__':
    start = Cooking()

Теперь есть вопросы:

  1. Можно ли напрямую передавать объекты в качестве аргумента (self.sauce) для изменения экземпляром объекта (self.heater)?
  2. Если 1 - да, есть ли способ заставить общую переменную (self.cereal) работать как положено?

Ответы [ 3 ]

0 голосов
/ 13 августа 2011

Как вы и предполагали, числа и строки передаются по значению, поэтому их нельзя изменить из других функций / методов. Самый простой способ передать значение в другую функцию для изменения - это поместить его в контейнер - список или словарь - и вместо этого передать этот контейнер.

0 голосов
/ 13 августа 2011

Проблема не в том, что аргументы передаются в качестве значений.В Python аргументы передаются по ссылке, поэтому start.heater.ingredients_list[1]["ingredient"] равно start.sauce.

Фактическая проблема заключается в предположении, что item['ingredient'].set('caramel') изменяет значение start.sauce.Это не так, это установка start.heater.ingredients_list[1]["ingredient"] по адресу строки "caramel".

Короче говоря, вы делаете это

a = "sugarAndWater"  # Put "sugarAndWater" in memory and assign its address to a
b = a                # Assign a to b, so b is the address of "sugarAndWater"
b = "caramel"        # Put "caramel" in memory and assign its address to b, don't alter a

Классическая конструкция, чтобы избежать этогосделать

a = ["sugarAndWater"]
b = a
b[0] = "sauce"

, что немного многословно, но помните, что у функций должно быть как можно меньше побочных эффектов.

Это объяснение уже есть в Интернете, в большой статье, котораяговорил о «коробках» и был намного более вдохновлен чем это.Если кто-то вспомнит, где это было ...

Редактировать: Вот оно , в Код, похожий на Pythonista

0 голосов
/ 13 августа 2011

Я действительно не смотрел ваш код, но обычный способ добиться этого - использовать список (или другой изменяемый контейнер) в качестве оболочки.

>>> def a(n):
...     n = 5
... 
>>> def b(n):
...     n[0] = 5
... 
>>> k = 3
>>> a(k)
>>> k
3
>>> k = [3]
>>> b(k)
>>> k[0]
5
...