如何在类之间链接像变量对象这样的Python公共变量?

发布于 2024-11-29 06:13:22 字数 1653 浏览 2 评论 0原文

我有一个关于对象之间的变量链接的问题。因为我是自学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)传输以由实例化对象修改(自加热器)?
  2. 如果 1 是,是否有任何技巧可以使公共变量(self.cereal)按预期工作?

I have a question regarding variable linking between objects. Because I'm learning Python programming by myself, I may have bad habits…

I am programming a module which will save me a lot of labor by managing by itself the standard configparser module. I just have to pass to it as an argument, the list of the application's variables, and just tell it "load()" and "save()" to let it do all the job automatically (create new config file, load values into variables, check updates, etc…).
It works perfectly with "true objects" like tkinter variables, but with variables containing simple numeric or string value, the value only is copied, not the object's "address".

Here's an example, it is an extremely simplified script focusing the problematic part but keeps the architecture of my module:

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()

There are now the questions:

  1. Is it ok to directly transfer objects as an argument (self.sauce) to be modified by the instanced object (self.heater)?
  2. If 1 is yes, is there any trick to make a common variable (self.cereal) to work as expected?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

や莫失莫忘 2024-12-06 06:13:22

正如您所怀疑的,数字和字符串是按值传递的,因此不能从其他函数/方法中修改它们。将值传递给另一个函数进行修改的最简单方法是将其放入容器(列表或字典)中,然后传递该容器。

As you suspected, numbers and strings are passed by value, so they cannot be modified from other functions / methods. The easiest way to pass a value to another function for modification is to put it in a container -- a list or a dictionary -- and pass that container instead.

汐鸠 2024-12-06 06:13:22

我确实没有查看您的代码,但实现此目的的常见方法是使用列表(或另一个可变容器)作为包装器。

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

I really didn't looked your code, but the common way to achieve this is using a list(or another mutable container) as a wrapper.

>>> def a(n):
...     n = 5
... 
>>> def b(n):
...     n[0] = 5
... 
>>> k = 3
>>> a(k)
>>> k
3
>>> k = [3]
>>> b(k)
>>> k[0]
5
谁把谁当真 2024-12-06 06:13:22

您遇到的问题不在于参数作为值传递。在 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

避免这种情况的经典构造是 do

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

,这有点冗长,但请记住函数应该有尽可能少的副作用。

这个解释已经在互联网上出现了,一篇很棒的文章讨论了“盒子”,并且比这更有启发。如果有人记得它在哪里...

编辑: 这里是,在代码中Python 达人

The issue you have is not with arguments being passed as values. In Python, arguments are passed by reference, so start.heater.ingredients_list[1]["ingredient"] is start.sauce.

The actual issue is with the assumption that item['ingredient'].set('caramel') is altering the value of start.sauce. It is not, it is setting start.heater.ingredients_list[1]["ingredient"] at the address of the string "caramel".

Long story short, you are doing this

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 classical construct to avoid that is to do

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

which is a bit verbose, but remember that functions should have as few side-effects as possible.

This explanation is already on the internet, on a great article that talked about "boxes" and was a lot more inspired than this. If someone remembers where it was...

Edit : Here it is, in Code Like a Pythonista

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文