我想继承int
(或其他一些类似的内置数字类型)的类,以便可以显式地键入check。
此问与答类似,但没有完全回答我所看到的: Sub-classing a built-in Python type such as int
这是我要实现的目标的粗略示例:
class MyId( int ) : pass
class MyCollection() :
def __init__( self ):
self.__id = MyId( 0 )
def nextId( self ) :
self.__id+=1
print "isinstance", isinstance(self.__id, MyId)
return self.__id
不幸的是,我对isinstance
的调用返回了False
。如何使它成功(理想情况下,具有相同的基本概念)?显然,如何通过与int
赋予MyId类“具有”而不是“是”关系来实现这一点……但我认为最好将其设为具有int
的{{1}}特定的“名称”。
当前,我正在Py2中编写此代码,但如果适用的话,任何跨版本的答案都值得赞赏。
答案 0 :(得分:3)
那是因为您需要覆盖__add__
方法。
如果不重写此方法,它将使用内置的int __add__
方法,该方法返回一个新的整数对象。
请参阅this topic,其中解释了@martineau在评论中提到的这种行为。
class MyId( int ):
def __add__(self, i):
return MyId(super(MyId, self).__add__(i))
class MyCollection() :
def __init__( self ):
self.__id = MyId( 0 )
def nextId( self ) :
self.__id += 1
print "isinstance", isinstance(self.__id, MyId)
return self.__id
a = MyCollection()
a.nextId()
打印:isinstance True
答案 1 :(得分:0)
请检查您的实例变量是否为int
,而不是子类int
。
class MyCollection():
def __init__( self ):
self.__id = 0
def nextId( self ) :
self.__id += 1
print "isinstance", isinstance(self.__id, int)
return self.__id
答案 2 :(得分:0)
这听起来像是您可以检查要传递的值是否已以特定方式创建的内容。在 Python 3.5.2 + 中,提供了NewType
的typing
模块。这使您可以对代码进行静态分析,以确保它正在执行您期望执行的操作。文档中给出的示例是:
from typing import NewType UserId = NewType('UserId', int) some_id = UserId(524313)
静态类型检查器会将新类型视为原始类型的子类。这对于帮助捕获逻辑错误很有用:
def get_user_name(user_id: UserId) -> str: ... # typechecks user_a = get_user_name(UserId(42351)) # does not typecheck; an int is not a UserId user_b = get_user_name(-1)
运行时不执行任何实际的类型检查,NewType
返回的值只是一个传递函数,其参数保持不变。这也意味着您无法做类似isinstance(obj, UserId)
的事情,因为UserId
不是实际的课程。真正的意思是,正如文档中提到的那样,静态类型检查器将帮助发现逻辑错误-看起来像您要的那样。
答案 3 :(得分:0)
根据Dun Dunes的建议,我只是完全放弃了整个int
概念。正如他指出的那样,任何香草对象都可以隐式用作唯一键!
实际上MyId
可以简单定义为:class MyId: pass
。通常就是这样-一个完美可用的,隐式唯一的键!
但是,对于我的用例,我需要在子进程之间来回传递这些键(通过multiprocessing
队列)。我在使用这种超轻量级方法时遇到了麻烦,因为当对对象进行腌制并将其推入进程时,哈希值会发生变化。另一个次要问题是我想使这些对象易于记录并通过日志手动读取/匹配。因此,我这样做了:
class _MyIdPrivate: pass
class MyId :
def __init__( self ):
self.__priv = _MyIdPrivate()
self.__i = hash( self.__priv )
def __str__( self ): return str( self.__i )
def __hash__( self ): return self.__i
def __eq__( self, other ):
try: return self.__i == other.__i
except: return False
class MyCollection :
def __init__( self ):
self.__objs={}
def uniqueId( self ): return MyId()
def push( self, i, obj ):
self.__objs[ i ] = obj
def pop( self, i ):
return self.__objs.pop( i, None )
c = MyCollection()
uId = c.uniqueId()
print "uId", uId
print "isinstance", isinstance(uId, MyId)
c.push( uId, "A" )
print c.pop( MyId() )
print c.pop( uId )
如您所见,我将简短而甜美的方法包装成更全面/详细的方法。创建MyId对象时,将创建_MyIdPrivate成员,并在创建时获取该对象的哈希值。进行酸洗并推入子项目时,_MyIdPrivate哈希将更改-没关系,因为我捕获了初始值,并且最终所有结果都绕开了该值。
与原始的int
计划相比,此方法的主要优点是我得到了唯一的密钥,而无需“计算”或直接分配它。
正如Dunes的建议,我也可以使用uuid。我可以看到相对于此的利弊...