在Python中使用类型作为字典键被认为是一种好的实践吗?

在Python中使用类型作为字典键被认为是一种好的实践吗?,python,python-3.x,dictionary,Python,Python 3.x,Dictionary,我有这样一个查找表: lookup = { "<class 'Minority.mixin'>": report_minority, "<class 'Majority.mixin'>": report_majority, } def report(o): h = lookup[str(type(o))] h() 查找={ “”:报告, “”报告(多数), } def报告(o): h=查找[str(类型(o))] h() 我觉得这很尴尬,因为键与ty

我有这样一个查找表:

lookup = {
  "<class 'Minority.mixin'>": report_minority,
  "<class 'Majority.mixin'>": report_majority,
}

def report(o):
  h = lookup[str(type(o))]
  h()
查找={
“”:报告,
“”报告(多数),
}
def报告(o):
h=查找[str(类型(o))]
h()

我觉得这很尴尬,因为
type()
如何返回并在
字符串
中表示
有关。如果有一天Python改变了它在
string
中表示
class
类型的方式,那么所有这样的代码都会被破坏。所以我想从专业人士那里得到一些建议,这样的钥匙是好的还是坏的?谢谢。

看看这个脚本,我不认为它是完美的,但它可以工作,而且我认为它比您的解决方案更优雅:

#!/usr/bin/env python3

class Person:
    pass

def display_person():
    print("Person !")

class Car:
    pass

def display_car():
    print("Car !")

lookup = {
    Person: display_person,
    Car: display_car
}


def report(o):
    lookup[o.__class__]()


report(Person())
report(Car())

编辑:对Python3的修改查看该脚本,我认为它并不完美,但它可以工作,而且比您的解决方案更优雅:

#!/usr/bin/env python3

class Person:
    pass

def display_person():
    print("Person !")

class Car:
    pass

def display_car():
    print("Car !")

lookup = {
    Person: display_person,
    Car: display_car
}


def report(o):
    lookup[o.__class__]()


report(Person())
report(Car())

编辑:对Python3的修改只需从查找和字典中删除
str
。所以

lookup = {
   Minority.mixin : report_minority,
   Majority.mixin : report_majority,
}

def report(o):
    h = lookup[type(o)]
    h()
这解决了您当前的问题,并且是相当合理的代码。然而,似乎对类型进行分派正是OO的目的。那么,为什么不在从其类型派生的
o
对象上使用这些不同的报告函数方法呢?然后你可以写:

o.report()

正确的变体将从类中获得。

只需从查找和字典中删除
str
。所以

lookup = {
   Minority.mixin : report_minority,
   Majority.mixin : report_majority,
}

def report(o):
    h = lookup[type(o)]
    h()
这解决了您当前的问题,并且是相当合理的代码。然而,似乎对类型进行分派正是OO的目的。那么,为什么不在从其类型派生的
o
对象上使用这些不同的报告函数方法呢?然后你可以写:

o.report()

正确的变体将从课堂上获得。

问题更多的是你为什么要这样做?你认为使用字符串有什么好处

类对象是可散列的,因此您可以直接使用
Minority.mixin
Majority.mixin
作为键。当您这样做时,您可以确保键始终是完全相同的对象,前提是您的类在其各自的模块中是全局的,从而使它们成为您的程序的单例。此外,当您稍后重构代码以重命名模块时,不会出现意外的混淆,最终您会得到一个不同的类型,并得到确切的
repr()
输出

因此,除非您有一个不能直接使用类的特定用例,否则您不应该使用字符串表示

(即使要使用工厂函数生成类,也最好使用基类和
isinstance
检查或从MRO提取基类)

因此,对于您的用例,请坚持:

lookup = {
    Minority.mixin: report_minority,
    Majority.mixin: report_majority,
}

def report(o):
    h = lookup[type(o)])
    h()
接下来,如果您确保
report\u minority
report\u minority
是函数(而不是方法),那么您可以使用和取消映射:

from functools import singledispatch

@singledispatch
def report(o):
    raise ValueError('Unhandled type {}'.format(type(o)))

@report.register(Minority.mixin)
def report_minority(o):
    # handle a Minority instance

@report.register(Majority.mixin)
def report_majority(o):
    # handle a Majority instance
请注意,这不适用于方法,因为方法必须采用多个参数才能分派工作,因为它们总是采用
self


与基于
str
的映射甚至直接类映射不同,单分派处理子类的效果要好得多。

问题更多的是,为什么要这样做?你认为使用字符串有什么好处

类对象是可散列的,因此您可以直接使用
Minority.mixin
Majority.mixin
作为键。当您这样做时,您可以确保键始终是完全相同的对象,前提是您的类在其各自的模块中是全局的,从而使它们成为您的程序的单例。此外,当您稍后重构代码以重命名模块时,不会出现意外的混淆,最终您会得到一个不同的类型,并得到确切的
repr()
输出

因此,除非您有一个不能直接使用类的特定用例,否则您不应该使用字符串表示

(即使要使用工厂函数生成类,也最好使用基类和
isinstance
检查或从MRO提取基类)

因此,对于您的用例,请坚持:

lookup = {
    Minority.mixin: report_minority,
    Majority.mixin: report_majority,
}

def report(o):
    h = lookup[type(o)])
    h()
接下来,如果您确保
report\u minority
report\u minority
是函数(而不是方法),那么您可以使用和取消映射:

from functools import singledispatch

@singledispatch
def report(o):
    raise ValueError('Unhandled type {}'.format(type(o)))

@report.register(Minority.mixin)
def report_minority(o):
    # handle a Minority instance

@report.register(Majority.mixin)
def report_majority(o):
    # handle a Majority instance
请注意,这不适用于方法,因为方法必须采用多个参数才能分派工作,因为它们总是采用
self


与基于
str
的映射甚至直接类映射不同,单分派处理子类的效果要好得多。

@Dorian您能详细说明一下为什么这个解决方案更优雅吗?循环真的有必要吗?我不知道,但我个人觉得循环比简单的字典查找更复杂???@Dorian从性能上看,迭代比散列查找要昂贵得多,不是吗?我认为它更优雅,因为与使用
type
相比,
istance
是测试对象类型的更好方法。但你是对的,我也不喜欢这个循环,它可能更贵,如果你的dict只包含2个元素,这没什么大不了的,但如果你的dict更大,它可能会更贵。@JinghuiNiu我找到了一个更好的解决方案来移除这个循环,我不知道
\uuuuu class\uuuuuu
属性,但我认为它非常适合解决这个问题。@Dorian您能详细说明一下为什么这个解决方案更优雅吗?循环真的有必要吗?我不知道,但我个人觉得循环比简单的字典查找更复杂???@Dorian从性能上看,迭代比散列查找要昂贵得多,不是吗?我认为它更优雅,因为与使用
type
相比,
istance
是测试对象类型的更好方法。但你是对的,我不喜欢厕所