Область видимости переменной Python

Я учу себя самому Python, и я переводил некоторый пример кода в этот

class Student(object):
    def __init__( self, name, a,b,c ):
        self.name = name
        self.a = a
        self.b = b
        self.c = c

    def average(self):
        return ( a+b+c ) / 3.0 

Что в значительной степени мое определение класса

Позже в основном методе я создаю экземпляр и вызываю его a

if __name__ == "__main__" :
    a = Student( "Oscar", 10, 10, 10 )

Вот так я узнаю, что переменная a объявлено в main доступен для метода average и чтобы этот метод работал, я должен напечатать self.a + self.b + self.c вместо

В чем причина этого?

Я нашел связанные вопросы, но я действительно не знаю, если они примерно одинаковы

3 ответа

Решение

Barenames (как a, b, c) всегда ограничены как локальные или глобальные (за исключением вложенных функций, которых нет в вашем коде). Логическое обоснование состоит в том, что добавление дополнительных областей действия излишне усложнит ситуацию - например, если в вашем self.a = a голое имя a может означать, что вы хотите (эквивалентно self.a) тогда само присвоение будет бессмысленным (присвоение имени себе), поэтому вам понадобятся более сложные правила.

Просто используя квалифицированные имена (например, self.a) когда вам нужно нечто иное, чем простое, понятное и оптимизированное поведение без имен, это, безусловно, самый простой подход - идеально работоспособный, без сложных правил вообще, и позволяет компилятору эффективно оптимизировать вещи (поскольку, например, область действия голого имени всегда лексическая) определяется, не зависит от динамически изменяющихся характеристик окружающей среды). Таким образом, кроме, возможно, ностальгии по другим языкам с более сложными правилами области видимости, на самом деле нет смысла усложнять семантику голых имен.

Есть несколько причин, хотя основная из них от Zen of Python: "Явное лучше, чем неявное". В таком языке, как C++, метод класса всегда имеет неявный аргумент this который помещается в стек каждый раз, когда вызывается метод. В этом случае, когда переменная экземпляра b существует, а также глобальная переменная bто пользователь может просто сослаться на b ссылаясь на один, не понимая, что будет использоваться другой. Таким образом, Python заставляет вас четко указывать свои возможности, чтобы избежать путаницы.

С учетом вышесказанного есть и другие причины. Например, я могу определить функцию вне класса, а затем присоединить ее к классу во время выполнения. Например:

def log(self):
    print "some library function requires all objects to have a log method"
    print "unfortunately we're using the Student class, which doesn't have one"
    print "this class is defined in a separate library, so we can't add the method"
    print "fortunately, we can just add the method dynamically at runtime"

Student.log = log

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

Вот еще более сложный пример; Предположим, мы хотим определить класс внутри другого класса, например, для целей модульного тестирования:

class SomeUnitTests(TestCase):
    def test_something(self):
        class SomeMockObject(SomeActualObject):
            def foo(self2):
                self.assertEqual(self2.x, SOME_CONSTANT)

        some_lib.do_something_with(SomeMockObject)

Здесь наличие явного "я" (которое мы можем называть как угодно, оно не обязательно должно быть "я") позволяет различать self внутреннего и внешнего классов. Опять же, это не то, что я делаю часто, но когда я это делаю, это невероятно полезно.

Все переменные экземпляра должны вызываться с использованием self

Другие вопросы по тегам