Классовое пространство имен без self

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

class Example:
    def inner_method1(self):
        print("abacaba")

    def inner_method2(self):
        inner_method1()


example = Example()
example.inner_method2()

Очевидно, работать так не будет, обращение к полю объекта должно быть таким:

self.inner_method1()

Когда кода много, все эти self'ы режут глаза. Можно ли обойтись без них?

Скорее всего я сам знаю ответ на этот вопрос, хотелось бы услышать ваше мнение, зачем так сделано


Ответы (1 шт):

Автор решения: gil9red

Нельзя. Так заложено архитектурой языка.

Думаю, это можно описать следующей фразой из дзена питона (увидеть можно через import this):

Explicit is better than implicit.

Явное указание на текущий объект self и обращение через него, считаю, помогают ориентироваться в том к какой переменной/функции будет обращение. Ведь, если нет self, cls, то это глобальный объект

В пример ниже будет понятно, что будет вызвано:

def foo():
    print('foo()')


class Example:
    def foo(self):
        print("self.foo()")

    def inner_method2(self):
        foo()
        self.foo()


example = Example()
example.inner_method2()

Результат:

foo()
self.foo()

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

Это отличается от логики в других языках, в которых без this поиск будет сначала внутри класса, например:

  • (https://onlinegdb.com/B_N2BoqQy):

    public class Main
    {
        static void foo() {
           System.out.println("Main.foo");
        }
    
        static void bar() {
            System.out.println("Main.bar");
        }
    
        static class InnerClass {
            InnerClass() {
                foo();
                this.foo();
                bar();
            }
    
            void foo() {
                System.out.println("InnerClass.foo");
            }   
        }
    
        public static void main(String[] args) {
            new InnerClass();
        }
    }
    

    Результат:

    InnerClass.foo
    InnerClass.foo
    Main.bar
    
  • (https://onlinegdb.com/KE7kfoRv8):

    using System;
    
    
    class HelloWorld {
        static void foo() {
           Console.WriteLine("foo");
        }
    
        static void bar() {
           Console.WriteLine("bar");
        }
    
        class InnerClass {
            public InnerClass() {
                foo();
                this.foo();
                bar();
            }
    
            void foo() {
                Console.WriteLine("InnerClass.foo");
            }
        }
    
        static void Main() {
            new InnerClass();
        }
    }
    

    Результат:

    InnerClass.foo
    InnerClass.foo
    Main.bar
    
  • (https://onlinegdb.com/0fns14VmB):

    #include <iostream>
    
    using namespace std;
    
    
    void foo() {
       cout << "foo" << endl;
    }
    
    void bar() {
       cout << "bar" << endl;
    }
    
    class HelloWorld {
    public:
        HelloWorld() {
            foo();
            this->foo();
            bar();
        }
    
        void foo() {
           cout << "HelloWorld.foo" << endl;
        }
    };
    
    
    int main()
    {
        HelloWorld obj;
    
        return 0;
    }
    

    Результат:

    HelloWorld.foo
    HelloWorld.foo
    bar
    

PS.

Когда кода много, все эти self'ы режут глаза

Не знаю... у меня наличие self не вызывало проблем :) Наоборот, это дает понимание какие переменные/функции относятся к текущему объекту, а какие внешние

PPS.

Вместо self можно использовать другое, в данном случае это просто аргумент методов объекта, но так не рекомендуется делать.

В целях образования, пример:

class Example:
    abc = 123

    def foo(this):
        print(this.abc)

    def inner_method2(_):
        _.foo()


example = Example()
example.inner_method2()
→ Ссылка