最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Indexing in calling instructions. Would it be possible that a function could detect if the function calling instruction

programmeradmin3浏览0评论

Having a function that returns a list:

def func1(list1):
    func1_result = list1 * 2  # This is just an illustrative example to simply show that the function returns a list resulting from any function calculation.
    return func1_result

And getting the whole list returned by the function with:

Example 1:

list1_1 = [5, 4, 3, 2, 1]

print(f"{func1(list1_1)}")  # "[5, 4, 3, 2, 1, 5, 4, 3, 2, 1]"

Or also getting the value of a specific index of the list returned by the function, with:

Example 2:

list1_1 = [5, 4, 3, 2, 1]

print(f"{func1(list1_1)[0]}")  # "5"

Then, the question is about, is there any way where the function func1 could detect if the calling instruction syntax/format is including or not the indexing part [n]? and also, when including the indexing part [n], then, how to know what specific index value is in the function calling instruction?

def func1(list1):
    func1_result = []
    
    '''
    if  the function calling instruction is about getting the whole resulting list:
        do the function calculations to get the whole resulting list `func1_result`.
    elif  the function calling instruction is about getting one specific index value of the resulting list:
        do the function calculations to get only the resulting value for the specified index.
        # In this case the result could be a 1-element list.
        # Main goal for this case: saving memory during calculations when working with large lists and with many function's calls.
    '''
    
    return func1_result

My understanding is that the indexing access specified in the calling instruction takes place after the function returns the resulting list, but maybe there would be a kind of way (ideally a direct way) which the function could get this calling format information from the calling instruction, without the need to specify it manually with an additional function parameter.

Having a function that returns a list:

def func1(list1):
    func1_result = list1 * 2  # This is just an illustrative example to simply show that the function returns a list resulting from any function calculation.
    return func1_result

And getting the whole list returned by the function with:

Example 1:

list1_1 = [5, 4, 3, 2, 1]

print(f"{func1(list1_1)}")  # "[5, 4, 3, 2, 1, 5, 4, 3, 2, 1]"

Or also getting the value of a specific index of the list returned by the function, with:

Example 2:

list1_1 = [5, 4, 3, 2, 1]

print(f"{func1(list1_1)[0]}")  # "5"

Then, the question is about, is there any way where the function func1 could detect if the calling instruction syntax/format is including or not the indexing part [n]? and also, when including the indexing part [n], then, how to know what specific index value is in the function calling instruction?

def func1(list1):
    func1_result = []
    
    '''
    if  the function calling instruction is about getting the whole resulting list:
        do the function calculations to get the whole resulting list `func1_result`.
    elif  the function calling instruction is about getting one specific index value of the resulting list:
        do the function calculations to get only the resulting value for the specified index.
        # In this case the result could be a 1-element list.
        # Main goal for this case: saving memory during calculations when working with large lists and with many function's calls.
    '''
    
    return func1_result

My understanding is that the indexing access specified in the calling instruction takes place after the function returns the resulting list, but maybe there would be a kind of way (ideally a direct way) which the function could get this calling format information from the calling instruction, without the need to specify it manually with an additional function parameter.

Share Improve this question edited Jan 18 at 3:09 codev asked Jan 17 at 20:35 codevcodev 476 bronze badges 4
  • What's the point of doing func1_result = [] before you reassign the variable? – Barmar Commented Jan 17 at 20:54
  • @Barmar: I think they just chose a poor example for "function that does real work for entire sequence, when we might only want one result". The example function could simplify to return list1 * 1 with zero change in behavior, and if you assume the inputs are actually sequences (so numeric multiplication isn't actually something to handle), a simple return list1[:]/return list1.copy()/return list(list1) (so many ways to shallow copy a list!) would be even simpler/more straightforward. – ShadowRanger Commented Jan 17 at 21:13
  • @Barmar, the function code is just an example to show a general scenario where a function is already working returning a list resulting from any function calculation, so there is no specific point of doing func1_result = [] and its only purpose was about the 2nd function code can run as is, as shown (in that situation returning an empty list because the needed commented part). So, the relevant part is about the function can have an efficient way to handle the situation when the calling instruction is to get only 1 specific element from a function that currently returns a resulting list. – codev Commented Jan 17 at 21:32
  • As @ShadowRanger mentions, the example function content could simplify to return list1 * 1. The current function workflow is about doing some calculation that obtains a list and then returning that list. – codev Commented Jan 17 at 21:48
Add a comment  | 

1 Answer 1

Reset to default 3

You can't do this in any reasonable way. The indexing instruction can't begin until the function returns a result, period.

The best you could do to achieve a result similar to this would be to have func1 actually be a class that stores its arguments without doing any work until a __getitem__ or __repr__/__str__ or whatever call requires it to do some work. In specific cases, this might be an improvement in performance, the code is just more complicated.

Trivial example:

import collections.abc
from operator import index

class lazy_mapping(collections.abc.Sequence):
    def __init__(self, list1):
        self._list1 = list1

    def __getitem__(self, idx_or_slice):
        if isinstance(idx_or_slice, slice):
            # Only do real work for elements from slice
            return [do_real_work(x) for x in self._list1[idx_or_slice]]

        # It's not a slice, do the real work for the single item indexed
        return do_real_work(self._list1[idx_or_slice])

    def __len__(self):
        return len(self._list1)

    def __repr__(self):
        return repr(self[:])  # Represent the class as the repr of the list produced by applying the function

And it would be used exactly as you propose, with print(f"{lazy_mapping(list1_1)[0]}") only performing the real work for index 0, not the rest of list1_1, and print(f"{func1(list1_1)}") performing the complete mapping as part of producing the repr. Inheriting from collections.abc.Sequence means you can allow it to provide the fallback implementations for all the things that are straightforward and mostly boilerplate.

By performing the work in __getitem__, you can limit it to the items actually requested. The risk is that they request data for many such elements, repeatedly, and now you're doing more work to optimize the "only want a single item" case at the expense of the "need the entire result (or multiple access to many elements)" case. A complicated result-caching algorithm could mitigate this, at the expense of even more complex code.

发布评论

评论列表(0)

  1. 暂无评论