帮助Python继承

发布于 2024-11-09 13:39:14 字数 845 浏览 0 评论 0原文

给定一个任意对象:

class Val(object):
    def __init__(self):
        this_val = 123

我想创建一个抽象基类,它有一个 Val() 属性:

class A(object):
    foo = Val()

我希望当我的孩子从该类继承时,他们会获得 的副本>Val()。例如:

class B(A):
    pass
class C(A):
    pass

我期望出现以下行为:

>>> b = B()
>>> c = C()
>>> c.foo.this_val = 456
>>> b.foo.this_val
123

但是我得到:

>>> b.this_val
456

我知道我可以将 self.foo = Val() 放入 init 中来实现该行为,但我要求 foo 保留为一个属性(它是 django 中的模型管理器)。任何人都可以建议解决这个问题吗?

编辑:我确实需要能够将值作为类属性访问,所以我想要的行为是:

>>> C.foo.this_val = 456
>>> B.foo.this_val
123

Given an arbitrary object:

class Val(object):
    def __init__(self):
        this_val = 123

I want to create an abstract base class which has an attribute that is a Val():

class A(object):
    foo = Val()

I would expect that when my children inherit from that class, they would get copies of Val(). For example:

class B(A):
    pass
class C(A):
    pass

I would expect the following behavior:

>>> b = B()
>>> c = C()
>>> c.foo.this_val = 456
>>> b.foo.this_val
123

But instead I get:

>>> b.this_val
456

I understand that I could just self.foo = Val() into the init to achieve that behavior, but I have a requirement that foo remain an attribute (it is a model manager in django). Can anyone suggest a work around for this?

EDIT: I really need to be able to access the value as a class attribute, so my desired behavior is:

>>> C.foo.this_val = 456
>>> B.foo.this_val
123

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

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

发布评论

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

评论(3

橪书 2024-11-16 13:39:14

属性foo存在于A上。您必须使用元类向每个类添加新的 Val

class Val(object):
    def __init__(self):
        self.this_val = 123

class MC(type):
  def __init__(self, name, bases, d):
    super(MC, self).__init__(name, bases, d)
    self.foo = Val()

class A(object):
  __metaclass__ = MC

class B(A):
  pass

B.foo.this_val = 456
print A.foo.this_val
print B.foo.this_val

The attribute foo only exists on A. You will have to use a metaclass to add a new Val to each class.

class Val(object):
    def __init__(self):
        self.this_val = 123

class MC(type):
  def __init__(self, name, bases, d):
    super(MC, self).__init__(name, bases, d)
    self.foo = Val()

class A(object):
  __metaclass__ = MC

class B(A):
  pass

B.foo.this_val = 456
print A.foo.this_val
print B.foo.this_val
苍白女子 2024-11-16 13:39:14

也许使用 descriptor 会满足您的要求:

class Val(object):
    def __init__(self):
        self.this_val = 123

class ValDesc(object):
    def __init__(self):
        self.cls_lookup = {}

    def __get__(self, obj, objtype=None):
        return self.cls_lookup.setdefault(objtype, Val())

class A(object):
    foo = ValDesc()

class B(A):
    pass
class C(A):
    pass

现在,只要您确保您没有设置任何对象的实例属性“foo”,它们将具有每个子类各自的类属性:

b = B()
c = C()
cc = C()
c.foo.this_val = 456
print c.foo.this_val   # 456
print cc.foo.this_val  # 456
print b.foo.this_val   # 123

编辑:通过我几个小时前所做的编辑,更改了键入__get__objtype 而不是 obj.__class__,这在直接访问类属性时也有效:

print B.foo.this_val   # 123
print C.foo.this_val   # 456

Maybe using a descriptor would suit your requirements:

class Val(object):
    def __init__(self):
        self.this_val = 123

class ValDesc(object):
    def __init__(self):
        self.cls_lookup = {}

    def __get__(self, obj, objtype=None):
        return self.cls_lookup.setdefault(objtype, Val())

class A(object):
    foo = ValDesc()

class B(A):
    pass
class C(A):
    pass

Now, as long as you make sure you don't set the instance attribute "foo" of any of your objects, they will have a class attribute that is individual to each subclass:

b = B()
c = C()
cc = C()
c.foo.this_val = 456
print c.foo.this_val   # 456
print cc.foo.this_val  # 456
print b.foo.this_val   # 123

EDIT: With the edit I made some hours ago, changing the key in __get__ to be objtype instead of obj.__class__, this also works when accessing the class attributes directly:

print B.foo.this_val   # 123
print C.foo.this_val   # 456
偷得浮生 2024-11-16 13:39:14

两者都做。

将其设为类属性,同时在 __init__ 函数中将其初始化为新实例。这样,存储的引用就不是共享的。

Do both.

Make it a class attribute, but also initialize it to a fresh instance in the __init__ function. That way the reference stored isn't a shared one.

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