简体   繁体   English

多个实例访问的Python类变量

[英]Python class variable accessed by multiple instances

I want to define a global variable which can be accessed (read and write) by all instances of the class. 我想定义一个全局变量,该类的所有实例都可以访问(读取和写入)。 My current solution is shown in the example below. 我当前的解决方案显示在下面的示例中。 I don't like having a variable in the global namespace, but I was not able to put idx in class. 我不喜欢在全局名称空间中使用变量,但是无法将idx放在类中。 How can I put idx in class and achieve the same? 如何将idx放在课堂上并实现相同的目标?

# working
idx = 0
class test(object):
    def add(self):
        global idx
        idx += 1
    def print_x(self):
        global idx
        print(idx)

test1 = test()
test1.add()
test1.print_x()
test2 = test()
test2.add()
test2.print_x()

# Error
class test(object):
    idx = 0
    def add(self):
        global idx
        idx += 1
    def print_x(self):
        global idx
        print(idx)

test1 = test()
test1.add()
test1.print_x()
test2 = test()
test2.add()
test2.print_x()

Traceback (most recent call last):
  File "test.py", line 16, in <module>
    test1.add()
  File "test.py", line 9, in add
    idx += 1
NameError: global name 'idx' is not defined

Your code fails because you tried to access a global variable idx without properly declaring it. 您的代码失败,因为您尝试在未正确声明的情况下访问全局变量idx You need to access your class variable. 您需要访问您的类变量。

class Test(object):
    idx = 0
    def add(self):
        Test.idx += 1

obj = Test()
obj.add()
print(Test.idx)
obj = Test()
obj.add()
print(Test.idx)

Output: 输出:

1
2

Here's a hacky little way that doesn't need any global variables. 这是一种不需要任何全局变量的小巧方法。 It makes use of the fact that default arguments are only created once when __init__ is called for the first time and if the default arguments are mutable, then changing one of them will impact all future functions/instances of the same class. 它利用了以下事实:默认参数仅在首次调用__init__时创建一次,并且如果默认参数是可变的,则更改其中一个将影响同一类的所有将来函数/实例。

We can create idx as a list since lists are mutable and then make sure we only modify that list in place. 由于列表是可变的,因此我们可以将idx创建为列表,然后确保仅在适当位置修改该列表。 Doing so like this will ensure that all instances of your Test class point to the exact same idx list. 这样可以确保Test类的所有实例都指向完全相同的idx列表。 Changing one changes them all, so long as you only do in-place modifications. 只要您只进行就地修改,更改一项就会全部更改。

class Test:
    def __init__(self, idx = [0]):
        self.idx = idx

    def add(self):
        self.idx[0] += 1

a = Test()
b = Test()

a.add()

print(a.idx, b.idx)
# >> Prints [1], [1]

You can achieve this using a singleton pattern. 您可以使用单例模式来实现。 Here is a small example with singleton: 这是一个单例的小例子:

class Singleton:
    # Here will be the instance stored.
    __instance = None

    @staticmethod
    def getInstance():
        """ Static access method. """
        if Singleton.__instance == None:
            Singleton()
        return Singleton.__instance

    def add(self):
        self.idx += 1

    def __init__(self):
        """ Virtually private constructor. """
        if Singleton.__instance != None:
            raise Exception("This class is a singleton!")
        else:
            Singleton.__instance = self
            self.idx = 0
In [3]: main = Singleton()
In [4]: a = Singleton.getInstance()
In [5]: print(a.idx)
0

In [6]: a.add()
In [7]: print(a.idx)
1

In [8]: b = Singleton.getInstance()
In [9]: print(b.idx)
1

Ref: https://www.tutorialspoint.com/python_design_patterns/python_design_patterns_singleton.htm 参考: https : //www.tutorialspoint.com/python_design_patterns/python_design_patterns_singleton.htm

There are some elegant Singleton examples on SO as well. 在SO上也有一些优雅的Singleton示例。

You have to define your variable in the class, outside of methods, and it shall not be a self variable. 您必须在方法之外的类中定义变量,并且该变量不得为自变量。 A self variable is unique to every instances. 自变量对于每个实例都是唯一的。 In methods you have to use the class name for accessing the variable, otherwise the method will look at it as a private variable, and in most cases you will get an error, because it was not initialized before usage. 在方法中,必须使用类名来访问变量,否则该方法会将其视为私有变量,并且在大多数情况下,您会得到一个错误,因为在使用前未对其进行初始化。

class MyClass:
    my_public_variable = 0
    __my_private_variable = 5

    def inc(self):
        MyClass.my_public_variable += 1
        MyClass.__my_private_variable += 1

    def show(self):
        print(MyClass.my_public_variable)
        print(MyClass.__my_private_variable)

obj1 = MyClass()
obj1.show()

obj2 = MyClass()
obj2.show()

obj1.inc()
obj2.show()

print(obj1.my_public_variable)
print(obj1.my_private_variable) # Invokes error

By running this code, the following will be printed out without the parenthesis: 通过运行此代码,将在不带括号的情况下打印出以下内容:

0  (my_public_variable of obj1)
5  (my_private_variable of obj1)
0  (my_public_variable of obj2)
5  (my_private_variable of obj2)
1  (my_public_variable of obj2, incremented by obj1)
6  (my_private_variable of obj2, incremented by obj1)
1  (my_public_variable of obj1, it can be accessed outside of the class, since it is a public variable of the class)
Error (because, as its name suggests, my_private_variable is a private variable of the class)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM