【问题标题】:Make a hashable id for all subclasses of base class为基类的所有子类创建一个可散列的 id
【发布时间】:2013-03-17 16:59:34
【问题描述】:

出于缓存/持久性的原因,我希望为基类的任意大的子类树(永远不会自行创建)获取唯一的可哈希地址。以下是目前的情况:

OBJECT_CACHE = dict()

class Base(object):
    def __new__(cls, *args, **kwargs):
        # calculate class_addr here?
        obj = OBJECT_CACHE.get(class_addr)
        if obj is None:
            obj = super(Base, cls).__new__(cls, *args, **kwargs)
            OBJECT_CACHE[class_addr] = obj
        return obj

但我不确定获得这样一个 id 的最佳方法是什么。我的概念是它看起来像下面这样:

Base:          # no id
    F          # id = 'f'
    A:         # id = 'a'
        E      # id = 'a.e'
        B:     # id = 'a.b'
            C  # id = 'a.b.c'
            D  # id = 'a.b.d'

我曾考虑尝试使用属性和super(),但理想情况下,子类将只包含像my_id = 'e' 这样的单行。提前致谢!

【问题讨论】:

  • 为什么不直接使用类对象本身呢?
  • @delnan 如果我明白你的意思,主要是因为默认哈希值与对象内存地址相关联——如果脚本停止并重新启动,这会改变。 (OBJECT_CACHE 可以腌制保存)
  • 不,它存储类名和模块名,并检索存储在具有该标识符的该名称的模块中的任何内容。试试看:class C(object): pass 后跟 import pickle; s = pickle.dumps({C: 1}); C = 'foo'; print pickle.loads(s)
  • 啊,好点子。我确实希望能够引用我注意到的符号中的对象(我最终没有使用 class.__name__,而是使用不同的属性)

标签: python oop inheritance


【解决方案1】:

你要找的是cls.mro():

OBJECT_CACHE = dict()
class Base(object):
    def __new__(cls, *args, **kwargs):
        class_addr = cls.name()
        obj = OBJECT_CACHE.get(class_addr)
        if obj is None:
            obj = super(Base, cls).__new__(cls, *args, **kwargs)
            OBJECT_CACHE[class_addr] = obj
        return obj
    @classmethod
    def name(cls):
        names = [k.__name__.lower() for k in cls.mro() 
                if k != Base and issubclass(k, Base)]
        return '.'.join(names[::-1])


class F(Base): pass
class A(Base): pass
class E(A): pass
class B(A): pass
class C(B): pass
f = F()
a = A()
e = E()
b = B()
c = C()
print(OBJECT_CACHE.keys())

产量

['a', 'a.e', 'a.b.c', 'a.b', 'f']

【讨论】:

  • mro() 看起来确实不错,但是如果其中一个子类继承自另一个不继承自 Base 的类怎么办?例如class A(Base, str)我可以检查类是否有共享基础吗?
  • mro 包含所有碱基,每个碱基只包含一次。所以我认为它会工作得很好。如果添加str 作为基础,那么basestring 也是mro 的一部分。我不知道你是否想包括那个。如果没有,只需将basestring 添加到要排除的类的元组中:if k not in (Base, object, basestring)
  • 我认为我们可以通过检查每个循环的issubclass() 来否定这一点。为了清楚起见,我会编辑您的答案,然后接受它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 2021-09-30
  • 2013-07-08
  • 1970-01-01
  • 2014-09-23
  • 1970-01-01
相关资源
最近更新 更多