Видимость переменных.

Основы Python и Django. -> Видимость переменных.

# Область видимости переменных.

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

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

Эти области называются namespace (пространство имен) и существуют во всех языках программирования.

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

Давайте взглянем на следующую функцию:

def f(): 
    print s 
s = "I hate spam"
f()

Переменная s определена как строковая перед тем как мы вызываем функцию f().

Так как внутри функции переменная s не определена, будет использоваться переменная, определенная в глобальном пространстве - вне всяких функций.

Вопрос — а что если определить переменную s внутри функции?

def f(): 
    s = "Me too."
    print s

s = "I hate spam." 
f()
print s

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

Me too.
I hate spam.

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

Что если мы скомбинируем эти два подхода следующим образом:

def f(): 
    print s
    s = "Me too."
    print s


s = "I hate spam." 
f()
print s

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

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

UnboundLocalError: local variable 's' referenced before assignment

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

Любая переменная, которая изменяется или создается внутри функции — локальная, если она явно не определена как глобальная при помощи ключевого слова global.

Пример использования global.

def f():
    global s
    print s
    s = "That's clear."
    print s


s = "Python is great!" 
f()
print s

Теперь у нас отсутствует неопределенность и вывод будет следующим:

Python is great!
That's clear.
That's clear.

Локальные переменные или функции не могут быть получены извне, например так:

def f():
    s = "I am globally not known"
    print s

f()
print s

Этот код вызовет такое исключение:

Traceback (most recent call last):
  File "global_local3.py", line 6, in <module>
    print s
NameError: name 's' is not defined

Проверка на существование переменной в локальной или глобальной области видимости.

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

Для этого существуют функции globals() и locals(), которые возвратят список всех переменных в соответствующей области.

if 'myVar' in locals():
    print «myVar exists».


if 'myVar' in globals():
    # myVar exists.

Проверка на существование аттрибута объекта:

if hasattr(obj, 'attr_name'):
    print „obj.attr_name exists“.

Получение аттрибута.

m =  getattr(c, "say", None)

Проверка является ли аттрибут методом.

m =  getattr(c, "say", None)
if callable(m):
    print 'Say is the function!!!'

Пространсто имен (namespace) — это, по сути, коллекция всех имен переменных. Все встроенные в Python функции находятся в глобальном пространстве программы, и поэтому доступны из любой ее точки. Каждый модуль (файл) создает свое собственное глобальное пространство а каждая функция в модуле создает свое локальное. Таким образом в ходе выполнения программы мы имеем множество пространств имен абсолютно изолированных друг от друга. На первом месте идет встроенное глобальное пространство интерпретатора Python? От куда переменные доступны из любого места. Потом пространство модуля, и наконец пространство функций. Каждое пространсво описывается понятием scope. Scope — эта область, выделяемая программной сущьностью (модулем, функцией, методом и т. д.) для хранения переменных. При определении вложенных функций, например:

def outer_function():
    b = 20
    def inner_func():
        c = 30

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

Пример ниже демонстрирует этот принцип:

def outer_function():
    a = 20
    def inner_function():
        a = 30
        print('a =',a)

    inner_function()
    print('a =',a)

a = 10
outer_function()
print('a =',a)

Вывод:

a = 30
a = 20
a = 10
Основы Python и Django. -> Основы работы с GIT репозиторием.

Основы работы с GIT репозиторием.

Установка клинтского приложения на компьютер.

sudo apt install git

Создание репозитория локально.

git init

При этом создается прпка .git.

Клонирование существующего репозитория локально.

git clone path_to_repo

При этом может использоваться 2 протокола передаци ssh и https.

При использовании ssh необходимо сгенерировать ключи (если они не были сгенерированы) командой

ssh-keygen

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

cat ~/.ssh/id_rsa.pub

Затем скопировать и вставить в интерфейсе git провайдера.

Для github это Settings->SSH and GPG keys.

Просмотр состояния репозитория.

git status

Добавление файлов для отслеживания.

git add .
git add --all
git add filename

–all - добавляет также уделенные

Удаление файлов из отслеживания.

git rm filename

Игнорирование файлов/директори.

Производится с теми файлами, которые не изменяются в процессе разработки (изображения, папки редакоров и пр.)

Правила игнорирования описываются в файле .gitignore например:

venv
*.pyc
.vscode

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

Коммит изменений локально.

git commit -m 'conmmet text'

Прикрепление локального репозитория к удаленному.

Производится один раз после создания на GIT сервере провайдера.

git remote add origin git@github.com:zdimon/test.git

Загрузка файлов на сервер с созданием master ветки.

git push -u origin master

Проводится так же один раз при создании.

В последующем применяется команда

git push

Обновление репозиторя (актуализирование).

git pull

Создание новой ветки.

git branch branch_name

Переход на ветку или коммит.

git checkout branch_name_or_commit_id

Слияние ветки.

git merge branch_name

При этом код из ветки branch_name сливается с текущей.

Основы Python и Django. -> Тернарный оператор.

Тернарный оператор.

Тернарный оператор (Ternary operator) – используется в строчку для задания условий в присваивании значения переменной.

Это укороченный вариант конструкции if-else.

[ontrue] if [expression] else [onfalse]

x, y = 50, 25
small = x if x < y else y

Тернарный оператор по сути включает в себя имя переменной, которой мы присваиваем значение и внутри этой же строки задаем условия, описываемые операторами if/or/else.

Не обязательно использовать все три if/or/else оператора, в условии может использоваться просто if/else.

cat_say = 'Mew'
me_say = 'Hi,cat' if cat_say == 'Mew' or cat_say == 'Myavki' else 'Who are you?'
print(me_say)
Hi,cat #результат

Пример присваивания логического значения

m = 1>3 or 7
Основы Python и Django. -> Логирование.

Логирование в Python.

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

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

За работу с логами отвечает внутренний модуль logging.

import logging

Лучшей практикой будет создание объекта логера с использованием служебной переменной name, которая обозначит место использования логера.

loger = logging.getLogger(__name__)

Существует несколько уровней логирования в зависимости от важности события для логера.

DEBUG: Самый низкий уровень для отладки. INFO: Общая информация о работе системы. WARNING: Информация о незначительных неполадках. ERROR: Информация об основных существенных ошибках. CRITICAL: Критические проблемы.

Установка уровня и вывод лога.

logging.basicConfig(level=logging.DEBUG)
logger.info('Start reading database')

Запись лога в файл установкой обработчика FileHandler.

handler = logging.FileHandler('hello.log')
logger.addHandler(handler)

Форматирование лога.

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

Существует много обработчиков логов, включая отсылку лога на email и даже на удаленный сервер.

Вы можете написать свой собственный обработчик.

try:
    open('/path/to/does/not/exist', 'rb')
except (SystemExit, KeyboardInterrupt):
    raise
except Exception, e:
    logger.error('Failed to open file', exc_info=True)

Конфигурация логера словарем.

import logging.config

logging.config.dictConfig({
    'version': 1,              
    'disable_existing_loggers': False,

    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'default': {
            'level':'INFO',    
            'class':'logging.StreamHandler',
        },  
        'file': {
            'level':'INFO',    
            'class':'logging.FileHandler',
            'filename': 'root.log',
        }, 
    },
    'loggers': {
        '': {                  
            'handlers': ['file'],        
            'level': 'INFO',  
            'propagate': True  
        }
    }
})

Фильтры.

Классы фильтра позволяют отфильтровывать определенные сообщения по условию.

Следующий пример демонстрирует фильтр, отсеивающий все сообщения кроме тех, что имеют уровень INFO.

import logging

class InfoFilter(logging.Filter):
    def filter(self, rec):
        return rec.levelno == logging.INFO

 'filters': {
     'my_filter': {
         '()': 'mymodule.InfoFilter'
     }
 },

 'mail_admins': {
     'level': 'ERROR',
     'filters': ['my_filter'],
     'class': 'django.utils.log.AdminEmailHandler'
 }

http://victorlin.me/posts/2012/08/26/good-logging-practice-in-python