Python中实现类属性子切片直接调用translate方法的最佳实践
Great question! Let's walk through how to make this work in a clean, Pythonic way. First, let's fix a couple of small issues in your original code, then dive into subclassing approaches that let you call translate() directly on scores or its slices.
First: Fixes to Your Original Code
Your initial code has a couple of typos that need addressing first:
- The
buildmethod is missing theselfparameter (required for instance methods)- The
translatemethod usesvalin the list comprehension but referencesscore; it should befor score in self.scores
list for Custom Score Container To let scores (and its slices) have a translate() method that uses the parent Data instance's encoding, we can create a custom subclass of list that holds a reference to the parent Data object. This keeps the translation logic tightly coupled to the score data while maintaining all standard list functionality.
class ScoreList(list): def __init__(self, parent, iterable=()): super().__init__(iterable) self.parent = parent # Link back to the parent Data instance def translate(self): # Use the parent's encoding to convert scores to strings return [self.parent.encoding[score] for score in self] def __getitem__(self, key): # Ensure slices return ScoreList instances (not regular lists) with the same parent result = super().__getitem__(key) if isinstance(result, list): return ScoreList(self.parent, result) return result class Data: def __init__(self): self.scores = ScoreList(self) # Initialize with parent reference self.encoding = {1: 'first', 2: 'second', 3:'third'} def build(self): # Replace scores with a populated ScoreList self.scores = ScoreList(self, [1,2,3]) # Test it out d = Data() d.build() print(d.scores.translate()) # Output: ['first', 'second', 'third'] print(d.scores[1:].translate()) # Output: ['second', 'third']
Why This Works:
ScoreListinherits all standard list methods (append, extend, sort, etc.) so it behaves exactly like a normal list- The
parentattribute ensurestranslate()always uses the correct encoding from the originalDatainstance - Overriding
__getitem__makes sure slices ofscoresalso returnScoreListobjects, so you can calltranslate()directly on slices too
numpy.ndarray for Array-Based Scores If you're working with NumPy arrays instead of regular lists, you can subclass numpy.ndarray to add the translate() method. NumPy has specific rules for subclassing, so we need to handle instance creation and view preservation carefully.
import numpy as np class ScoreArray(np.ndarray): def __new__(cls, input_array, parent=None): # Create the array instance first (required for NumPy subclasses) obj = np.asarray(input_array).view(cls) obj.parent = parent # Attach parent reference return obj def __array_finalize__(self, obj): # Carry over the parent reference when slicing or creating views if obj is None: return self.parent = getattr(obj, 'parent', None) def translate(self): if self.parent is None: raise ValueError("ScoreArray must be linked to a Data instance") # Efficient vectorized translation for NumPy arrays return np.vectorize(lambda x: self.parent.encoding[x])(self) class Data: def __init__(self): self.scores = ScoreArray([], parent=self) self.encoding = {1: 'first', 2: 'second', 3:'third'} def build(self): self.scores = ScoreArray([1,2,3], parent=self) # Test it out d = Data() d.build() print(d.scores.translate()) # Output: ['first' 'second' 'third'] print(d.scores[1:].translate()) # Output: ['second' 'third']
Why This Works:
__new__and__array_finalize__follow NumPy's subclassing rules to ensure parent references are preserved across slices and viewsnp.vectorizeapplies the translation logic efficiently to the entire array
- Prioritize Subclassing Over Monkey Patching: Modifying built-in types (like adding
translate()tolistglobally) is messy and can break other code. Subclassing keeps your changes isolated to your specific use case. - Maintain Clear State Links: The parent reference ensures
translate()always uses the correct encoding from the originalDatainstance, avoiding disconnected state or global variables. - Follow Single Responsibility: The
translate()method on the score container does one specific job—translating scores using the parent's encoding—keeping your code clean and focused.
内容的提问来源于stack exchange,提问作者codebrotherone

