mar*_*eau 5 python subclassing
在基本上处理自定义枚举类型实现时,我遇到了这样一种情况:我必须从两者中派生出单独但几乎相同的子类int,long因为它们是Python中的不同类.这似乎有点讽刺意味,因为两者的实例通常可以互换使用,因为大多数情况下它们只是在需要时自动创建.
我的工作很好,但本着DRY(不要重复自己)的精神,我不禁想知道是否有更好的,或者至少更简洁的方式来实现这一点.目标是让子类实例可以在任何地方使用 - 或尽可能接近 - 它们的基类实例可以使用.理想情况下,这应该自动发生,类似于内置int()实际返回的方式,long只要它检测到一个是必需的.
这是我目前的实施:
class NamedInt(int):
"""Subclass of type int with a name attribute"""
__slots__ = "_name" # also prevents additional attributes from being added
def __setattr__(self, name, value):
if hasattr(self, name):
raise AttributeError(
"'NamedInt' object attribute %r is read-only" % name)
else:
raise AttributeError(
"Cannot add attribute %r to 'NamedInt' object" % name)
def __new__(cls, name, value):
self = super(NamedInt, NamedInt).__new__(cls, value)
# avoid call to this subclass's __setattr__
super(NamedInt, self).__setattr__('_name', name)
return self
def __str__(self): # override string conversion to be name
return self._name
__repr__ = __str__
class NamedLong(long):
"""Subclass of type long with a name attribute"""
# note: subtypes of variable length 'long' type can't have __slots__
def __setattr__(self, name, value):
if hasattr(self, name):
raise AttributeError(
"NamedLong object attribute %r is read-only" % name)
else:
raise AttributeError(
"Cannot add attribute %r to 'NamedLong' object" % name)
def __new__(cls, name, value):
self = super(NamedLong, NamedLong).__new__(cls, value)
# avoid call to subclass's __setattr__
super(NamedLong, self).__setattr__('_name', name)
return self
def __str__(self):
return self._name # override string conversion to be name
__repr__ = __str__
class NamedWholeNumber(object):
"""Factory class which creates either a NamedInt or NamedLong
instance depending on magnitude of its numeric value.
Basically does the same thing as the built-in int() function
does but also assigns a '_name' attribute to the numeric value"""
class __metaclass__(type):
"""NamedWholeNumber metaclass to allocate and initialize the
appropriate immutable numeric type."""
def __call__(cls, name, value, base=None):
"""Construct appropriate Named* subclass."""
# note the int() call may return a long (it will also convert
# values given in a string along with optional base argument)
number = int(value) if base is None else int(value, base)
# determine the type of named numeric subclass to use
if -sys.maxint-1 <= number <= sys.maxint:
named_number_class = NamedInt
else:
named_number_class = NamedLong
# return instance of proper named number class
return named_number_class(name, number)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
247 次 |
| 最近记录: |