Существуют ли более эффективные способы выбора различных действий в функции на основе ее входных данных? - PullRequest
1 голос
/ 10 апреля 2020

Я создал обобщенную c функцию для создания 2D-сетки размером x, y, make_grid.

def make_grid(x, y, mode="empty"):
    if mode == "rand":
        def filling():
            return randint(0, 1)
    else:
        def filling():
            return 0
    grid = []
    for r in range(x):
        row = []
        for c in range(y):
            row.append(filling())
        grid.append(row)
    return grid

. Я настроил ее для определения функции filling. основанный на вводе mode, чтобы я не запустил кучу if проверок без необходимости через циклы for - надежда на то, что на большой сетке это сэкономит значительное время.

Я не уверен, однако, что это был бы самый Pythoni c способ достижения этого - не совсем понятно определять функции внутри функций таким способом. Кто-нибудь может предложить лучшие (более четкие или более эффективные) методы? Я чувствую, что лямбды могут быть верным путем, но я никогда не чувствовал себя комфортно с ними ... Я должен, по крайней мере, быть в состоянии определить функции в другом месте, выбрать, какую из них следует вызывать перед для l oop, а затем используйте его во время цикла for, верно?

Редактировать: вот более минимальный пример, так как я сначала был позорно ленивым и не удосужился сделать правильный… (я оставив оригинал, чтобы ответы все еще имели смысл.)

def example(mode=0):
    if mode == 1:
        def action_to_take():
            print("mode1")
    else:
        def action_to_take():
            print("mode_other")
    for r in range(1000):
        for c in range(1000):
            action_to_take()

Представьте себе, что условно определенная функция action_to_take достаточно сложна, чтобы ответить на этот вопрос, и l oop обходится достаточно раз, чтобы ставить под сомнение эффективность кода разумно.

Ответы [ 3 ]

2 голосов
/ 10 апреля 2020

вы можете использовать dict:

def fill_rand():
    return randint(0, 1)

def default_fill():
    return 0

# you can add how  many modes you want
filling_mode = {
    'rand': fill_rand,

}

def make_grid(x, y, mode="empty"):
    filling = filling_mode.get(mode) or default_fill

    grid = []
    for r in range(x):
        row = []
        for c in range(y):
            row.append(filling())
        grid.append(row)
    return grid
1 голос
/ 10 апреля 2020

Условно определять такие функции редко. Вы можете упростить это и немного сократить его с помощью более простого подхода:

import numpy as np

def make_grid(x, y, mode='empty'):  
  if mode == 'rand':
    return np.random.randint(0, high=2, size=(y, x)).tolist()
  return np.zeros((y, x)).tolist()

Если вам не нравится numpy, я бы использовал списочные выражения, потому что это делает код кратким:

from random import randint

def grid(x=1, y=1, zeros=False):
  return [[0 if zeros else randint(0,1) for _ in range(y)] for _ in range(x)]

a = grid(x=7, y=10, zeros=False)

Трудно обобщать слишком много, кроме этого. В общем, довольно не принято условно определять функцию. Гораздо более распространено условно определять значение внутри функции (см., Например, синтаксис x if b else y в моей функции grid() выше).

Если вы публикуете реальную ситуацию или дополнительную информацию о функции, которые вы условно хотите создать, мы, вероятно, можем дать больше информации. В любом случае, если вам нужно поддерживать оба поведения, обычно имеет смысл определять эти функции вне условного, но вызывать их внутри условного, как @ kederra c, выполнило ...

0 голосов
/ 11 апреля 2020

В случае, когда аргумент mode используется только для определения того, какое действие необходимо выполнить в определенной точке внутри функции, другой вариант, о котором я только что подумал, - просто передать имя функции в качестве параметра. Как показано ниже:

def action_one():
    print("mode1")


def action_default():
    print("other")


def example(func=lambda *args: None):
    for r in range(1000):
        for c in range(1000):
            func()

Затем можно вызвать example(action_default) или example(action_one), и с этим лямбда-выражением в качестве значения по умолчанию будет даже example() - что ничего не изменит в точке, где func называется.

...