我希望能够定义一个存在的类变量(以某种方式在基类中),但不能在子类或实例之间共享。我最初尝试的操作如下:

from __future__ import print_function  # For lambda print()

class CallList(list):
    def __call__(self, *args, **kwargs):
        for f in self:
            f(*args, **kwargs)

class State:
    on_enter = CallList()
    def enter(self):
        self.on_enter()

class Opening(State): pass
class Closing(State): pass

Opening.on_enter.append(lambda: print('Opening state entered'))
Closing.on_enter.append(lambda: print('Closing state entered'))


但是子类和子类实例的行为是引用基类的类变量,这给了我以下内容:

opening = Opening()
closing = Closing()

opening.enter()
# Actual output:  Opening state entered
#                 Closing state entered
# Desired output: Opening state entered

opening.on_enter.append(lambda: print('Additional instance callback'))
opening.enter()
# Actual output:  Opening state entered
#                 Closing state entered
#                 Additional instance callback
# Desired output: Opening state entered
#                 Additional instance callback

closing.enter()
# Actual output:  Opening state entered
#                 Closing state entered
#                 Additional instance callback
# Desired output: Closing state entered


我知道为什么会这样(我原本期望与其他语言不同的是其他语言,但这很好)。

可以修改基类(而不是子类)以使每个子类具有各自的类变量副本,并且可以为子类的实例获取其类变量的副本,然后可以对其进行独立修改也没有分享?

最佳答案

首先,从对象继承开始使用new-style classes

class State(object):
    on_enter = CallList()
    def enter(self):
        self.on_enter()


旧式的课程太旧了,我在这里提出的建议是行不通的。

您的特定问题可以使用descriptors解决。正如您在文档中所看到的,描述符使我们能够覆盖特定属性(即它们所应用的属性)的属性访问。从类中读取属性时,这甚至是可能的。

import weakref

class CallListDescriptor(object):
    def __init__(self):
        self._class_level_values = weakref.WeakKeyDictionary()

    def __get__(self, instance, type):
        if instance is None:
            # class-level access
            try:
                return self._class_level_values[type]
            except KeyError:
                default = CallList()
                self._class_level_values[type] = default
                return default
        # instance-level access
        return instance._call_lists.setdefault(self, CallList())


class State(object):
    def __init__(self):
        # for the instance-level values
        self._call_lists = {}

    on_enter = CallListDescriptor()


我们将弱引用用于类级别的属性,以确保子类可以在超类仍在作用域内时正确地收集垃圾。

我们可以测试它是否有效:

class SubState(State):
    pass

class OtherSubState(State):
    pass

assert State.on_enter is State.on_enter
assert State.on_enter is not SubState.on_enter
assert State.on_enter is not OtherSubState.on_enter
assert SubState.on_enter is SubState.on_enter

instance = SubState()
assert instance.on_enter is not SubState.on_enter


但是,我建议摆脱子类功能,仅确保实例具有单独的值,然后将状态表示为State的实例而不是子类(除非您有充分的理由不这样做,否则可能是完美的):

class CallListDescriptor(object):
    def __get__(self, instance, type):
        if instance is None:
            return self

        return instance._call_lists.setdefault(self, CallList())

class State(object):
    def __init__(self):
        # for the instance-level values
        self._call_lists = {}

关于python - Python中的类变量和继承,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31559203/

10-12 21:19