【发布时间】:2019-11-30 07:10:29
【问题描述】:
在我正在处理的问题中,有scope:name 形式的数据标识符,既是scope 又是name 字符串。 name 的不同部分由点分隔,例如 part1.part2.part3.part4.part5。在许多情况下,scope 仅等于 part1 的 name,但并非总是如此。我正在编写的代码必须与以不同模式提供或需要标识符的不同系统一起使用。有时他们只需要像scope:name这样的完整字符串表示,在其他一些情况下,调用有两个不同的参数scope和name。从其他系统接收信息时,有时会返回完整的字符串scope:name,有时会省略scope,应从name 推断,有时会返回包含scope 和name 的dict。
为了简化这些标识符的使用,我创建了一个类来内部管理它们,这样我就不必一遍又一遍地编写相同的转换、拆分和格式。课程非常简单。它只有两个属性(scope和name,一个将字符串解析为类对象的方法,以及一些表示对象的魔术方法,特别是__str__(self)以scope:name的形式返回对象,即标识符的完全限定名称 (fqn):
class DID(object):
"""Represent a data identifier."""
def __init__(self, scope, name):
self.scope = scope
self.name = name
@classmethod
def parse(cls, s, auto_scope=False):
"""Create a DID object given its string representation.
Parameters
----------
s : str
The string, i.e. 'scope:name', or 'name' if auto_scope is True.
auto_scope : bool, optional
If True, and when no scope is provided, the scope will be set to
the projectname. Default False.
Returns
-------
DID
The DID object that represents the given fully qualified name.
"""
if isinstance(s, basestring):
arr = s.split(':', 2)
else:
raise TypeError('string expected.')
if len(arr) == 1:
if auto_scope:
return cls(s.split('.', 1)[0], s)
else:
raise ValueError(
"Expecting 'scope:name' when auto_scope is False"
)
elif len(arr) == 2:
return cls(*arr)
else:
raise ValueError("Too many ':'")
def __repr__(self):
return "DID(scope='{0.scope}', name='{0.name}')".format(self)
def __str__(self):
return u'{0.scope}:{0.name}'.format(self)
正如我所说,代码必须执行与字符串的比较并使用某些方法的字符串表示。我很想写 __eq__ 魔术方法及其对应的 __ne__。以下是刚刚__eq__的实现:
# APPROACH 1:
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.scope == other.scope and self.name == other.name
elif isinstance(other, basestring):
return str(self) == other
else:
return False
如您所见,它以一种可以相互比较的方式定义了 DID 和字符串之间的相等比较。 我的问题是这是否是一个好习惯:
一方面,当other 是一个字符串时,该方法将self 转换为一个字符串,我一直在考虑显式优于隐式。您最终可能会认为您正在使用两个字符串,而 self 的情况并非如此。
另一方面,从意义的角度来看,DID 代表 fqn scope:name,并且比较与字符串的相等性是有意义的,就像比较 int 和 float 或任何比较从basetring 派生的两个对象。
我也考虑过在实现中不包括基本字符串的情况,但对我来说这更糟糕并且容易出错:
# APPROACH 2:
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.scope == other.scope and self.name == other.name
else:
return False
在方法 2 中,比较表示相同标识符的 DID 对象和字符串之间的相等性,返回 False。对我来说,这更容易出错。
在这种情况下有哪些最佳做法?是否应该像方法 1 中那样实现 DID 和字符串之间的比较,即使来自不同类型的对象可能被认为是相等的?即使s != DID.parse(s),我也应该使用方法2吗?不应该实现__eq__ 和__ne__ 以免产生误解吗?
【问题讨论】:
-
你试过
1 == 1.0吗?但是请注意,__eq__并不是孤立存在的……这就是为什么hash(1) == hash(1.0),你不想用__eq__的自定义实现来打破 Liskov 原则,它会破坏子类或类似东西的散列…… -
作为记录,如果你使用的是 Python 2,并且你实现了
__eq__,请确保implement__ne__in terms of__eq__; Python 3 会为你做到这一点,Python 2 不会。 -
鸭子类型会建议您简单地尝试属性比较,如果出现
AttributeError,则回退到字符串比较。不用担心other的确切类型。 -
@GiacomoAlzetta,您正式指出了我对我提出的方法的担忧。
__eq__不是孤立存在的。谢谢。 -
@ShadowRanger。我考虑到了这一点。当卡在 Python 2 中时,需要考虑到这一点。
标签: python python-2.7