область видимости переменной Python - PullRequest
7 голосов
/ 20 апреля 2010

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

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 ]

9 голосов
/ 20 апреля 2010

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

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

2 голосов
/ 20 апреля 2010

Есть несколько причин, хотя главная из них от 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 внутреннего и внешнего классов. Опять же, это не то, что я делаю часто, но когда я делаю это, это невероятно полезно.

0 голосов
/ 20 апреля 2010

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

...