杰瑞科技汇

python subscriptable

Of course! The term "subscriptable" in Python refers to an object's ability to have its elements accessed using square brackets []. This is a fundamental concept in Python.

python subscriptable-图1
(图片来源网络,侵删)

Let's break it down in detail.

The Core Idea: What Does "Subscriptable" Mean?

When you see the error TypeError: 'X' object is not subscriptable, it means you are trying to use the square bracket notation [] on an object X that doesn't support it.

Think of it like a book:

  • A list, tuple, or dictionary is like a book with an index or a table of contents. You can look up a specific page or entry using its number or key (e.g., my_list[5], my_dict['name']). These are subscriptable.
  • An integer or a string (in some contexts) is like a single, standalone chapter. You can't look up a "page 5" within that single chapter because it doesn't have an internal index of its own parts. These are generally not subscriptable.

How to Check if an Object is Subscriptable

The most reliable way to check is to use the built-in isinstance() function with the collections.abc.Sequence or collections.abc.Mapping abstract base classes. These classes define the standard interface for sequences (like lists, tuples) and mappings (like dictionaries), respectively.

python subscriptable-图2
(图片来源网络,侵删)
import collections.abc
# Subscriptable objects
my_list = [1, 2, 3]
my_tuple = (1, 2, 3)
my_dict = {'a': 1, 'b': 2}
my_string = "hello"
my_set = {1, 2, 3}
# Non-subscriptable objects
my_integer = 123
my_float = 45.67
my_boolean = True
print(f"Is a list subscriptable? {isinstance(my_list, collections.abc.Sequence)}") # True
print(f"Is a tuple subscriptable? {isinstance(my_tuple, collections.abc.Sequence)}") # True
print(f"Is a dict subscriptable? {isinstance(my_dict, collections.abc.Mapping)}") # True
print(f"Is a string subscriptable? {isinstance(my_string, collections.abc.Sequence)}") # True
print(f"Is a set subscriptable? {isinstance(my_set, collections.abc.Sequence)}") # True
print("-" * 20)
print(f"Is an int subscriptable? {isinstance(my_integer, collections.abc.Sequence)}") # False
print(f"Is a float subscriptable? {isinstance(my_float, collections.abc.Sequence)}") # False
print(f"Is a bool subscriptable? {isinstance(my_boolean, collections.abc.Sequence)}") # False

Common Subscriptable Data Types

Here are the most common subscriptable objects you'll use, along with how you subscript them.

Data Type Example How to Subscript Description
list my_list = [10, 20, 30] my_list[0] Accesses an element by its integer index (starts at 0).
tuple my_tuple = ('a', 'b', 'c') my_tuple[1] Accesses an element by its integer index (immutable).
str my_string = "python" my_string[3] Accesses a character by its integer index.
dict my_dict = {'key1': 'val1'} my_dict['key1'] Accesses a value by its key.
set my_set = {1, 2, 3} my_set[0] ERROR! Sets are unordered and not subscriptable by index.

The TypeError: 'X' object is not subscriptable

This is the error you'll encounter most often. Let's look at common scenarios that cause it.

Scenario 1: Trying to subscript an integer or float

This is a very common mistake, especially when a function is expected to return a number but instead returns a list or tuple.

def get_first_item(items):
    # This function is supposed to return the first item,
    # but it incorrectly returns a list containing the first item.
    return [items[0]]
my_data = [10, 20, 30]
first_element = get_first_item(my_data)
print(f"The function returned: {first_element}")
print(f"The type of the returned value is: {type(first_element)}")
# Now, let's try to subscript it again, thinking it's the number 10.
# This will fail because first_element is a list, not an integer.
try:
    # This is the line that causes the error
    value = first_element[0] + 5 
except TypeError as e:
    print(f"\nError caught: {e}")
    # The correct way would be to access the element inside the list first
    correct_value = first_element[0] + 5
    print(f"The correct value is: {correct_value}")

Output:

python subscriptable-图3
(图片来源网络,侵删)
The function returned: [10]
The type of the returned value is: <class 'list'>
Error caught: 'int' object is not subscriptable
The correct value is: 15

Wait, the error message says 'int' object is not subscriptable, but we were trying to subscript a list!

This highlights a subtle but important point: The error message refers to the type of the object you are trying to subscript. In this case, the error occurred inside the function get_first_item when it tried to do items[0]. If items was, for example, the integer 123, the error would have been raised there. The key takeaway is to always check the type of your variable before trying to subscript it.

Scenario 2: Confusing a variable name with a function call

Sometimes you might have a variable and a function with the same name, leading to confusion.

# Let's say we have a list named 'data'
data = [1, 2, 3]
# And a function that also happens to be named 'data'
def data():
    return "I am a function, not a list!"
# If you call the function without parentheses, you get the function object itself
# This function object is not subscriptable.
try:
    print(data[0]) 
except TypeError as e:
    print(f"Error: {e}")
    print("You likely meant to call the function with parentheses: data()")

Output:

Error: 'function' object is not subscriptable
You likely meant to call the function with parentheses: data()

How to Make Your Own Objects Subscriptable

You can create your own custom classes that are subscriptable by implementing special "magic" methods in your class.

  • For integer indexing (like a list or tuple), implement __getitem__(self, key).
  • For assignment (e.g., my_obj[0] = 'new_value'), implement __setitem__(self, key, value).
  • For deletion (e.g., del my_obj[0]), implement __delitem__(self, key).

Example: A Custom Countdown Class

Let's create a class that behaves like a list, counting down from a given number.

class Countdown:
    def __init__(self, start):
        if not isinstance(start, int):
            raise TypeError("Start value must be an integer.")
        self.current = start
    def __iter__(self):
        # This makes the object iterable, so you can use it in a for loop
        return self
    def __next__(self):
        # This is part of making it iterable
        if self.current < 0:
            raise StopIteration
        else:
            value = self.current
            self.current -= 1
            return value
    def __getitem__(self, index):
        # This makes the object subscriptable!
        if not isinstance(index, int):
            raise TypeError("Index must be an integer.")
        if index < 0 or index >= self.current + 1:
            raise IndexError("Index out of range for countdown.")
        # The value at a given index is start - index
        return self.current + 1 - (index + 1) # Simplifies to self.current - index
# --- Usage ---
try:
    # Create a countdown from 5
    countdown = Countdown(5)
    # Now it's subscriptable!
    print(f"The first item is: {countdown[0]}")  # Output: 5
    print(f"The third item is: {countdown[2]}")  # Output: 3
    print(f"The last item is: {countdown[5]}")   # Output: 0
    # You can also iterate over it
    print("\nIterating over the countdown:")
    for number in countdown:
        print(number)
except (TypeError, IndexError)
分享:
扫描分享到社交APP
上一篇
下一篇