Создание hash для типа python

Допустим такую структуру:

class Base:
  id = 0

  def __type_hash__(cls):
    return hash((Base,cls.id))

  def __init__(self,value)
    self.value = value

  def __hash__(self):
    return hash(value)

class C87(Base):
  id = 0x87

class CA0(C87):
  id = 0xA0

class CFoo(C87):
  pass

class CBar(CA0):
  pass

вот хочу использовать класс в списках и ключах чтоб например

C87 in [CFoo] == True
CFoo in [Base, CA0] == False

__type_hash__ - плейсхолдер для неизвестной магии. Экземпляры чтоб сравнивались по value, а классы по id.


Ответы (1 шт):

Автор решения: Amgarak

Если я правильно понял вашу идею:

Через метакласс мы можем переопределить методы самого класса и будет hash/сравнение через id.

В то время как экземпляры переопределят методы обратно, и будут использоваться уже те что определены в самом классе, а следовательно всё уже будет работать через value.

class BaseMeta(type):
    def __eq__(cls, other):
        if isinstance(other, type):
            return cls.id == getattr(other, 'id', None)
        return False

    def __hash__(cls):
        return hash(cls.id)  

class Base(metaclass=BaseMeta):
    id = 0

    def __init__(self, value):
        self.value = value

    def __hash__(self):
        return hash(self.value)

    def __eq__(self, other):
        if isinstance(other, Base):
            return self.value == other.value
        return False

class C87(Base):
    id = 0x87
    
class CA0(C87):
    id = 0xA0

class CFoo(C87):
    pass

class CBar(CA0):
    pass

print(hash(C87) == hash(CFoo))  # True
print(hash(C87) == hash(CA0))  # False
print(hash(CBar) == hash(CA0))  # True

print(C87 == CFoo)  # True
print(CFoo == CA0)  # False

foo1 = CFoo(100)
foo2 = CFoo(100)
bar1 = CBar(200)
bar2 = CBar(100)

print(foo1 == foo2)  # True
print(foo1 == bar1)  # False

print(hash(foo1) == hash(bar1)) # False
print(hash(foo1) == hash(bar2)) # True

print(C87 in [CFoo]) # True
print(CFoo in [Base, CA0]) # False

my_dict = {foo1:"78", foo2:"90", bar1:"54", bar2:"13"}
print(my_dict) # {<__main__.CFoo object at 0x7a26419d10>: '13', <__main__.CBar object at 0x7a26419850>: '54'}
print(my_dict[foo1]) # 13

my_dict2= {C87:"78", CFoo:"90", CBar:"54", CA0:"13"}
print(my_dict2) # {<class '__main__.C87'>: '90', <class '__main__.CBar'>: '13'}
print(my_dict2[C87]) # 90 
→ Ссылка