Терпеть не могу их на самом деле, и избегаю использовать, т.к. считаю что лучше написать 2-3 лишних строчки кода. зато они будут читаться намного лучше. Однако же иногда попадаются, и иногда использую. Вот пример как использовать его в python
Синтаксис:
переменная=значение_1 if (условие выполняется) else значение_2
Пример:
radius=a if a>b else b
Читаем так: radius будет равно a, если a больше b, иначе radius будет b. Или тоже самое в классическом виде:
В общем в рамках компании по попытке обучения одного товарища программированию, написал небольшую консольную игру, дабы с ним попробовать её воспроизвести.
Суть игры: компьютер загадывает случайную кнопку из списка и время за которое игрок должен успеть её нажать. Если игрок успевает нажать — ему добавляется балл.
Итак, для написания понадобится знать что такое циклы, массивы, случайные числа. Использовать будем модули keyboard, random и time
keyboard — для получения нажатий клавиш на клавиатуре
random — для получения случайных числел
time — для расчета времени реакции
Для начала определим одномерный массив, в котором перечислим доступные для выбора компьютером клавиши.
keys=["q","w","e","r","t","y"];
Далее создадим бесконечный цикл, внутри которого будем выбирать случайную клавишу для нажатия:
import keyboard
import random
import time
keys=["q","w","e","r","t","y"];
while True:
key_to_press=keys[random.randint(0, len(keys)-1)]
print(f"-нажми кнопку {key_to_press}")
Что делает этот код? Бесконечно выводит в консоль сообщение о том, что нужно нажать случайно выбранную кнопку. Давайте теперь чуть переделаем код, чтобы случайно выбиралась не только клавиша которую нужноно нажать игроку, но и время за которое ему нужно её нажать:
import keyboard
import random
import time
keys=["q","w","e","r","t","y"];
while True:
key_to_press=keys[random.randint(0, len(keys)-1)]
time_to_press=random.randint(1, 3)
print(f"Нажми кнопку {key_to_press} за {time_to_press} секунды");
Что дальше? А дальше нам нужно объявить еще один цикл и ждать пока не истечет время отведенное для того чтобы игрок нажал кнопку. Для этого, перед началом цикла запомним время начала игры, и внутри цикла постоянно будем проверять, на сколько оно отличается от текущего времени:
import keyboard
import random
import time
keys=["q","w","e","r","t","y"];
while True:
key_to_press=keys[random.randint(0, len(keys)-1)]
time_to_press=random.randint(1, 3) # время в секундах ожидания реакции
print(f"Нажми кнопку {key_to_press} за {time_to_press} секунды");
start_time=time.time() # запоминаем время начала игры
while True:
if (time.time()-start_time>time_to_press): # разница между текущее временем и временем начала игры больше чем time_to_press, то игрок не успел нажать кнопку
print("- ты проиграл, не успел нажать!")
break;
Теперь добавим чуточку интерактивности, а именно проверку, «а не нажата ли клавиша загаданная компьютером»:
import keyboard
import random
import time
keys=["q","w","e","r","t","y"];
while True:
key_to_press=keys[random.randint(0, len(keys)-1)]
time_to_press=random.randint(1, 3) # время в секундах ожидания реакции
print(f"Нажми кнопку {key_to_press} за {time_to_press} секунды");
start_time=time.time() # запоминаем время начала игры
while True:
if (time.time()-start_time>time_to_press): # разница между текущее временем и временем начала игры больше чем time_to_press, то игрок не успел нажать кнопку
print("- ты проиграл, не успел нажать!")
break;
if keyboard.is_pressed(key_to_press):
print(f'-Ты выиграл!')
break
Ну и осталось чуток прилизать код, добавив возможность подсчета кто круче, компьютер или игрок:
import keyboard
import random
import time
# создадим массив с доступными клавишами
keys=["q","w","e","r","t","y"];
count_win_gamer=0
count_win_pc=0
while True:
start_time=time.time()
key_to_press=keys[random.randint(0, len(keys)-1)]
time_to_press=random.randint(1, 3)
print(f"Нажми кнопку {key_to_press} за {time_to_press} секунды");
win=False;
while True:
if (time.time()-start_time>time_to_press):
print(f"- ты проиграл уже {count_win_pc} , не успел нажать! Общий счёт: {count_win_pc}/{count_win_gamer} (ты)")
count_win_pc = count_win_pc + 1
break;
if keyboard.is_pressed(key_to_press):
count_win_gamer=count_win_gamer+1
print(f'-Ты выиграл уже {count_win_gamer} раз! Общий счёт: {count_win_pc}/{count_win_gamer} (ты)')
win = True;
break
Следующим шагом будет защитить доступ к остальным компонентам API, от доступа без сессионного ключа. Для этого воспользуемся классом FastApi security и добавим в требования заголовка запроса тег авторизации.
Получим итоговый роутинг auth.py:
# -*- coding: utf-8 -*-
"""Different helper-functions to work with users."""
import json
import fastapi;
from fastapi import APIRouter,Depends
from app.schemas import auth as auth_models
from pydantic import BaseModel
token_key = fastapi.security.APIKeyHeader(name="Authorization")
class Token(BaseModel):
token: str
# получить текущий токен
def get_current_token(oauth_header: str = fastapi.Security(token_key)):
#print(f"Token: {oauth_header}")
oauth_header=oauth_header.replace("Token ","")
return oauth_header
router = APIRouter()
@router.post('/auth',response_model=auth_models.auth_out,tags=["auth"]) # заданы исходящие параметры
async def auth(into = Depends(auth_models.auth_in)): # заданы входящие параметры
# если параметры не заданы
if into.password==None: into.password="NONE"
if into.login == None: into.password = "NONE"
hash="12345678"
# сформируем ответ
out=auth_models.auth_out(hash=hash)
return out
@router.post('/GetInfo',response_model=auth_models.info_out,tags=["auth"]) # заданы исходящие параметры
async def GetInfo(token: Token=Depends(get_current_token)): # заданы входящие параметры
print(f"Токен: {token}")
if token!="12345678":
print("Токен не верен!")
return auth_models.info_out(error=True,comment="Токен не найден")
# сформируем ответ
return auth_models.info_out(error=False,result={"username":"Pavel","email":"vasya@mail.ru"})
В результате мы можем увидеть в документации появившийся «замочек»:
При попытке выполнения запроса без авторизации, соответственно получим ошибку аторизации:
В предыдущей статье был рассмотрен запуск сервера и доступ к нему. Одно НО, доступ этот осуществляется или с локального ПК (в main.py), как вы видели присутствует строчка:
Если host поменять например на 0.0.0.0, сервер «из вне» будет конечно доступен, но по нестандартному порту и не по защищенному протоколу. Однако есть способ «завернуть» весь трафик в https через проксирование в apache/ngnix.
Для apache необходимо установить модуль proxy:
sudo a2enmod proxy proxy_http
sudo service apache2 restart
FastApi — это фреймворк позволяющий создавать «самодокументирующиеся API». Т.е. и реализация и документация пишется прямо в коде. Причем FastApi при помощи вебинтерфейса предоставляет еще и возможность тестирования получившегося API.
Подготовка
Для работы потребуется установленные пакеты fastapi и uvicorn :
pip3 install fastapi
pip3 install uvicorn
uvicorn требуется чтобы запустить веб сервер на определенном порту, для взаимодействия с фреймворком fastapi. Далее его можно проксировать через apache или ngnix, В основном для того, чтобы к api можно было обращаться из вне не только по IP но и по DNS имени. Ну и чтобы обернуть в https. Хотя консольный uvicorn позволяет может запускаться и по https протоколу, если указать ему сертификаты. Но не пробовал, ибо было не нужно.
Еще разик акцентирую внимание: uvicorn может поставляться в виде пакета python или в виде консольной утилиты. По сути это два разных способа поднятия вебсервера для fastapi. Результат будет один. Только в случае использования пакета python — внутри скрипта нужно будет реализовывать запуск uvicorn
Первый шаг
Как происходит работа внешнего пользователя с API? Обычно он авторизуется по логину-паролю, получает «сессионный ключ» и далее работает уже с ним. Что собственно и попробуем реализовать. Сначала на минимальном примере.
В FastApi используется модель pedantic, т.е. на входе функций реализуемых API должно попадать данные согласно заранее построенной схеме. Вызов функции, осуществляется при помощи роутинга в URL.
Например реализуем вызов функции API авторизации по URL вида:
http://127.0.0.1:8000/v1/auth
Запрос к URL будет выполнятся при помощи POST, с параметрами login и password
Создадим следующую структуру файлов и папок:
В файле main.py реализуем запуск сервера uvicorn и начальные настройки для запуска фреймворка FastAPI.
В файле /app/routers/auth.py реализуем логику ответа на вызов URL с параметрами POST
В файле /app/schemas/auth.py — создадим проверку входящих и исходящих параметров вызова согласно схеме pedantic
main.py:
import uvicorn
from fastapi import FastAPI
from app.routers import auth
tags_metadata = [
{"name": "auth", "description": "Получение ключа по логину, паролю"},
]
app = FastAPI(title="API documentation", description="Какое то описание ",version="0.0.1", openapi_tags=tags_metadata, )
app.include_router(auth.router, prefix="/v1")
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000, log_level="info")
Схема auth.py:
# -*- coding: utf-8 -*-
from typing import Optional
from pydantic import BaseModel,Field
class auth_out(BaseModel):
""" Что Выходит """
hash: str = Field(..., title="Сессионый ключ полученый по логину - паролю", example="iauwhfpseurh e")
class auth_in(BaseModel):
""" Что входит """
login: Optional [str] = Field(..., title="Логин пользователя", example="Например Вася")
password: Optional [str] =Field(..., title="Пароль пользователя", example="Например IUHID#U$HI")
Роутер auth.py:
# -*- coding: utf-8 -*-
"""Different helper-functions to work with users."""
import json
from fastapi import APIRouter,Depends
from app.schemas import auth as auth_models
router = APIRouter()
@router.post('/auth',response_model=auth_models.auth_out,tags=["auth"]) # заданы исходящие параметры
async def auth(into = Depends(auth_models.auth_in)): # заданы входящие параметры
# если параметры не заданы
if into.password==None: into.password="NONE"
if into.login == None: into.password = "NONE"
hash="eopwhdfweruieruiopfhp[ruifhp[eruifhperf8yareuifh[ay8wedfper8"
# сформируем ответ
out=auth_models.auth_out(hash=hash)
return out
Ну вот собственно и всё. Минимальный рабочий каркас собран. Осталось попробовать его запустить и посмотреть результат в браузере. Для этого в консоли запустим:
python main.py
Далее открываем браузер по url http://127.0.0.1:8000/docs или (http://127.0.0.1:8000/redoc) и можем наблюдать уже сформированную готовую к употреблению документацию:
Причем работоспособность вызовов можно попробовать прямо сейчас.
В текущем случае мы запустили сервер uvicorn из скрипта python, но есть вариант запуска сервера и из консоли. Какие преимущества имеет запуск из консоли, мне не очень пока очевидны. Но факт есть факт. Скрипт можно запустить и так:
uvicorn main:app --port 8000 --workers 10
В данном случае запустили 10 воркеров FastApi. Если использовать ключ —reload, то сервер будет отслеживать изменение файлов и перезапускать сам себя. Это удобно для моментальной отладки
Внимание! Ключи —reload и —workers одновременно не работают.