python: законно ли передавать себя во вложенную функцию внутри метода класса?

class A:
    def __init__(self):
        self.name = None
        self.a = 10
        self.b = 20
        self.c = 30
    def func1(self, param1, param2):
        def inner_func1(self, param1, param2):
            print(self, self.a, self.b)

        inner_func1(self, param1, param2)

a = A()
print(a)
a.func1(1,2)

Мой первый вопрос: можно ли передавать параметр self во вложенную функцию метода класса? Я запускаю этот код на python-3.5.2 без проблем, и оба print() отображают один и тот же адрес экземпляра класса A. Однако python-3.6 жалуется на строку print(self, self.a, self.b), что self не имеет члена a.

Также интересно, что PyCharm IDE не выделяет self в этой строке и говорит, что он "затмевает внешнюю область видимости".

Что именно я делаю неправильно?


person Mark    schedule 18.03.2020    source источник
comment
Python 3.6 отлично работает с этим кодом. Вы уверены, что это ошибка Python, а не ошибка/предупреждение PyCharm?   -  person chepner    schedule 18.03.2020
comment
Единственная особенность первого параметра метода экземпляра (имя self просто условное, не обязательное) заключается в том, что вам не нужно указывать явный аргумент. Протокол дескриптора позволяет писать a.func(1,2), а не type(a).func(a, 1, 2).   -  person chepner    schedule 18.03.2020


Ответы (1)


Любая функция, определенная в области видимости, может использовать переменные из окружающей ее области. В данном случае вы определяете функцию внутри функции, поэтому доступны все переменные включающей функции — self, param1, and param2. Таким образом, вы можете передать self в качестве параметра внутренней функции, но поскольку она уже имеет доступ к self, в этом нет особого смысла.

Если вы создаете новые переменные с этими именами внутри своей новой функции, они «затеняют» переменные с этими именами во внешней области, что означает, что имена из внешней области недоступны, пока те же имена ссылаются на что-то еще во внутренней области. . self — это просто обычное имя переменной без особого значения, за исключением того, что это первый параметр функции экземпляра класса, и поэтому он передается неявно, когда метод вызывается с помощью оператора точки, что означает, что он подчиняется этим правилам.

Во внутренней функции вы передаете self явно, что безвредно, но в данном случае также бессмысленно. Python 3.6 (и Pycharm) выдает вам предупреждения, потому что он не может выполнять проверку типов, но это все.

Другими словами, это будет работать так же хорошо и не вызовет ошибок:

def func1(self, param1, param2):
    def inner_func1():
        print(self, self.a, self.b)

    inner_func1()
person Green Cloak Guy    schedule 18.03.2020