【问题标题】:Initializing a class that consist of many classes in such a way that one of the classes has different attributes初始化一个由许多类组成的类,其中一个类具有不同的属性
【发布时间】:2015-04-22 17:43:33
【问题描述】:

以下是类及其关系:

http://i.imgur.com/HS5YrZZ.png

澄清代码:

class A(object):
    def __init__(self):
        self.atr = 1

class B(object):
    def __init__(self):
        self.atr = A()

class C(object):
    def __init__(self):
        self.atr = A()


class D(object):
    def __init__(self):
        self.atr1 = B()
        self.atr2 = C()


test1 = D()

现在,如果我想以 Aself.atr = 2 的方式初始化 D,并且该更改反映到所有使用 @ 的类(BC),我该怎么办当我初始化D时也是987654328@

就像我在伪代码中想象的那样:

test2 = D(A.self.atr = 2)

所以你初始化D 的方式是Aself.atr = 2

【问题讨论】:

  • 你没有。在良好的 OO 设计中,D 既不知道也不关心 BC 在其实现中使用 A。如果BC 需要修改他们的A 实例,他们将在自己的__init__ 中提供这样做的方法。就此而言,A 本身并没有提供在创建实例时为atr 指定值的方法。
  • 按照 chepner 的说法,唯一相似的可能是基类。 B 和 C 继承基类 A 的地方。那么它只是他们都拥有的属性。
  • @chepner 但是如果不允许这样做,你不会失去大量的效用吗?就像在我的例子中一样,如果 A 是一张卡片,B 是套牌,C 是玩家,D 是游戏,那么您可以轻松地生成 10 个游戏,每张卡片除了其他 9 个生成的游戏外,还具有独特的属性,因为当您生成 D(游戏)时,您可以通过更改卡片的类别(A),轻松地使游戏中的每张卡片具有独特的品质。我怎么能这样做?
  • 至少,您首先让A.__init__ 取一个值分配给atr,这样BC 可以在实例化A 时分别传递一个值。然后,对BC 执行相同的操作,以便D 在实例化BC 时可以传递一个值。
  • 如果你想要更好的建议,你将不得不想出一个更具体的例子。就目前而言,我只能重申我之前的 cmets 和 jsbueno 的回答。

标签: python class oop python-3.x


【解决方案1】:

如果您希望 B 和 C 具有不同的属性,如 D 的调用所要求的那样,实现此目的的方法是传递用于初始化 B 和 C 的参数,以便它们知道要做什么。

参数本身可以是A的一个实例,其中你关心的属性设置在inistantiatin B和C之前:

class A(object):
    def __init__(self, atr=1):
        self.atr = atr

class B(object):
    def __init__(self, config):
        self.atr = config

class C(object):
    def __init__(self, config):
        self.atr = config

class D(object):
    def __init__(self):
        my_a = A(2)
        self.atr1 = B(my_a)
        self.atr2 = C(my_a)

test1 = D()

更新 我从上面的 cmets 中看到,您似乎不喜欢这种方法,因为您的印象是到处都有很多重复的代码 - 然而事实并非如此——例如,如果你有很多类必须像 A 类一样“预配置”,并传递给许多其他类,你可以只创建一个包含所有预配置类的包——你' 仍然会将单个参数传递给您创建的每个实例。

此外,如您所愿,Python 中有一些机制允许动态重新配置类 - 使用“变量”作为其中之一 - 问题是,以您想要的这种幼稚的方式进行操作,您很快就会无法维护的混乱。

例如,如果您只是将模块级(= 全局)变量用于“1”而不是将其硬编码为 A,您可以这样做:

CURRENT_ATR_VALUE = 1
class A(object):
    def __init__(self):
        self.atr = CURRENT_ATR_VALUE

class B(object):
    def __init__(self):
        self.atr = A()

class C(object):
    def __init__(self):
        self.atr = A()


class D(object):
    def __init__(self, atr):
        global CURRENT_ATR_VALUE
        old = CURRENT_ATR_VALUE 
        CURRENT_ATR_VALUE = atr
        self.atr1 = B()
        self.atr2 = C()
        CURRENT_ATR_VALUE = old


test1 = D(atr=2)

这将产生您想要的确切效果,再简单不过了 - 不需要任何语言的高级自省功能,但仍然会很快导致您陷入无法维护的混乱局面。传递参数的方式确实包含所需范围内的自定义值,没有副作用,即使在多线程或多处理运行环境中也是如此,并且更值得推荐。

如果你真的想搞砸,你可以创建一个工厂函数,它会生成一个具有所需属性的 new 类“A”,并将其作为新的模块注入到模块全局命名空间中“A”类,而你实例化其他类 - 这将是“更漂亮”,也许是你想要的。只需在里面写 A :

def A_factory(atr=1):    
    class A(object):
        def __init__(self, atr=1):
            self.atr = atr
    globals()["A"] = A

# creates default "A" class
A_factory(1)

并在如上实例化“B”和“C”时使用所需的“atr”调用此工厂。这是绝对无法管理的,但它最终是你所要求的。 T

【讨论】:

  • 这里略有不同。在最初,BC 的实例都有自己的A 实例作为属性。在这里,他们共享一个实例。这是否重要取决于所涉及的实际类。
  • 确实 - 无论如何,如果这是所需的意图,此模型下的解决方案是为每个传递 A 实例的调用创建一个实例。
猜你喜欢
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多