Python Recursion внутри метода Inherited Class - PullRequest
1 голос
/ 20 октября 2019

У меня есть класс и метод:

class Demo(dict):

  def foo(self, key):
     bar = self[key]
     foo(bar, key)

Класс Demo принимает dict в качестве аргумента
С app.py Я звоню Demo как:

data = { 'a': { 'a' : 123 } }

Demo(data).foo('a')

Мой вопрос: как передать вновь сформированный словарь bar = self[key] в качестве аргумента foo() при повторном обращении?

Должен ли я использовать это вместо?:

class Demo():

  def foo(self, data, key):
     bar = data[key]
     foo(bar, key)

Есть ли какой-нибудь другой лучший подход?

Ответы [ 4 ]

3 голосов
/ 20 октября 2019

Вместо этого вы можете использовать внутреннюю рекурсивную функцию:

def foo(self, key):
    def inner(new_d):
        bar = new_d[key]
        inner(bar)

    inner(self)  # Or whatever you want to be the initial value

Обратите внимание на то, как оно образовало замыкание в течение key, поэтому его не нужно передавать постоянно. Доступ к нему можно получить только из внешней области видимости.

Конечно, эта функция на самом деле не имеет особого смысла, хотя она будет повторяться вечно, поэтому я предполагаю, что это упрощенный пример.

2 голосов
/ 20 октября 2019

Можно делать то, что вы хотите, хотя я не знаю, является ли это лучшим решением. Это действительно зависит от того, чего вы пытаетесь достичь.

Следующий код рекурсивно так, как вы хотите. Преимущество состоит в том (если вы этого хотите), что параметр self.data в корневом классе (self) изменяется на протяжении всего отклонения. Это хорошо, если вы ХОТИТЕ, чтобы данные изменялись (например, для более позднего доступа к измененным данным другим способом позже.)

class Demo(dict):
    def __init__(self, data):
        self.data = data

    def foo(self, key):
        try:
            self.data = self.data[key]
            return self.foo(key)
        except:
            return self.data

data = { 'a': { 'a' : 123 } }

print(Demo(data).foo('a'))

Если вы НЕ ХОТИТЕ, чтобы self.data был постоянно изменен,Вы должны использовать второй метод, когда data и key передаются в функцию вместе, и не влияют на self.data ... или другой ответ (о inner recursive function от @Carcigenicate)

1 голос
/ 20 октября 2019

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

class Demo(dict):
    def foo(self, key):
        if isinstance(self[key], dict):
            return self.__class__(self[key]).foo(key)
        return self[key]

, чтобы:

data = {'a': {'a': 123}}
print(Demo(data).foo('a'))

выходы:

123

Демо: https://repl.it/@blhsing/PassionateOddAssembly

1 голос
/ 20 октября 2019

Ваш foo метод должен вызываться для экземпляра Demo, а не сам по себе. В обеих версиях вашего кода вызов foo без поиска чего-либо (вероятно, экземпляра) является ошибкой.

Возможно, вы хотите:

def foo(self, key):
    obj = Demo(self[key])
    obj.foo(key)

Это будет работать какПока ваши данные имеют вложенные словари под одним и тем же ключом. Сбой, когда self[key] не возвращает словарь. Предположительно, вы хотите иметь базовый случай, чтобы справиться с этим:

def foo(self, key):
    value = self[key]  # you might want a further base case to handle the key not existing at all!
    if not isinstance(value, dict):
        pass           # if you have something to do for the base case, do it here
    else:              # recursive case
        obj = Demo(value)
        obj.foo(key)

Теперь этот класс немного глуп, он копирует много вещей просто так, чтобы вы могли иметь метод, который работает на dict,Гораздо более разумный подход позволил бы избавиться от класса и просто использовать рекурсивную функцию с двумя аргументами, и вам не нужно создавать obj в рекурсивном случае:

# this foo is a top-level function, not part of a class!
def foo(data, key):  # no self argument any more
    value = data[key]
    ...
    foo(value, key)  # recursive call is simpler now
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...