Область видимости переменной 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