Содержание

Часто задаваемые вопросы | Python 3 для начинающих и чайников

Некоторые не совсем очевидные вещи, с которыми сталкиваются начинающие программисты Python.

Почему я получаю исключение UnboundLocalError, хотя переменная имеет значение?

Может показаться неожиданным получить UnboundLocalError в ранее работающем коде, в который добавили операцию присваивания где-то внутри функции.

Этот код:

>>> x = 10
>>> def bar():
...     print(x)
>>> bar()
10

работает, но следующий код:

>>> x = 10
>>> def foo():
...     print(x)
...     x += 1

приводит к UnboundLocalError:

>>> foo()
Traceback (most recent call last):
  ...
UnboundLocalError: local variable 'x' referenced before assignment

Это происходит потому, что, когда вы делаете присваивание переменной в области видимости, она становится локальной в этой области и скрывает другие переменные с таким же именем во внешних областях.

Когда последняя инструкция в foo присваивает новое значение переменной x, компилятор решает, что это локальная переменная. Следовательно, когда более ранний print пытается напечатать неинициализированную переменную, возникает ошибка.

В примере выше можно получить доступ к переменной, объявив её глобальной:

>>> x = 10
>>> def foobar():
...     global x
...     print(x)
...     x += 1
>>> foobar()
10

Это явное объявление требуется для того, чтобы напомнить вам, что (в отличие от внешне аналогичной ситуации с переменными класса и экземпляра), вы на самом деле, изменяете значение переменной во внешней области видимости:

>>> print(x)
11

Вы можете сделать подобную вещь во вложенной области видимости использованием ключевого слова nonlocal:

>>> def foo():
...    x = 10
...    def bar():
...        nonlocal x
...        print(x)
...        x += 1
...    bar()
...    print(x)
>>> foo()
10
11

Каковы правила для глобальных и локальных переменных в Python?

В Python, переменные, на которые только ссылаются внутри функции, считаются глобальными. Если переменной присваивается новое значение где-либо в теле функции, считается, что она локальная, и, если вам нужно, то нужно явно указывать её глобальной.

Хотя это немного удивительно на первый взгляд, это легко объяснимо. С одной стороны, требование global для присваиваемых переменных предотвращает непреднамеренные побочные эффекты в bar. С другой стороны, если global был обязательным для всех глобальных ссылок, вы бы использовали global все время. Вы должны были бы объявить как глобальную каждую ссылку на встроенную функцию или компонент импортируемого модуля.

Почему анонимные функции (lambda), определенные в цикле с разными значениями, возвращают один и тот же результат?

Например, вы написали следующий код:

>>> squares = []
>>> for x in range(5):
...    squares.append(lambda: x**2)

Это даёт вам список из 5 функций, считающих x**2. Можно ожидать, что, будучи вызванными, они вернут, соответственно, 0, 1, 4, 9, и 16. Однако, вы увидите, что все они возвращают 16:

>>> squares[2]()
16
>>> squares[4]()
16

Это случается, поскольку x не является локальной для lambda, а определена во внешней области видимости, и получается тогда, когда она вызывается — а не когда определяется.

В конце цикла, x=4, поэтому все функции возвращают 4**2, то есть 16. Это можно также проверить, изменив значение x и посмотрев на результат:

>>> x = 8
>>> squares[2]()
64

Чтобы избежать подобного, необходимо сохранять значения переменных локально:

>>> squares = []
>>> for x in range(5):
...    squares.append(lambda n=x: n**2)

Здесь, n=x создаёт локальную для функции переменную n и вычисляется в момент определения функции:

>>> squares[2]()
4
>>> squares[4]()
16

Это применимо не только к анонимным, а также и к обычным функциям.

Как организовать совместный доступ к глобальным переменным для нескольких модулей?

Канонический способ организовать подобный доступ — это создать отдельный модуль (часто называемый config или cfg). Просто добавьте import config в каждый модуль приложения. При этом модуль становится доступен через глобальное имя. Поскольку существует только один экземпляр модуля, любые изменения, произведённые в модуле отражаются везде.

Например:

config.py:

x = 0

mod.py:

import config
config.x = 1

main.py:

import config
import mod
print(config.x)

По тем же соображениям, модули можно использовать как основу для имплементации синглтона.

Как правильнее использовать импортирование?

В общих случаях не используйте from modulename import *. Это засоряет пространство имён того, кто импортирует. Некоторые люди избегают этой идиомы даже для тех немногих модулей, которые были спроектированны, чтобы так импортироваться. Это такие модули как Tkinter и threading.

Импортируйте модули в начале файла. Это отвечает на вопрос, какие модули требует Ваш код и находится ли имя модуля в области видимости. Запись по одному импорту на строку упрощает добавление и удаление операторов импорта, но множественный импорт будет занимать меньше места на экране.

Хорошая практика, если Вы импортируете модули в следующем порядке:

  • стандартные библиотечные модули (например, sys, os, getopt, re)
  • модули сторонних разработчиков (всё, что установлено в директории site-packages) — например, PIL, NumPy и т. д.
  • локально созданные модули

Иногда бывает необходимо поместить импорт в функцию или класс, чтобы избежать проблем с циклическим импортом. Gordon McMillan советует:

Циклический импорт отлично работает, если оба модуля используют форму import <module>. Но они терпят неудачу, когда второй модуль хочет извлечь имя из первого (from module import name) и импорт находится на внешнем уровне. Это происходит из-за того, что имена первого модуля ещё недоступны, так как первый модуль занят импортом второго.

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

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

Переносите импорт во вложенные области видимости, такие как определения функций, только если Вы столкнулись с проблемой, например циклического импорта, или если Вы пытаетесь сократить время инициализации модуля.

Эта техника полезна, если многие из импортов не являются необходимыми, и зависят от того, как программа будет исполняться. Вы также можете поместить импорт в функцию, если конкретные модули используются только в этой функции. Обратите внимание, что загрузить модуль в первый раз может оказаться дорого из-за задержки на инициализацию модуля, однако повторные загрузки «бесплатны», они стоят только пары поисков в словарях. Даже если имя модуля исчезло из области видимости, модуль скорее всего до сих пор находится в sys.modules.

Почему значения по умолчанию разделяются между объектами?

Этот тип ошибки часто встречается среди начинающих. Предположим, функция:

def foo(mydict={}):  # Опасность: разделяемая ссылка между вызовами
    ... compute something .
.. mydict[key] = value return mydict

В первый раз, когда вы вызываете функцию, mydict содержит одно значение. Второй раз, mydict содержит 2 элемента, поскольку, когда foo() начинает выполняться, mydict уже содержит элемент.

Часто ожидается, что вызов функции создаёт новые объекты для значений по умолчанию. Но это не так. Значения по умолчанию создаются лишь однажды, когда функция определяется. Если этот объект изменяется, как словарь в нашем примере, последующие вызовы функции будут использовать изменённый объект.

По определению, неизменяемые объекты (числа, строки, кортежи и None), безопасны при изменении. Изменение изменяемых объектов, таких как словари, списки, и экземпляры пользовательских классов может привести к неожиданным последствиям.

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

Например, не пишите:

def foo(mydict={}):
    ...

Но пишите так:

def foo(mydict=None):
    if mydict is None:
        mydict = {}  # create a new dict for local namespace

Однако, эта особенность может быть полезна. Когда у вас есть функция, которая долго выполняется, часто применяемая техника — кэширование параметров и результата каждого вызова функции:

def expensive(arg1, arg2, _cache={}):
    if (arg1, arg2) in _cache:
        return _cache[(arg1, arg2)]

    # Расчёт значения
    result = ... expensive computation ...
    _cache[(arg1, arg2)] = result     # Кладём результат в кэш
    return result

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

Получить такие параметры можно с помощью спецификаторов * и ** в списке аргументов функции; они возвращают кортеж позиционных аргументов и словарь именованых параметров. После этого Вы можете передать их в другую функцию, используя в её вызове * и **:

def f(x, *args, **kwargs):
    . ..
    kwargs['width'] = '14.3c'
    ...
    g(x, *args, **kwargs)

Почему изменение списка ‘y’ изменяет также список ‘x’?

Если вы написали код:

>>> x = []
>>> y = x
>>> y.append(10)
>>> y
[10]
>>> x
[10]

вы, возможно, будете удивлены тому, что добавление в y изменяет также и x.

Два факта приводят к такому результату:

  • Переменные — это просто ссылки на объекты. y = x не создаёт копию списка — это просто создаёт переменную y, которая ссылается на тот же объект, что и x.
  • Списки изменяемы.

После вызова append, содержимое объекта было изменено с [] на [10]. Поскольку x и y ссылаются на один и тот же объект, использование любого из них даёт нам [10].

Если мы используем неизменяемые объекты:

>>> x = 5  # числа неизменяемы
>>> y = x
>>> x = x + 1  # 5 нельзя изменить. Мы создаём НОВЫЙ объект
>>> x
6
>>> y
5

мы можем видеть, что x и y больше не равны, поскольку числа неизменяемы, и x = x + 1 не изменяет число 5 путем увеличения. Вместо этого, создаётся новый объект 6 и присваивается переменной x (то есть, изменяется то, на какой объект ссылается x). После этого у нас 2 объекта (6 и 5) и 2 переменные, которые на них ссылаются.

Некоторые операции (например y.append(10) и y.sort()) изменяют объект, в то время, как внешне похожие операции (например y = y + [10] и sorted(y)) создают новый объект. Вообще в Python (и во всех случаях в стандартной библиотеке), метод, который изменяет объект, возвращает None, чтобы помочь избежать ошибок. Поэтому, если вы написали

y = y.sort()

думая, что это даст вам отсортированную копию y, вы вместо этого получите None, что скорее всего приведёт к легко диагностируемой ошибке.

Однако, существует один класс операций, где одна и та же операция ведёт себя по-разному с различными типами: расширенные операторы присваивания. Например, += изменяет списки, но не кортежи или числа (a_list += [1, 2, 3] эквивалентно a_list.extend([1, 2, 3])) и изменяет список, в то время, как some_tuple += (1, 2, 3) и some_int += 1 создают новый объект.

Если вы хотите знать, ссылаются ли 2 переменные на один объект или нет, вы можете использовать оператор is, или встроенную функцию id.

Как создавать функции более высокого порядка?

Есть два пути: использовать вложенные функции или вызываемые объекты. Например, с использованием вложенных функций:

def linear(a, b):
    def result(x):
        return a * x + b
    return result

Использование вызываемого объекта:

class linear:

    def __init__(self, a, b):
        self.a, self.b = a, b

    def __call__(self, x):
        return self.a * x + self.b

В обоих случаях,

taxes = linear(0.3, 2)

даёт функцию, что (к примеру) taxes(10e6) == 0.3 * 10e6 + 2.

Использование вызываемого объекта — немного медленнее, и в результате получается больше кода. Однако, заметьте, что несколько функций могут разделять свою сигнатуру с помощью наследования:

class exponential(linear):
    # __init__ наследуется
    def __call__(self, x):
        return self. a * (x ** self.b)

Объект может сохранять свое состояние для нескольких вызовов:

class counter:

    value = 0

    def set(self, x):
        self.value = x

    def up(self):
        self.value = self.value + 1

    def down(self):
        self.value = self.value - 1

count = counter()
inc, dec, reset = count.up, count.down, count.set

Здесь inc, dec, reset выступают в роли функций, которые разделяют одну и ту же переменную.

Как скопировать объект в Python?

В общем случае, с помощью модуля copy.

Некоторые объекты можно скопировать более просто. Словари имеют метод copy:

newdict = olddict.copy()

Последовательности могут быть скопированы путём срезов:

new_l = l[:]

Как узнать доступные методы и атрибуты объекта?

dir(x) возвращает список методов и атрибутов.

Как можно узнать имя объекта?

Вообще говоря, никак, поскольку объекты в действительности не имеют имён. Важно: присваивание всегда связывает имя с объектом. Это верно и для инструкций def и class.

>>> class A:
...    pass
...
>>> B = A
>>>
>>> a = B()
>>> b = a
>>> print(b)
<__main__.A object at 0x7fbcc3ee5160>
>>> print(a)
<__main__.A object at 0x7fbcc3ee5160>

Возможно, класс имеет имя: однако, хотя он связан с двумя именами и запрашивается через имя B, созданный экземпляр всё ещё считается экземпляром класса A. Однако, невозможно сказать, имя экземпляра a или b, поскольку оба они связаны с одним и тем же значением.

Какой приоритет у оператора «запятая»?

Запятая не является оператором в Python.

>>> "a" in "b", "a"
(False, 'a')

Поскольку запятая — не оператор, но разделитель между выражениями, пример выше исполняется как если бы было введено:

("a" in "b"), "a"

А не

"a" in ("b", "a")

То же самое верно и для операторов присваивания (=, += и другие). Они не являются операторами как таковыми, а лишь синтаксическими разделителями в операциях присваивания.

Есть ли в Python эквивалент тернарного оператора «?:» в C?

Да. Синтаксис:

[on_true] if [expression] else [on_false]
x, y = 50, 25
small = x if x < y else y

Можно ли писать обфусцированные однострочники?

Можно.

from functools import reduce

# Простые числа < 1000
print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))

# Первые 10 чисел Фибоначчи
print(list(map(lambda x,f=lambda x,f:(f(x-1,f)+f(x-2,f)) if x>1 else 1:
f(x,f), range(10))))

# Множество Мандельброта
print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y,
Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,
Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,
i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y
>=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(
64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy
))))(-2. 1, 0.7, -1.2, 1.2, 30, 80, 24))
#    \___ ___/  \___ ___/  |   |   |__ lines on screen
#        V          V      |   |______ columns on screen
#        |          |      |__________ maximum of "iterations"
#        |          |_________________ range on y axis
#        |____________________________ range on x axis

Не пытайтесь это делать дома!

Почему -22 // 10 равно -3?

Поскольку i % j имеет тот же знак, что j. А ещё

i == (i // j) * j + (i % j)

Как можно изменить строку?

Никак, поскольку строки неизменяемы. В большинстве ситуаций, нужно просто сделать новую строку из различных частей. Однако, если так нужно, можно использовать io.StringIO, либо модуль array:

>>> import io
>>> s = "Hello, world"
>>> sio = io.StringIO(s)
>>> sio.getvalue()
'Hello, world'
>>> sio.seek(7)
7
>>> sio.write("there!")
6
>>> sio.getvalue()
'Hello, there!'

>>> import array
>>> a = array. array('u', s)
>>> print(a)
array('u', 'Hello, world')
>>> a[0] = 'y'
>>> print(a)
array('u', 'yello, world')
>>> a.tounicode()
'yello, world'

Как использовать строки для вызова функций/методов?

Существует несколько приёмов.

  • Лучший — использование словаря, ставящего соответствие строке функцию. Его главное достоинство — строки не обязаны совпадать с названиями функций.
def a():
    pass

def b():
    pass

dispatch = {'go': a, 'stop': b}  # Note lack of parens for funcs

dispatch[get_input()]()
  • Использование встроенной функции getattr:
import foo
getattr(foo, 'bar')()
  • Использование locals или eval (не рекомендуется)
def myFunc():
    print("hello")

fname = "myFunc"

f = locals()[fname]
f()

f = eval(fname)
f()

Как удалить все символы новой строки в конце строки?

Можно использовать S.rstrip(«\r\n») для удаления символов новой строки, без удаления конечных пробелов:

>>> lines = ("line 1 \r\n"
. ..          "\r\n"
...          "\r\n")
>>> lines.rstrip("\r\n")
'line 1 '

Как создать многомерный список?

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

>>> A = [[None] * 2] * 3

Это выглядит правильно, если напечатать:

>>> A
[[None, None], [None, None], [None, None]]

Но если вы присвоите значение, то оно появится в нескольких местах:

>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]

Причина в том, что оператор * не создаёт копию, а только ссылку на существующий объект. *3 создаёт список из 3 ссылок на один и тот же список. Изменение в одной строке изменяют другие, что, вероятно, не то, что вы хотите.

Возможные пути решения:

A = [None] * 3
for i in range(3):
    A[i] = [None] * 2
w, h = 2, 3
A = [[None] * w for i in range(h)]

Или, можно использовать специальные модули, предоставляющие матрицы. Наиболее известным является NumPy.

Почему a_tuple[i] += [‘item’] не работает, а добавление работает?

Это из-за того, что расширенный оператор присваивания — оператор присваивания, а также из-за разницы между изменяемыми и неизменяемыми объектами в Python.

Это обсуждение относится в общем, когда расширенные операторы присваивания применяются к элементам кортежа, которые указывают на изменяемые объекты, но мы будем использовать список и +=, как образец.

Если вы напишете:

>>> a_tuple = (1, 2)
>>> a_tuple[0] += 1
Traceback (most recent call last):
  ...
TypeError: 'tuple' object does not support item assignment

Причина исключения должна быть понятна: 1 добавляется к объекту a_tuple[0], но когда мы пытаемся присвоить результат, 2, к первому элементу в кортеже, мы получаем ошибку, поскольку мы не можем изменить элемент кортежа.

То есть, это выражение делает следующее:

>>> result = a_tuple[0] + 1
>>> a_tuple[0] = result
Traceback (most recent call last):
 ...
TypeError: 'tuple' object does not support item assignment

Когда мы пишем что-то вроде:

>>> a_tuple = (['foo'], 'bar')
>>> a_tuple[0] += ['item']
Traceback (most recent call last):
 . ..
TypeError: 'tuple' object does not support item assignment

Исключение немного более неожиданное, но более удивителен тот факт, что, несмотря на ошибку, элемент добавился!

>>> a_tuple[0]
['foo', 'item']

Чтобы понять, что случилось, нужно знать, что:

  • Если объект определяет метод __iadd__, он вызывается, когда выполняется +=, и возвращенное значение используется для присваивания
  • Для списков, __iadd__ эквивалентен вызову extend для списка

Таким образом,

>>> a_list = []
>>> a_list += [1]
>>> a_list
[1]

Эквивалентен:

>>> result = a_list.__iadd__([1])
>>> a_list = result

Таким образом, наш пример с кортежом эквивалентен:

>>> result = a_tuple[0].__iadd__(['item'])
>>> a_tuple[0] = result
Traceback (most recent call last):
  ...
TypeError: 'tuple' object does not support item assignment

__iadd__ завершился успешно, и список увеличился, но присваивание законилось ошибкой.

Как объявить переменную в Python? Какие типы данных поддерживаются?

Python является полностью объектно-ориентированным, а не «статически типизированным». Вам не нужно объявлять переменные перед их использованием или объявлять их тип. Каждая переменная в Python является объектом.

В этом уроке будут рассмотрены несколько основных типов переменных.

Числа

Python поддерживает два типа чисел — целые числа и числа с плавающей точкой. (Он также поддерживает комплексные числа, которые не будут объясняться в этом уроке).

Чтобы определить целое число, используйте следующий синтаксис:

myint = 7
print(myint)

Чтобы определить число с плавающей запятой, вы можете использовать одно из следующих обозначений:

myfloat = 7.0
print(myfloat)
myfloat = float(7)
print(myfloat)

Строки

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

mystring = 'hello'
print(mystring)
mystring = "hello"
print(mystring)

Разница между ними заключается в том, что использование двойных кавычек позволяет легко включать апострофы (тогда как при использовании одинарных кавычек они завершают строку)

mystring = "Don't worry about apostrophes"
print(mystring)

Существуют дополнительные варианты определения строк, которые облегчают включение таких вещей, как возврат каретки, обратная косая черта и символы Unicode. Они выходят за рамки этого руководства, но описаны в документации по Python.

Простые операторы могут быть выполнены для чисел и строк:

one = 1
two = 2
three = one + two
print(three)

hello = "hello"
world = "world"
helloworld = hello + " " + world
print(helloworld)

Назначения могут быть сделаны для более чем одной переменной «одновременно» в одной строке следующим образом

a, b = 3, 4
print(a,b)

Смешивание операторов между числами и строками не поддерживается:

# This will not work!
one = 1
two = 2
hello = "hello"

print(one + two + hello)

Упражнение

Цель этого упражнения — создать строку, целое число и число с плавающей запятой. Строка должна называться mystring и содержать слово «hello». Число с плавающей запятой должно называться myfloat и должно содержать число 10.0, а целое число должно называться myint и должно содержать число 20.

# change this code mystring = None myfloat = None myint = None # testing code if mystring == "hello": print("String: %s" % mystring) if isinstance(myfloat, float) and myfloat == 10. 0: print("Float: %f" % myfloat) if isinstance(myint, int) and myint == 20: print("Integer: %d" % myint) # change this code mystring = "hello" myfloat = 10.0 myint = 20 # testing code if mystring == "hello": print("String: %s" % mystring) if isinstance(myfloat, float) and myfloat == 10.0: print("Float: %f" % myfloat) if isinstance(myint, int) and myint == 20: print("Integer: %d" % myint) test_object('mystring', incorrect_msg="Don't forget to change `mystring` to the correct value from the Упражнение description.") test_object('myfloat', incorrect_msg="Don't forget to change `myfloat` to the correct value from the Упражнение description.") test_object('myint', incorrect_msg="Don't forget to change `myint` to the correct value from the Упражнение description.") test_output_contains("String: hello",no_output_msg= "Make sure your string matches exactly to the Упражнение desciption.") test_output_contains("Float: 10.000000",no_output_msg= "Make sure your float matches exactly to the Упражнение desciption. ") test_output_contains("Integer: 20",no_output_msg= "Make sure your integer matches exactly to the Упражнение desciption.") success_msg("Great job!")

Типы данных. Переменные. Урок 3

Данные и их типы

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

Очевидно, данные бывают разными. Часто компьютерной программе приходится работать с числами и строками. Так на прошлом уроке мы работали с числами, выполняя над ними арифметические операции. Операция сложения выполняла изменение первого числа на величину второго, а умножение увеличивало одно число в количество раз, соответствующее второму.

Числа в свою очередь также бывают разными: целыми, вещественными, могут иметь огромное значение или очень длинную дробную часть.

При знакомстве с языком программирования Python мы столкнемся с тремя типами данных:

  • целые числа (тип int) – положительные и отрицательные целые числа, а также 0 (например, 4, 687, -45, 0).

  • числа с плавающей точкой (тип float) – дробные, они же вещественные, числа (например, 1.45, -3.789654, 0.00453). Примечание: для разделения целой и дробной частей здесь используется точка, а не запятая.

  • строки (тип str) — набор символов, заключенных в кавычки (например, "ball", "What is your name?", 'dkfjUUv', '6589'). Примечание: кавычки в Python могут быть одинарными или двойными; одиночный символ в кавычках также является строкой, отдельного символьного типа в Питоне нет.

Операции в программировании

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

Так в математике и программировании символ плюса является оператором операции сложения по отношению к числам. В случае строк этот же оператор выполняет операцию конкатенации, т. е. соединения.

>>> 10.25 + 98.36
108.61
>>> 'Hello' + 'World'
'HelloWorld'

Здесь следует для себя отметить, что то, что делает оператор в операции, зависит не только от него, но и от типов данных, которыми он оперирует. Молоток в случае нападения на вас крокодила перестанет играть роль строительного инструмента. Однако в большинстве случаев операторы не универсальны. Например, знак плюса неприменим, если операндами являются, с одной стороны, число, а с другой – строка.

>>> 1 + 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 
'int' and 'str'

Здесь в строке TypeError: unsupported operand type(s) for +: 'int' and 'str' интерпретатор сообщает, что произошла ошибка типа – неподдерживаемый операнд для типов int и str.

Изменение типов данных

Приведенную выше операцию все-таки можно выполнить, если превратить число 1 в строку "1". Для изменения одних типов данных в другие в языке Python предусмотрен ряд встроенных в него функций (что такое функция в принципе, вы узнаете в других уроках). Поскольку мы пока работаем только с тремя типами (int, float и str), то рассмотрим только соответствующие им функции: int(), float(), str().

>>> str(1) + 'a'
'1a'
>>> int('3') + 4
7
>>> float('3.2') + int('2')
5.2
>>> str(4) + str(1.2)
'41.2'

Эти функции преобразуют то, что помещается в их скобки соответственно в целое число, вещественное число или строку. Однако надо понимать, что преобразовать можно не все:

>>> int('hi')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with 
base 10: 'hi'

Здесь возникла ошибка значения (ValueError), так как передан литерал (в данном случае строка с буквенными символами), который нельзя преобразовать к числу с основанием 10. Однако функция int() не такая простая:

>>> int('101', 2)
5
>>> int('F', 16)
15

Если вы знаете о различных системах счисления, то поймете, что здесь произошло.

Обратите внимание еще на одно. Данные могут называться значениями, а также литералами. Эти три понятия ("данные", "значение", "литерал") не обозначают одно и то же, но близки и нередко употребляются как синонимы. Чтобы понять различие между ними, места их употребления, надо изучить программирование глубже.

Переменные

Данные хранятся в ячейках памяти компьютера. Когда мы вводим число, оно помещается в какую-то ячейку памяти. Но как потом узнать, куда именно? Как впоследствии обращаться к этим данными? Нужно как-то запомнить, пометить соответствующую ячейку.

Раньше, при написании программ на машинном языке, обращение к ячейкам памяти осуществляли с помощью указания их регистров, т. е. конкретно сообщали, куда положить данные и откуда их взять. Однако с появлением ассемблеров при обращении к данным стали использовать словесные переменные, что куда удобней для человека.

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

Слово "переменная" обозначает, что сущность может меняться, она непостоянна. Действительно, вы увидите это в дальнейшем, одна и та же переменная может быть связана сначала с одними данными, а потом – с другими. То есть ее значение может меняться, она переменчива.

В программе на языке Python, как и на большинстве других языков, связь между данными и переменными устанавливается с помощью знака =. Такая операция называется присваивание (также говорят "присвоение"). Например, выражение sq = 4 означает, что на объект, представляющий собой число 4, находящееся в определенной области памяти, теперь ссылается переменная sq, и обращаться к этому объекту следует по имени sq.

Имена переменных могут быть любыми. Однако есть несколько общих правил их написания:

  1. Желательно давать переменным осмысленные имена, говорящие о назначении данных, на которые они ссылаются.

  2. Имя переменной не должно совпадать с командами языка (зарезервированными ключевыми словами).

  3. Имя переменной должно начинаться с буквы или символа подчеркивания (_), но не с цифры.

  4. Имя переменной не должно содержать пробелы.

Чтобы узнать значение, на которое ссылается переменная, находясь в режиме интерпретатора, достаточно ее вызвать, т. е. написать имя и нажать Enter.

>>> sq = 4
>>> sq
4

Вот более сложный пример работы с переменными в интерактивном режиме:

>>> apples = 100
>>> eat_day = 5
>>> day = 7
>>> apples = apples - eat_day * day
>>> apples
65

Здесь фигурируют три переменные: apples, eat_day и day. Каждой из них присваивается свое значение. Выражение apples = apples - eat_day * day сложное. Сначала выполняется подвыражение, стоящее справа от знака равенства. После этого его результат присваивается переменной apples, в результате чего ее старое значение (100) теряется. В подвыражении apples - eat_day * day вместо имен переменных на самом деле используются их значения, т. е. числа 100, 5 и 7.

Практическая работа

  1. Переменной var_int присвойте значение 10, var_float - значение 8.4, var_str - "No".

  2. Значение, хранимое в переменной var_int, увеличьте в 3.5 раза. Полученный результат свяжите с переменной var_big.

  3. Измените значение, хранимое в переменной var_float, уменьшив его на единицу, результат свяжите с той же переменной.

  4. Разделите var_int на var_float, а затем var_big на var_float. Результат данных выражений не привязывайте ни к каким переменным.

  5. Измените значение переменной var_str на "NoNoYesYesYes". При формировании нового значения используйте операции конкатенации (+) и повторения строки (*).

  6. Выведите значения всех переменных.

Примеры решения и дополнительные уроки в android-приложении и pdf-версии курса

Локальные и глобальные переменные. Урок 11 курса "Python. Введение в программирование"

В программировании особое внимание уделяется концепции о локальных и глобальных переменных, а также связанное с ними представление об областях видимости. Соответственно, локальные переменные видны только в локальной области видимости, которой может выступать отдельно взятая функция. Глобальные переменные видны во всей программе. "Видны" – значит, известны, доступны. К ним можно обратиться по имени и получить связанное с ними значение.

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

Вернемся к нашей программе из прошлого урока, немного упростив ее для удобства:

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    print("Площадь: %.2f" % (a*b))

def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    print("Площадь: %.2f" % (0.5 * a * h))

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
  rectangle()
elif figure == '2':
  triangle()

Сколько здесь переменных? Какие из них являются глобальными, а какие – локальными?

Здесь пять переменных. Глобальной является только figure. Переменные a и b из функции rectangle(), а также a и h из triangle() – локальные. При этом локальные переменные с одним и тем же идентификатором a, но объявленные в разных функциях, – разные переменные.

Следует отметить, что идентификаторы rectangle и triangle, хотя и не являются именами переменных, а представляют собой имена функций, также имеют область видимости. В данном случае она глобальная, так как функции объявлены непосредственно в основной ветке программы.

В приведенной программе к глобальной области видимости относятся заголовки объявлений функций, объявление и присваивание переменной figure, конструкция условного оператора.

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

…
elif figure == '2':
  triangle()

print(a)

Пример выполнения:

1-прямоугольник, 2-треугольник: 2
Основание: 4
Высота: 5
Площадь: 10. 00
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    print(a)
NameError: name 'a' is not defined

Однако мы можем обращаться из функций к глобальным переменным:

def rectangle():
    a = float(input("Ширина %s: " % figure))
    b = float(input("Высота %s: " % figure))
    print("Площадь: %.2f" % (a*b))

def triangle():
    a = float(input("Основание %s: " % figure))
    h = float(input("Высота %s: " % figure))
    print("Площадь: %.2f" % (0.5 * a * h))

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
  rectangle()
elif figure == '2':
  triangle()

Пример выполнения:

1-прямоугольник, 2-треугольник: 1
Ширина 1: 6.35
Высота 1: 2.75
Площадь: 17.46

В данном случае из тел функций происходит обращение к имени figure, которое, из-за того, что было объявлено в глобальной области видимости, видимо во всей программе.

Наши функции не совсем идеальны. Они должны вычислять площади фигур, но выводить результат на экран им не следовало бы. Вполне вероятна ситуация, когда результат нужен для внутренних нужд программы, для каких-то дальнейших вычислений, а выводить ли его на экран – вопрос второстепенный.

Если функции не будут выводить, а только вычислять результат, то его надо где-то сохранить для дальнейшего использования. Для этого подошли бы глобальные переменные. В них можно записать результат. Напишем программу вот так:

result = 0

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    result = a*b

def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    result = 0.5 * a * h

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
  rectangle()
elif figure == '2':
  triangle()

print("Площадь: %.2f" % result)

Итак, мы ввели в программу глобальную переменную result и инициировали ее нулем. В функциях ей присваивается результат вычислений. В конце программы ее значение выводится на экран. Мы ожидаем, что программа будет прекрасно работать. Однако…

1-прямоугольник, 2-треугольник: 2
Основание: 6
Высота: 4.5
Площадь: 0.00

… что-то пошло не так.

Дело в том, что в Python присвоение значения переменной совмещено с ее объявлением. (Во многих других языках это не так.) Поэтому, когда имя result впервые упоминается в локальной области видимости, и при этом происходит присваивание ей значения, то создается локальная переменная result. Это другая переменная, никак не связанная с глобальной result.

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

Когда мы вызывали внутри функции переменную figure, то ничего ей не присваивали. Наоборот, мы запрашивали ее значение. Интерпретатор Питона искал ее значение сначала в локальной области видимости и не находил. После этого шел в глобальную и находил.

В случае с result он ничего не ищет. Он выполняет вычисления справа от знака присваивания, создает локальную переменную result, связывает ее с полученным значением.

На самом деле можно принудительно обратиться к глобальной переменной. Для этого существует команда global:

result = 0

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    global result
    result = a*b

def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    global result
    result = 0.5 * a * h

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
  rectangle()
elif figure == '2':
  triangle()

print("Площадь: %.2f" % result)

В таком варианте программа будет работать правильно.

Однако менять значения глобальных переменных в теле функции – плохая практика. В больших программах программисту трудно отследить, где, какая функция и почему изменила их значение. Программист смотрит на исходное значение глобальной переменной и может подумать, что оно остается таким же. Сложно заметить, что какая-то функция поменяла его. Подобное ведет к логическим ошибкам.

Чтобы избавиться от необходимости использовать глобальные переменные, для функций существует возможность возврата результата своей работы в основную ветку программы. И уже это полученное из функции значение можно присвоить глобальной переменной в глобальной области видимости. Это делает программу более понятной.

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

Практическая работа

В языке Python можно внутри одной функции определять другую. Напишите программу по следующему описанию.

В основной ветке программы вызывается функция cylinder(), которая вычисляет площадь цилиндра. В теле cylinder() определена функция circle(), вычисляющая площадь круга по формуле πr2. В теле cylinder() у пользователя спрашивается, хочет ли он получить только площадь боковой поверхности цилиндра, которая вычисляется по формуле 2πrh, или полную площадь цилиндра. В последнем случае к площади боковой поверхности цилиндра должен добавляться удвоенный результат вычислений функции circle().

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

Примеры решения и дополнительные уроки в android-приложении и pdf-версии курса

Глобальные переменные в Python: сохранить локальную переменную от вызова к вызову функции

Есть несколько способов реализовать подобное поведение.

Глобальные переменные

Первое, что может прийти в голову, это использовать глобальные переменные.
Важно учитывать то, что глобальные переменные доступы на чтение

def func1():
    print(x)

x = 10
func1()   # 10

но простое использование на запись не разрешается:

def func2():
    y = 20    # создаёт локальную переменную, а не изменяет глобальную

y = 10
func2()
print(y)      # 10

Более того, при попытке обратиться к переменной сначала на чтение, потом на запись, мы получим ошибку:

def func3():
    print(z)
    z = 20

z = 10
func3()   # UnboundLocalError: local variable 'z' referenced before assignment

Это происходит из-за того, что использование присваивания переменной z обозначает её, как локальную (как в случае 2). Попытка вывести значение локальной переменной, у которой ещё не задано значение, как раз и порождает возникновение этой ошибки.

Аналогичный пример как раз приведён в вашем вопросе. Там тоже переменная someGlobalVar определяется, как локальная, потому что выполняется присваивание. Так как в этом присваивании используется сначала чтение значения ещё не инициализированной переменной someGlobalVar, мы получаем ту же ошибку.


Для того, чтобы этот пример работал, необходимо предварительно пометить переменную, как global:

def func4():
    global w
    print(w)
    w = 20


w = 10
func4()    # 10
print(w)   # 20

Аналогично будет работать и в вашем случае.


Использование поля функции

Второй способ, который может прийти в голову, это использование объекта функции для хранения состояния функции.

def func5():
    if not hasattr(func5, '_state'):  # инициализация значения
        func5. _state = 0
    print(func5._state)
    func5._state = func5._state + 1


# до первого вызова функции значение не установлено
# print(func5._state)  # AttributeError: 'function' object has no attribute '_state'
func5()                # 0
print(func5._state)    # 1

В этом способе удобно то, что значение ассоциировано с самой функцией.

Стоит быть осторожным, давая имена подобным полям функции, так как в Python 2 у функции есть стандартные поля с названиями, не начинающимися с двух подчёркиваний, например, func_closure, func_code и т.п. Все они начинаются с func_, поэтому главное не использовать этот префикс и не начинать название поля с __, в остальных случаях шанс коллизии имён практически равен нулю.


Использование класса с поведением функции

Третий способ заключается в создании класса с поведением функции. Это наиболее удобный и безопасный, по моему мнению, способ реализации подобного поведения. Просто создайте класс и перегрузите его метод __call__:

class FuncCreator:
    def __init__(self, start_state):
        self.state = start_state

    def __call__(self):
        print(self.state)
        self.state += 1


func6 = FuncCreator(0)
print(func6.state)  # 0
func6()             # 0
print(func6.state)  # 1

Это увеличивает объём кода, но добавляет удобств от использования функциональности класса.


Использование изменяемого объекта, как значение по умолчанию для параметра

Четвёртый способ заключается в том, чтобы создать функцию, у которой будет необязательный параметр, использующий изменяемое значение в качестве состояния:

def func7(state=[]):
    if not state:
        state.append(0)
    print(state[0])
    state[0] += 1


func7()  # 0
func7()  # 1

В качестве объекта состояния можно использовать любой изменяемый объект. Это использует то, что все значения по умолчанию присваиваются один раз.


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

Если вернуться к исходному примеру, то для подсчёта числа вызовов функции будет также может быть удобно использовать декораторы. Это позволит в том числе и переиспользовать код.

Для Python 3 код может выглядеть, например, так:

from functools import wraps


def call_count(func):
    count = 0
    @wraps(func)
    def wrapper(*args, **kwargs):
        nonlocal count
        count += 1
        func(*args, **kwargs)
        print(count)
    return wrapper

В Python 2 нет nonlocal, но можно использовать изменяемые переменные:

from functools import wraps


def call_count(func):
    count = [0]
    @wraps(func)
    def wrapper(*args, **kwargs):
        count[0] += 1
        func(*args, **kwargs)
        print(count[0])
    return wrapper

Использоваться это будет следующим образом:

@call_count
def f():
    pass

f()  # 1
f()  # 2

При желании вы можете скомбинировать этот способ с каким-нибудь из описанных ранее.


Из всех выше упомянутых способов я бы рекомендовал использовать классы (так как функция с изменяющимся состоянием уже больше похожа на класс, чем на функцию) или поле функции, в случае необходимости быстрого добавления функциональности в код.

Python 3 - Урок 004. Типы переменных

Переменные - это не что иное, как зарезервированные ячейки памяти для хранения значений. Это означает, что при создании переменной вы резервируете некоторое пространство в памяти.

На основе типа данных переменной интерпретатор выделяет память и решает, что можно сохранить в зарезервированной памяти. Поэтому, присваивая переменным разные типы данных, вы можете хранить целые числа, десятичные знаки или символы в этих переменных.

Присвоение значений переменным

Переменные Python не требуют явного объявления для резервирования пространства памяти. Объявление присваивается автоматически, когда вы присваиваете значение переменной. Знак равенства (=) используется для присвоения значений переменным.

Операнд слева от оператора =  является именем переменной, а операнд справа от оператора = является значением, которое хранится в переменной. Например,


#!/usr/bin/python3

counter = 100          # Целочисленная переменная
miles   = 1000.0       # Переменная с плафающей точкой
name    = "John"       # Строковая переменная

print (counter)
print (miles)
print (name)

Здесь 100, 1000.0 и «John» являются значениями, присвоенными счетчику, милям и переменной имени, соответственно. Это дает следующий результат:


100
1000.0
John

Множественное присвоение

Python позволяет одновременно назначать одно значение нескольким переменным.

Например,


a = b = c = 1

Здесь создается целочисленный объект со значением 1, и все три переменные назначаются в одну и ту же ячейку памяти. Вы также можете назначить несколько объектов нескольким переменным. Например,


a, b, c = 1, 2, "john"

Переменным a и b присваиваются целочисленные значения 1 и 2 соответсвенно, а переменной c присваивается строка john .

Стандартные типы данных

Данные, хранящиеся в памяти, могут быть разных типов. Например, возраст человека хранится как числовое значение, а его адрес хранится в виде буквенно-цифровых символов. Python имеет различные стандартные типы данных, которые используются для определения возможных операций и методов хранения для каждого из них.

Python имеет пять стандартных типов данных -

  • Числа - Numbers
  • Строки - String
  • Список - List
  • Кортеж - Tuple
  • Словарь - Dictionary

Числа Python

Числовые типы данных хранят числовые значения. Числовые объекты создаются при назначении им значения. Например,


var1 = 1
var2 = 10

Вы также можете удалить ссылку на числовой объект, используя оператор del. Синтаксис инструкции del -


del var1[,var2[,var3[....,varN]]]]

Вы можете удалить один объект или несколько объектов, используя инструкцию del.

Например,


del var
del var_a, var_b

Python поддерживает три разных числовых типа -

  • int (целые числа со знаком)
  • float (реальные значения с плавающей запятой)
  • complex (комплексные числа)

Все целые числа в Python3 представлены как long числа. Следовательно, нет отдельного типа long.

Примеры
int float complex
10 0.0 3.14j
100 15.20 45. j
-786 -21.9 9.322e-36j
080 32.3+e18 .876j
-0490 -90. -.6545+0J
-0x260 -32.54e100 3e+26J
0x69 70.2-E12 4.53e-7j

Комплексное число состоит из упорядоченной пары вещественных чисел с плавающей запятой, обозначаемой x + yj, где x и y - вещественные числа, j - мнимая единица.

Строки Python

Строки в Python идентифицируются как непрерывный набор символов, представленных в кавычках. Python позволяет использовать пару одиночных или двойных кавычек. Подмножества строк могут быть взяты с использованием оператора среза ([] и [:]) с индексами, начинающимися с 0 в начале строки и работающими от -1 до конца.

Знак плюс (+) является оператором конкатенации строк, а звездочкой (*) является оператор повторения. Например,


#!/usr/bin/python3

str = 'Hello World!'

print (str)          # Вывод всей строки
print (str[0])       # Вывод первого символа строки
print (str[2:5])     # Вывод символов с третьего по пятый
print (str[2:])      # Вывод строки с третьего символа
print (str * 2)      # Вывод строки дважды
print (str + "TEST") # Вывод склеенной строки

Это приведет к следующему результату -


Hello World!
H
llo
llo World!
Hello World!Hello World!
Hello World!TEST

Списки Python

Списки являются наиболее универсальными составными типами данных Python. Список содержит элементы, разделенные запятыми и заключенные в квадратные скобки ([]). В некоторой степени списки аналогичны массивам в C. Одно из различий между ними состоит в том, что все элементы, принадлежащие списку, могут быть разных типов данных.

Доступ к значениям, хранящимся в списке, можно получить с помощью оператора среза ([] и [:]) с индексами, начинающимися с 0 в начале списка и заканчивающимися -1. Знак плюс (+) - это оператор конкатенации списка, а звездочка (*) - оператор повторения. Например,


#!/usr/bin/python3

list = [ 'abcd', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']

print (list)          # Вывод всего списка
print (list[0])       # Вывод первого элемента списка
print (list[1:3])     # Вывод элементов со второго по третий 
print (list[2:])      # Вывод элементов начиная с третьего
print (tinylist * 2)  # Вывод списка дважды
print (list + tinylist) # Вывод результирующего списка

Это приведет к следующему результату -


['abcd', 786, 2.23, 'john', 70.200000000000003]
abcd
[786, 2.23]
[2.23, 'john', 70.200000000000003]
[123, 'john', 123, 'john']
['abcd', 786, 2.23, 'john', 70.200000000000003, 123, 'john']

Кортежи Python

Кортеж - это другой тип данных последовательности, аналогичный списку. Кортеж состоит из нескольких значений, разделенных запятыми. Однако, в отличие от списков, кортежи заключены в круглые скобки.

Основное различие между списками и кортежами - Списки заключены в скобки ([]), и их элементы и размер могут быть изменены, а кортежи заключены в круглые скобки (()) и не могут быть обновлены. Кортежи можно рассматривать как списки только для чтения. Например,


#!/usr/bin/python3

tuple = ( 'abcd', 786 , 2.23, 'john', 70.2  )
tinytuple = (123, 'john')

print (tuple)           # Вывод всего кортежа
print (tuple[0])        # Вывод первого элемента в кортеже
print (tuple[1:3])      # вывод элементов со второго по третий 
print (tuple[2:])       # Вывод элементов кортежа с третьего
print (tinytuple * 2)   # Вывод кортежа дважды
print (tuple + tinytuple) # Вывод результирующего кортежа

Это приведет к следующему результату -


('abcd', 786, 2.23, 'john', 70.200000000000003)
abcd
(786, 2.23)
(2.23, 'john', 70.200000000000003)
(123, 'john', 123, 'john')
('abcd', 786, 2. 23, 'john', 70.200000000000003, 123, 'john')

Следующий код недопустим с кортежем, потому что мы попытались обновить кортеж, что запрещено. Подобный случай возможен со списками -


#!/usr/bin/python3

tuple = ( 'abcd', 786 , 2.23, 'john', 70.2  )
list = [ 'abcd', 786 , 2.23, 'john', 70.2  ]
tuple[2] = 1000    # запрещено для кортежей
list[2] = 1000     # допустимо для списков

Словари Python

Словарь Python - это тип хеш-таблицы. Они работают как ассоциативные массивы или хэши, как в Perl, и состоят из пар ключ-значение. Ключ словаря может быть почти любым типом Python, но обычно это числа или строки. Значения, с другой стороны, могут быть любым произвольным объектом Python.

Словари заключены в фигурные скобки ({}), и значения могут быть получены с помощью квадратных скобок ([]). Например,


#!/usr/bin/python3

dict = {}
dict['one'] = "This is one"
dict[2]     = "This is two"

tinydict = {'name': 'john','code':6734, 'dept': 'sales'}

print (dict['one'])       # Вывод значения для ключа 'one'
print (dict[2])           # Вывод значения для клюса 2
print (tinydict)          # Вывод всего словаря
print (tinydict. keys())   # Вывод всез ключей словаря
print (tinydict.values()) # Вывод всех значений

Это приведет к следующему результату -


This is one
This is two
{'name': 'john', 'dept': 'sales', 'code': 6734}
dict_keys(['name', 'dept', 'code'])
dict_values(['john', 'sales', 6734])

Словари не имеют понятия об упорядочивании среди элементов.

Преобразование типа данных

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

Существует несколько встроенных функций для преобразования из одного типа данных в другой. Эти функции возвращают новый объект, представляющий преобразованное значение.

S.No. Функция & Описание
1

int(x [,base])

Преобразует x в целое число.

2

float(x)

Преобразует x в число с плавающей запятой.

3

complex(real [,imag])

Создает комплексное число.

4

str(x)

Преобразует объект x в строковое представление.

5

repr(x)

Преобразует объект x в строковое выражение.

6

eval(str)

Обрабатывает строку и возвращает объект. Используется для выполнения программного кода представленного сторокой.

7

tuple(s)

Преобразует s в кортеж.

8

list(s)

Преобразует s в список.

9

set(s)

Преобразует s в набор.

10

dict(d)

Создает словарь. d должен быть последовательностью (ключ, значение) кортежей.

11

frozenset(s)

Преобразует s в неизменяемый набор.

12

chr(x)

Преобразует целое число в символ.

13

unichr(x)

Преобразует целое число в символ Unicode.

14

ord(x)

Преобразует один символ в его целочисленное значение.

15

hex(x)

Преобразует целое число в шестнадцатеричную строку.

16

oct(x)

Преобразует целое число в восьмеричную строку.

Переменные и константы в Python

В этой статье вы узнаете о переменных и константах в Python, вариантах их объявления и использования.

Переменные в Python

В большинстве языков программирования переменная является именованным местоположением, используемым для хранения данных в памяти. Каждая переменная должна иметь уникальное имя, называемое идентификатором. Принято думать о переменных как о контейнерах, которые содержат данные и эти данные могут быть извлечены или изменены позже, во время программирования.

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

Объявление переменных в Python

В отличии от других языков программирования, в Python переменные не нуждаются в объявлении для резервирования места в памяти. «Объявление переменной» или «инициализация переменной» происходит автоматически, когда мы присваиваем значение переменной.

Присвоение значения переменной в Python

Вы можете использовать оператор присваивания =, чтобы присвоить значение переменной.

блок 1

Пример 1: Объявление и присвоение значения переменной

message = 'hello'

В данном примере мы присвоили переменной message значение hello. Чтобы вывести значение переменной на экран нужно вызвать функцию print()

print(message)

Вы увидите следующее:

hello

Вам не нужно указывать тип переменной во время присвоения значения. Python язык с динамической типизацией, поэтому на этапе присвоения интерпретатор «понял» что переменная message имеет тип str (string, строка). При этом, далее вы можете присвоить этой переменной значение 123 и ее тип автоматически сменится на int (integer, число).

Пример 2: изменение значения переменной, изменение типа переменной

message = 'bye'
print(message)
print(type(message))
message = 123
print(message)
print(type(message))

В этом примере мы сначала изменили значение на другую строку, затем присвоили переменной значение типа int. Как видите никаких ошибок это не спровоцировало.

Пример 3: Присвоение нескольких значений нескольким переменным на одной строке

Иногда можно присваивать значения сразу нескольким переменным на одной строке:

a, b, c = 1, 'hello', 12

Эта запись то же самое что и:

a = 1
b = 'hello'
c = 12

Не стоит злоупотреблять этим способом, он несколько снижает читабельность кода.

Если мы хотим присвоить одно и то же значение нескольким переменным одновременно, мы можем сделать следующим способом:

a = b = c = 15

В результате, все три переменные будут типа int и содержать в себе значение 15.

Константы в Python

Константа - это тип переменной, значение которой нельзя изменить на протяжении всего жизненного цикла программы. Однако в Python, это носит скорее рекомендательный характер. Дело в том, что в отличии от многих языков программирования, в которых присвоение нового значения константе вызовет ошибку, в Python значение константы может быть изменено и это не вызовет вопросов со стороны интерпретатора.

При объявлении константы вы как бы говорите себе и другим программистам которые возможно будут читать ваш код «Значение этой переменной не должно меняться на протяжении всего цикла работы программы!».

Как объявить константу в Python

Как и обычная переменная (а константа в Python, технически, это обычная переменная) константа инициализируется в момент присвоения ей значения:

PI = 3. 14

Имя константы пишется в верхнем регистре (PI, MESSAGE и т.д.) с целью выделить ее, дать понять что это именно константа и ее значение должно оставаться неизменным. Если в имени присутствуют два или больше слов, то они разделяются символом подчеркивания (WELCOME_MESSAGE).

блок 3

Как определить / объявить типы строковых переменных

Переменная Python - это зарезервированная область памяти для хранения значений. Другими словами, переменная в программе на Python передает данные компьютеру для обработки.

Каждое значение в Python имеет тип данных. Различные типы данных в Python: числа, список, кортеж, строки, словарь и т. Д. Переменные в Python могут быть объявлены любым именем или даже алфавитами, такими как a, aa, abc и т. Д.

Как объявить и использовать переменную

Посмотрим на примере.Мы определим переменную в Python, объявим ее как «a» и распечатаем.

а = 100
print (a) 

Повторное объявление переменной

Вы можете повторно объявить переменные Python даже после того, как вы объявили их один раз.

Здесь у нас есть переменная объявления Python, инициализированная значением f = 0.

Позже мы повторно присвоим переменной f значение "guru99"

Python 2 Пример

# Объявить переменную и инициализировать ее
f = 0
печать f
# повторное объявление переменной работает
f = 'guru99'
print f 

Python 3 Пример

# Объявить переменную и инициализировать ее
f = 0
печать (е)
# повторное объявление переменной работает
f = 'guru99'
print (f) 

Python Конкатенация строк и переменная

Давайте посмотрим, сможете ли вы объединить различные типы данных, такие как строка и число, вместе.Например, мы соединим «Гуру» с числом «99».

В отличие от Java, которая объединяет число со строкой без объявления числа как строки, в то время как объявление переменных в Python требует объявления числа как строки, в противном случае будет отображаться ошибка TypeError

Для следующего кода вы получите неопределенный вывод -

a = "Гуру"
b = 99
напечатать a + b
 

После того, как целое число объявлено как строка, оно может объединить в выходных данных "Guru" + str ("99") = "Guru99".

a = "Гуру"
b = 99
print (a + str (b)) 

Типы переменных Python: локальные и глобальные

В Python есть два типа переменных: глобальная переменная и локальная переменная. Если вы хотите использовать одну и ту же переменную для остальной части вашей программы или модуля, вы объявляете ее как глобальную переменную, а если вы хотите использовать переменную в определенной функции или методе, вы используете локальную переменную при объявлении переменной Python.

Давайте разберемся с типами переменных Python с разницей между локальными и глобальными переменными в приведенной ниже программе.

  1. Давайте определим переменную в Python, где переменная «f» имеет глобальную в области видимости и ей присвоено значение 101, которое печатается в выходных данных
  2. Переменная f снова объявлена ​​в функции и предполагает локальную область . Ему присваивается значение «Я изучаю Python». который распечатывается как результат. Эта объявленная переменная Python отличается от глобальной переменной «f», определенной ранее.
  3. После завершения вызова функции локальная переменная f уничтожается.В строке 12, когда мы снова печатаем значение «f», оно отображает значение глобальной переменной f = 101

Python 2 Пример

# Объявить переменную и инициализировать ее
f = 101
печать f
# Глобальные и локальные переменные в функциях
def someFunction ():
# global f
    f = 'Я изучаю Python'
    печать f
someFunction ()
print f 

Python 3 Пример

# Объявить переменную и инициализировать ее
f = 101
печать (е)
# Global vs.локальные переменные в функциях
def someFunction ():
# global f
    f = 'Я изучаю Python'
    печать (е)
someFunction ()
print (f) 

При объявлении переменной Python с использованием ключевого слова global, вы можете ссылаться на глобальную переменную внутри функции.

  1. Переменная «f» имеет глобальный в области видимости и ей присвоено значение 101, которое выводится на выходе
  2. Переменная f объявляется с использованием ключевого слова global . Это НЕ , локальная переменная , а та же глобальная переменная, объявленная ранее.Следовательно, когда мы печатаем его значение, на выходе получаем 101
  3. . Мы изменили значение «f» внутри функции. После завершения вызова функции измененное значение переменной «f» сохраняется. В строке 12, когда мы снова печатаем значение «f», оно отображает значение «изменение глобальной переменной»

Python 2 Пример

f = 101;
печать f
# Глобальные и локальные переменные в функциях
def someFunction ():
  глобальный f
  печать f
  f = "изменение глобальной переменной"
someFunction ()
print f 

Python 3 Пример

f = 101;
печать (е)
# Global vs.локальные переменные в функциях
def someFunction ():
  глобальный f
  печать (е)
  f = "изменение глобальной переменной"
someFunction ()
print (f) 

Удалить переменную

Вы также можете удалить переменные Python с помощью команды del «имя переменной».

В приведенном ниже примере удаления переменной Python мы удалили переменную f, и когда мы продолжаем ее печатать, мы получаем ошибку « имя переменной не определено », что означает, что вы удалили переменную.

Пример переменной удаления Python или переменной удаления Python:

f = 11;
печать (е)
дель ф
print (f) 

Резюме:

Объявление переменной Python - qaru

Хорошо, обо всем по порядку.

В Python нет таких вещей, как «объявление переменной» или «инициализация переменной».

Это просто то, что мы называем «присваиванием», но, вероятно, следует называть просто «именование».

Присвоение означает, что «это имя в левой части теперь относится к результату оценки правой части, независимо от того, на что оно ссылалось раньше (если что-то было)».

  foo = 'bar' # имя 'foo' теперь является именем строки 'bar'
foo = 2 * 3 # имя 'foo' перестает быть именем строки 'bar',
# и начинается с имени целого числа 6, полученного в результате умножения
  

Таким образом, имена Python (возможно, более подходящий термин, чем «переменные») не имеют связанных типов; ценности делают. Вы можете повторно применить одно и то же имя ко всему, независимо от его типа, но поведение объекта по-прежнему зависит от его типа.Имя - это просто способ обозначить значение (объект). Это отвечает на ваш второй вопрос: вы не создаете переменные для хранения настраиваемого типа. Вы не создаете переменные для хранения какого-либо определенного типа. Вы вообще не «создаете» переменные. Вы даете имена объектам.

Второй момент: Python следует очень простому правилу, когда дело доходит до классов, которое на самом деле намного более согласованно, чем то, что делают языки, такие как Java, C ++ и C #: все, что объявлено внутри блока class , является частью класса .Итак, написанные здесь функции ( def ) являются методами, то есть частью объекта класса (не сохраняются для каждого экземпляра), как в Java, C ++ и C #; но другие имена здесь , также часть класса. Опять же, имена - это просто имена, и они не имеют связанных типов, а функции также являются объектами в Python. Таким образом:

  класс Пример:
    данные = 42
    def method (self): передать
  

Классы тоже являются объектами , в Python.

Итак, теперь мы создали объект с именем Example , который представляет класс всех вещей, которые являются Example s. Этот объект имеет два пользовательских атрибута (в C ++ - «элементы»; в C # - «поля или свойства или методы»; в Java - «поля или методы»). Один из них называется data , и в нем хранится целочисленное значение 42 . Другой называется метод , и он хранит объект функции. (Есть еще несколько атрибутов, которые Python добавляет автоматически.)

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

Создадим экземпляр:

  x = Пример ()
  

Теперь у нас есть отдельный объект с именем x , который является экземпляром Example .Данные и метод на самом деле не являются частью объекта, но мы все равно можем искать их через x из-за некоторой магии, которую Python делает за кулисами. Когда мы ищем метод , в частности, , мы вместо этого получаем «связанный метод» (когда мы его вызываем, x передается автоматически как параметр self , чего не может произойти, если мы ищем Example.method напрямую).

Что происходит, когда мы пытаемся использовать x.данные ?

Когда мы его исследуем, он сначала ищет объект. Если он не найден в объекте, Python просматривает класс.

Однако, когда мы назначаем x.data , Python создаст атрибут для объекта. Это , а не заменит атрибут класса.

Это позволяет нам выполнить инициализацию объекта . Python автоматически вызовет метод класса __init__ для новых экземпляров при их создании, если они есть.В этом методе мы можем просто назначить атрибуты, чтобы установить начальные значения для этого атрибута для каждого объекта:

  класс Пример:
    name = "Игнорируется"
    def __init __ (я, имя):
        self.name = имя
    # отдых как раньше
  

Теперь мы должны указать имя при создании примера , и каждый экземпляр имеет собственное имя . Python будет игнорировать атрибут класса Example.name всякий раз, когда мы ищем .name экземпляра, потому что атрибут экземпляра будет найден первым.

И последнее предостережение: модификация (мутация) и назначение - разные вещи!

В Python строки неизменяемы. Их нельзя изменить. Когда вы это сделаете:

  a = "привет"
б = а
а + = 'мама'
  

Вы, , не меняете исходную строку «привет». В Python это невозможно. Вместо этого вы создаете новую строку «привет мама» и заставляете перестать быть именем для «привет» и вместо этого начать быть именем для «привет мама» .Мы сделали b именем для 'hi' , а после повторного применения имени a , b все еще остается именем для 'hi' , потому что 'hi' все еще существует и не было изменено.

Но списки можно менять:

  a = [1, 2, 3]
б = а
а + = [4]
  

Теперь b также является [1, 2, 3, 4], потому что мы сделали b именем для того же объекта, что и a , а затем изменили это.Мы не создавали новый список для имен и , потому что Python просто по-разному обрабатывает + = для списков.

Это имеет значение для объектов, потому что если бы у вас был список как атрибут класса и вы использовали экземпляр для изменения списка, то изменение было бы «видно» во всех других экземплярах. Это потому, что (а) данные на самом деле являются частью объекта класса, а не объекта-экземпляра; (b) поскольку вы изменяли список, а не выполняли простое присвоение, вы не создали новый атрибут экземпляра, скрывающий атрибут класса.

переменных в Python - настоящий Python