Khi làm việc về triển khai kiểu liệt kê tùy chỉnh, tôi gặp phải tình huống xuất hiện mà tôi phải tách riêng gần như các lớp con giống hệt nhau từ cả int
và long
vì chúng là các lớp riêng biệt trong Python. Điều này có vẻ mỉa mai vì các trường hợp của hai thường có thể được sử dụng thay thế cho nhau bởi vì hầu hết chúng chỉ được tạo tự động bất cứ khi nào được yêu cầu.Tránh có hai lớp con số khác nhau (int và long)?
Những gì tôi đã làm tốt, nhưng theo tinh thần của DRY (Đừng lặp lại), tôi không thể không tự hỏi nếu không có bất kỳ tốt hơn, hoặc ít nhất là một cách ngắn gọn hơn, để thực hiện điều này . Mục đích là để có các thể hiện lớp con có thể được sử dụng ở khắp mọi nơi - hoặc càng gần càng tốt - các trường hợp của các lớp cơ sở của chúng có thể có. Lý tưởng nhất điều này sẽ xảy ra tự động tương tự như cách được xây dựng trong int()
thực sự trả về một long
bất cứ khi nào nó phát hiện một là bắt buộc.
Dưới đây là thực hiện hiện tại của tôi:
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)
Câu trả lời hay, nhưng không xử lý 'NamedInt ('HexBased', 'deadbeef', 16)'. – martineau
Hmm, điểm tốt. Tôi nghĩ rằng nó có thể được cố định với varargs. Tôi sẽ chỉnh sửa để làm điều đó. – Blckknght
Cảm ơn bạn đã sửa chữa. Rất khó để quyết định giữa câu trả lời này và câu trả lời của @ eryksun, vì cả hai đều giải quyết vấn đề DRY rất tốt - nhưng cuối cùng đã chọn câu trả lời này vì đó là IMHO đơn giản và dễ hiểu nhất. BTW, có thể thêm thuộc tính '__slots__' vào chỉ lớp con' NamedInt' (như eryksun đã làm) mà dường như giải quyết nhu cầu đó cho trường hợp 'int' phổ biến hơn (và _is_ một đặc tính quan trọng cho việc sử dụng dự định). – martineau