我希望能够定义一个存在但不在子类或实例之间共享的类变量(在基类中以某种方式)。我最初尝试的是以下内容:
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
我理解为什么会发生这种情况(我期待与经验不同的是其他语言,但那很好)。
是否可以修改Base类(而不是子类)来获取子类,每个子类都有自己的类变量副本,并且子类的实例可以得到它们的classes变量的副本,然后可以独立修改也没有共享?
答案 0 :(得分:1)
首先,通过继承object:
开始使用new-style classesclass 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()
我们正在使用weakref作为类级属性,以确保在超类仍然在范围内时,子类可以正确地收集垃圾。
我们可以测试它是否有效:
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 = {}