Python 如何在类之间共享公共上下文?

Python 如何在类之间共享公共上下文?,python,class,overlapping-instances,Python,Class,Overlapping Instances,当前情景: context = get_context_from_some_method() A = a(context, 1) B = b(context, 2) C = c(context, 3) D = d(context, 4) . . . Z = z(context, 26) 我有一组类,它们都在构造函数中接受一个公共参数context,并且所有类都从一个公共基继承 class base: def common_method(self): pass cla

当前情景:

context = get_context_from_some_method()

A = a(context, 1)
B = b(context, 2)
C = c(context, 3)
D = d(context, 4)
.
.
.
Z = z(context, 26)
我有一组类,它们都在构造函数中接受一个公共参数
context
,并且所有类都从一个公共基继承

class base:
    def common_method(self):
        pass

class a(base):
    def __init__(self,context, aa):
        pass

class b(base):
    def __init__(self, context, bb):
        pass

# ...

class z(base):
    def __init__(self, context, zz):
        pass
在main中的用法:

context = get_context_from_some_method()

A = a(context, 1)
B = b(context, 2)
C = c(context, 3)
D = d(context, 4)
.
.
.
Z = z(context, 26)
问题:

context = get_context_from_some_method()

A = a(context, 1)
B = b(context, 2)
C = c(context, 3)
D = d(context, 4)
.
.
.
Z = z(context, 26)
  • 是否有一种巧妙的方法可以隐式地向所有类提供
    上下文
  • 我们有一个共同的基类,但我没有看到一个明显的方式让它为所有的类设置上下文
  • 可以假设我希望保持所有类实例的公共上下文
  • 只是一个随机的想法——元类能帮上什么忙吗
我知道这看起来很傻,但我只是想以某种方式消除冗余,这样我就可以以某种方式设置一个全局上下文并专注于我的对象

请建议一些解决方法?

**问题的最新情况**

我不能在基类中设置上下文,因为这将在web应用程序中使用。因此,许多具有不同上下文的页面将使用类结构。因此,如果我在base中设置了一个上下文,那么它将与另一个使用相同base的web页面实例所设置的上下文冲突。因为,在web应用程序中,上述所有类都将位于所有页面的公共内存中


您可以使用类变量:

base.context = 'context'
A = a(1)
B = b(2)
#...

您应该将上下文定义为base的类属性。修改您的示例将是:

class base:

    context = None

    def common_method(self):
        pass

class A(base):
    def __init__(self, aa):
        pass

class B(base):
    def __init__(self, bb):
       pass

.
.
.

class Z(base):
    def __init__(self, zz):
        pass

base.context = get_context_from_some_method()
A = a(1)
B = b(2)
Z = z(3)    

所有A、B和Z实例共享相同的上下文属性。

编辑:如果不想/不能使用类变量,最好使用工厂函数。使其成为基类上的静态方法或模块级函数

def make_instances(context, *instances):
    return [cls(context, *args) for cls, args in instances]

A, B, ..., Z = make_instances(get_context_from_some_method(), 
                 (a, (1,)), (b, (2,)), ..., (z, (26,)))

# or
instances = make_instances(get_context_from_some_method(), 
             zip(list_of_subclasses, ((x,) for x in range(1, 27))))
或者,我不知道这是否适用于您的情况,请使用模块级全局变量:

class z(base):
    def __init__(self, zz):
        self.zz = zz
        self.context = context

context = 'abc'
Z = z(26)

除了使用另一个答案中的类变量的建议外,我还建议您将上下文复制到实例上,以便以后可以在不影响已创建实例的情况下更改上下文

class base:
    context = None # if you want to be able to create without context.
    # just omit the previous line if you want an error
    # when you haven't set a context and you try to instantiate a subclass

class a(base):
    def __init__(self, aa):
        self.aa = aa
        self.context = self.context # sets an instance variable
        # so the class variable can be changed

class b(base):
    def __init__(self, bb):
        self.bb = bb
        self.context = self.context

base.context = 'context'

A = a(1)
B = b(2)

base.context = 'newcontext'

print A.context # context

消除冗余的方法是识别重复的模式,并将模式分解为一些单独的代码位

不确定这是否是您的真实代码,但从您的示例来看,模式是您正在以类似的方式实例化一整组类。即使从键入
上下文所需的每行中删除了9个字符,
,您仍在执行以下操作:

A = a(1)
B = b(2)
C = c(3)
...
这会让我发疯的。冗余的问题不在于键入,而是如果您想更改它(比如您想从0开始,或者您想为每个类添加一个额外的参数,或者其他什么),您必须更改每一行

所以我宁愿这样做:

classes = [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
instances = [cls(context, i) for i, cls in enumerate(classes, 1)]
在这里,我的代码清楚地表明我正在实例化一整组类,并且我正在向每个类传递上下文,以及一个从1到我拥有的类数的整数(每个类增加)。而且很容易独立决定更改类列表,或者更改传递给每个类的内容



这确实意味着我的实例的名称类似于
instances[0]
instances[13]
而不是
A
N
。这也是有办法的,但我发现很少实例化一个事物集合,然后将它们作为独立的个体事物而不是集合来使用。

你的意思是,比如,全局变量?!这在这里敲响了一些警钟。不是一个全局变量,我指的是对所有人来说有多普遍。随意调用它,它仍然是一个全局值,具有所有缺点(防止模仿,不能将不同的实例集与不同的上下文实例一起使用…)。您的更新使情况变得更糟。所以您想设置一些全局状态,然后创建一些实例,然后再次更改全局状态,以便将来的实例将使用不同的值?这不仅不是线程安全的,而且在以后的调试和维护中也是一场灾难。我强烈建议您保持当前的状态,通过构造函数明确地提供正确的上下文。@NiklasB。使用工厂函数,你不必重复你自己,也不会创建全局状态。比我要写的要好得多!为了完整性:每个实例都可以使用
self.context
访问该变量。这不是一个好主意,而是它回答了问题。这本身不允许您以后更改上下文,而是允许以前创建的实例维护以前的上下文。@agf:这不是一个要求。这个问题本身不是很明智,所以我不确定讨论这些细节有多明智。@Niklas B:对于新手来说,第一个答案并不完整,如果不修改类的定义,它就不起作用,设置后上下文属性也不存在。pablodcar:那么你应该写一条评论,而不是用完全相同的想法发布另一个答案。另外,你的代码包含很多不必要的空白。@ NIKLASB:那么你应该考虑答案的完整性,或者说明为什么有一个<代码>很多不必要的空白空间<代码>或者忽略它,然后说这只是一个复制品。你的第一条评论有很多不必要的词;)。我留下了一条评论,因为我不喜欢在没有留下解释的情况下进行向下投票,特别是对于新用户。我在编辑我的答案时也提到了这个选项。注意
enumerate
取一个
start
可选参数。@agf-Huh,我一直以为这是为了决定在序列中的哪个位置开始,而没有阅读文档来确认。谢谢@YugalJindle我添加了一个不使用全局状态的版本和一个使用模块级全局变量的版本。你没有得到我,
base。上下文在
a
之间可能会发生更改