PythonЧуть более развернутое введение в Python

Для тех, кого заинтересовал пост товарища nuclear, пишу более развернутый вариант введения, с некоторым количеством академического занудства :)
Эта статья расчитана скорее не на новичков в программировании, а на разработчиков на других языках, которые хотят изучить Python, и которым интересно увидеть обзор его синтаксиса.
Примечание: в этой статье символы >>> это не часть кода, а приглашение интерпретатора к вводу команд. Писать его не нужно, оно оставлено только чтобы примеры выглядели точно так же, как то, что увидите вы, если решите их проверить.
Описанное здесь касается Python 2.5, синтаксис 3.x имеет ряд отличий.
Что это за язык?
Пайтон — язык высокого уровня, со строгой динамической типизацией. Поддерживает следующие парадигмы:
— Императивная (структурная)
— Объектно-ориентированная
— Функциональная
Каноническая реализация, CPython представляет собой интерпретатор компилирующего типа.
Для чего его можно применять?
Почти для всего. Он широко используется в разработке веб-приложений, классических десктопных программ, небольших скриптов и как встроенный скриптовый язык внутри других программных продуктов. Кроме того, его используют в своей работе такие организации, как Google и NASA.
Являясь интерпретируемым, он не подходит для приложений с критичной производительностью, но действительно требующие этого части достаточно легко вынести в модули на C.

Существует ли какой-то стандарт, описывающий Python?
Нет. Python очень быстро и динамично развивается, поэтому официальный стандарт, подобный ANSI C, отсутствует. Роль стандарта выполняет синтаксис реализации CPython, поддерживаемой самими разработчиками языка.
Впрочем, быстрое развитие не означает отсутствие обратной совместимости. Исключением является недавний переход от ветки 2.x к 3.x, синтаксис которых не совместим между собой в виду большого количества изменений. Но такое случается очень редко.

Перейдем к синтаксису языка.
Переменные и типы данных
Объявлять переменные и явно указывать их тип не нужно, они инициализируются при первом использовании. Но то, что тип не нужно указывать, не значит, что его нет. Посмотрим на примеры:
i = 12 # Целое число
 f = 3.14159 # Число с плавающей точкой
 s = "fgsfds" # Строка ASCII
 u = u"строка" # Строка Unicode

Вы можете узнать тип переменной, прочитав ее поле __class__ (те, кто не знают про ООП могут рассматривать это как магическое заклинание).
>>> print(s.__class__)
<type 'str'>
>>> print(f.__class__)
<type 'float'>
>>> print(u.__class__)
<type 'unicode'>

Оператор вывода
Для вывода значений используется оператор print. Он поддерживает несколько параметров через запятую, а также форматный вывод. Важное замечание: в Python 2.x оператор print не требует скобок. В 3.x они обязательны. Поэтому если возможно, то лучше их писать (в тех случаях, когда они не повлияют на семантику).
>>> print("gfdf")
gfdf
>>> print "gfgfd", 50 # Здесь скобки в 2.x писать не стоит, интерпретатор воспримет их как описание кортежа
gfgfd 50
>>> print "Hello, %s!" % "username"
Hello, username!


Структуры данных
Язык поддерживает многие классические структуры данных. Среди них списки, кортежи и словари (они же ассоциативные массивы или хэши).
Список:

>>> list = [] # Так объявляется пустой список
>>> list = [1, 2, 5, "q"] # Так список с элементами. Обратите внимание, что они могут быть разных типов.
>>> print list # Вывести список можно целиком, а не поэлементно
[1, 2, 5, 'q']
>>> list.append(14) # Добавим в конец списка элемент.
>>> print list
[1, 2, 5, 'q', 14]
>>> list.remove(2) # Можно удалить элемент с заданным значением
>>> print list
[1, 5, 'q', 14]
>>> print list[-2] # Отрицательный индекс означает нумерацию с конца списка, а не сначала.
5
>>> print list[1:3] # Срез списка. Получает подсписок, состоящий из элементов, стоящих между индексами.
[5, 'q']
# Запись срезов возможна и с одним параметром
>>> print(list[:3]) # Выведет первые три элемента
[1, 5, 'q']
>>> print(list[2:]) # Выведет элементы, начиная со второго
['q', 14]

Встроенные функции позволяют использовать спискок как очередь или стек. Нумерация элементов начинается с нуля.
Лирическое отступление: кто верно скажет, в каком еще языке были срезы массивов и отрицательные индексы, получит в подарок первую версию OS/360 на перфоленте :)
Кортеж
Представляет собой неизменяемый список. Записывается вот так:
>>> t = ()
>>> t = ('a', 3, 10)

Словарь
Словарь похож на список, но индексами у него служат не числа, а произвольные значения. Он состоит из пар «ключ: значение».
>>> dict = {} # Пустой словарь
>>> dict = { 1: "a", 2: "b" } # Словарь с элементами
>>> print dict
{1: 'a', 2: 'b'} 
>>> dict.keys() # Получим все ключи (ключ — аналог индекса списка)
[1, 2] 
>>> dict.values() # Получим значения
['a', 'b']
>>> dict.items() # Получим все элементы. Выдаются в виде списка кортежей
[(1, 'a'), (2, 'b')]


Арифметические и логические операторы
Сложение и вычитание пишутся очевидным образом: + и -. Для деления используется /, для всех типов чисел (различаться по типу будет результат). Для взятия остатка используется % ( 5 % 2 вернет 1).
Логические операции:
— «<», «>», «<=», «>=». Очевидны.
— Проверка на неравенство: !=
— Проверка на равенство: ==
— Принадлежность списку или другой структуре: in (пример: if 1 in [1, 2, 3] )
Отдельного упоминания заслуживает оператор присваивания. Он может быть использован для множественного присваивания, например a, b = 1, 2; или даже a, b = b, a (последнее действительно поменяет значения переменных местами).

Операторы управления потоком
Здесь мы рассмотрим условный оператор и циклы. Нужно учитывать, что никаких специальных операторов, обозначающих блоки кода (вроде { } или begin end) в Пайтоне нет, вложенность определяется глубиной отступа. Блоком кода будут строки, у которых она одинакова.
Условный оператор
>>> a = 3
>>> if a == 3: # Краткая форма, без второй ветви
...     print "Yes, a equals 3!"
Yes, a equals 3!

>>> if a == 3: # Со второй ветвью
...     print "Yes, a equals 3!"
... else:
...     print "No, unfortunately a does not equal 3"

>>> if a == 5: # Для длинных условных операторов существует специальный синтаксис
...     print "Yes, a equals 5!"
... elif a == 3:
...     print "Yes, a equals 3!"
... else:
...     print "No, a does not equal 3 or 5"
... 
Yes, a equals 3!

Оператора выбора (вроде switch в C или case of в Pascal) в Пайтоне нет.
Цикл по элементам структуры данных
>>> for i in list:
...   print i
... 
1
5
q
14

>>> for i in range(4, 6): # Для диапазона значений можно использовать функцию range() или xrange().
...   print i
... 
4
5

Функции range() и xrange() различаются тем, что первая действительно создает список, а вторая нет. Поэтому xrange() стоит использовать при больших диапазонах, которые могут занимать слишком много памяти.

>>> l = range(1, 10)
>>> print l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x = xrange(1,100000)
>>> print x
xrange(1, 100000)

Если вызвать их с одним аргументом, диапазон будет от нуля до его значения.
>>> for i in range(6):
...   print i
... 
0
1
2
3
4
5

Цикл с предусловием
Примера кода будет достаточно, чтобы понять, как он пишется.
>>> a = 0
>>> while a < 5:
...   print a
...   a = a +1
... 
0
1
2
3
4

Определение новых функций:
>>> def square(x):
...     return x*x
... 
>>> print square(4)
16
# Функция со значением аргумента по умолчанию:
>>> def hello( name="world" ):
...   print "Hello, ", name
... 
>>> hello() # Если ее вызвать без аргументов, она использует значение по умолчанию
Hello,  world
>>> hello("open-life.org") # А если указать значение аргумента, то использует его
Hello,  open-life.org

Анонимные функции
Анонимная функция не имеет собственного имени. Записывается с использованием ключевого слова lambda.
>>> (lambda x: x+1)(40)
41
>>> f = lambda x: x+1 # Ее можно даже присвоить переменной
>>> f(30) # А потом вызвать по имени
31
>>> map( f, [2, 3, 4] ) # А вот так можно применить функцию ко всему списку сразу
[3, 4, 5]

Генераторы
Генератор это функция, сохраняющая внутреннее состояние. Но это только звучит устрашающе, на самом деле очень удобная штука :)
>>> def gen(): # Определение генератора отличается от функции только тем, что вместо return используется yield
...   x = 0
...   while x < 5:
...     yield x
...     x = x + 1
... 
>>> for i in gen():
...   print i
... 
0
1
2
3
4

Как видно из примера, генератор исправно вернул нам пять значения, каждое следующее на единицу больше предыдущего. Если вы помните xrange(), то она точно такой же природы.
Объектно-ориентированное программирование
Посмотрим простой пример создания класса и объекта.
>>> class Foo(): # Определяем класс
...   def __init__(self): # Метод __init__ это конструктор.
...     print "Object has been created"
...   field = 1
...   def method(self):
...     print "I am a fine method!"
... 
>>> foo = Foo()
Object has been created
>>> print foo.field
1
>>> foo.method()
I am a fine method!

Никакого специального синтаксиса для private и protected нет, но есть соглашение, что protected должны иметь имя, начинающиеся с символа «_», а private с «__».
Теперь простой пример наследования:
>>> class Bar(Foo):
...   anotherField = 2
... 
>>> bar = Bar()
Object has been created
>>> print bar.field
1
>>> bar.method()
I am a fine method!
>>> print bar.anotherField
2

Python поддерживает множественное наследование. Вот пример:
>>> class Foobar(Foo, Bar):
...   def anotherMethod(self):
...     print "I am another method!"
... 
>>> foobar = Foobar()
Object has been created
>>> print foobar.field
1
>>> print foobar.anotherField
2
>>> foobar.anotherMethod()
I am another method!

В Python классы сами являются объектами. Да собственно, там все является объектом, даже переменные и функции.
Заключение
Мы рассмотрели основы синтаксиса языка Python. Хочется верить, что этот обзор помог вам решить, хотите ли вы изучать этот язык, или узнать о нем что-то новое.

P.S.
Всякая критика и пожелания очень приветствуются.

Комментарии (20)

Мне понравилось, очень даже. Только кат повыше сделайте =)
Ушел читать внимательно :)
Сделал повыше. И правда силишком много оставил в анонсе.
Я дальше планировал кратко описать wxpython.
Может это сделаете вы или вместе? Или может вы опишите другой Gui?
Лучше вы опишите wxPython, а я pyGTK. Тогда у читателей будет возможность сравнить и выбрать себе библиотеку по вкусу.
Так и сделаем ;)
Тогда осталось чтоб питоно-kdeшник описал pyqt4.
Если кдешники не найдутся, можно будет совместными усилиями :)
Понравилось, так держать.
  • avatar
  • LRN
  • 27 июля 2009, 17:07
  • #
  • 0
Та же претензия, что и к «краткому» введению — используется print вместо print()
Поскольку присутствует академическое занудство, можно было бы упомянуть о том, что присваивание — это на самом деле alias (на эти грабли часто наступают)
По-хорошему следовало бы упомянуть об утиной типизации Питона (в конце концов, Питон вообще весь объектный, «под капюшоном»).
Про print я упомянул, что речь идет о 2.5, функцией он стал в 3.0
Про alias и утиную типизацию разумно, надо дописать, но думаю, на уровне упоминания. По-хорошему про это надо отдельную подробную статью, но потом.
Не так давно начал изучать python, после 4 лет PHP, я просто в восторге.

Возникло пару замечаний к статье:

1. Наверное, стоило бы чуть глубже раскрыть тему срезов списков, в частности срезы вида list[2:] и list[:4] — такие штуки часто бывают полезны;

2. Если я не ошибаюсь, функции, которые Вы назвали анонимными так и называются — лямбда-функции.

3. Также Вы не упомянули о self в параметрах методов и зачем он нужен — такого в других языках, насколько я помню, не существует, поэтому вводная статья должна освещать этот вопрос.

4. Хотелось бы больше узнать про версии и их различия, какую лучше где использовать и почему.
На последний вопрос можно ответить сразу: сейчас логичнее использовать 2.6, потому что на 3.x портированы еще не все распространенные библиотеки, и (в случае веб-приложений) его почти нет на хостингах. Различий там полно, многие из них касаются ООП.
Анонимная функция достаточно распространенный термин, поэтому я и употребил именно его.
Про срезы и self напишу, но уже завтра. Предыдущие пожелания тоже учту.
Я уже жду :)
> Лирическое отступление: кто верно скажет, в каком еще языке были срезы массивов и отрицательные индексы, получит в подарок первую версию OS/360 на перфоленте :)

Я два знаю, один современный японский, второй — почти умерший, но говорят (давно уже говорят, но без толку), что он возродиться в 6й версии :)
Ах да, ещё один забыл — малоизвестный, написан в семидесятых, название можно перевести, как «Картина» (это если ещё кто-то поугадывать захочет, чтобы кайф не ломать).
Ого, какой язык вспомнили. Но о нем у меня не особо хорошее представление, я имел в виду несколько другой. Первый в мире язык высокого уровня :)
> Первый в мире язык высокого уровня
Ну, с такими подсказками не интерестно :) «Транслятор формул», я ему почти пол-года когда-то посвятил…
Отличная статья! Правда-правда, лучше про Python еще не читал (=

Пожелание: напишите, пожалуйста, про применение пайтона в web-программировании — у вас хорошо получается писать)))
> Лирическое отступление: кто верно скажет, в каком еще языке были срезы массивов и отрицательные индексы, получит в подарок первую версию OS/360 на перфоленте :)

В Perl'е есть и срезы и отрицательные индексы. А также срезы и подобные индексы можно было применять в скриптах под Vim, если ничего не путаю…

По поводу статьи — просто «пять с плюсом». Сам сел за Python в начале месяца… После брутальной литературы, подобные «живые» обзоры читаются легко и приятно!
  • avatar
  • LRN
  • 23 мая 2010, 21:30
  • #
  • 0
from __future__ import print_function

a = 3

def somefun ():
  a = 1
  if a == 1:
    print ("a == 1! {0}".format (a))
    a = 2
    print ("a == 2? {0}".format (a))
    def fun2 (arg):
      a = 5
      print ("arg == {0}".format (arg))

  print ("Now a == {0}".format (a))

  fun2 (a)

  print ("a before leaving somefun() == {0}".format (a))

a = 4

somefun()

print ("global a = {0}".format (a))

Вопрос для зубров: что выведет на stdout интерпретатор? Чтобы узнать это, не запуская интерпретатор, надо знать о том, как и чем в Питоне образуются скопы, и в каком порядке они просматриваются.

В частности, в отличие от C, в Питоне простые стэйтменты управления потоком вычисления (flow control; то есть if, for, while) не имеют собственного скопа, а переменные из глобального скопа являются read-only: попытка записать что-то в такую переменную без предварительной декларации её в качестве global в локальном скопе ведёт к созданию локальной переменной с тем же именем, с которой и проводятся все последующие операции.
Кстати, почему в комментах нет хайлайта синтаксиса, как в основной статье?
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.