Примеры программ на языке Python: различия между версиями
м Откат правок 90.151.82.3 (обс.) к версии 95.154.65.85 Метка: откат |
DannyS712 (обсуждение | вклад) м <source> -> <syntaxhighlight> (phab:T237267) |
||
Строка 5: | Строка 5: | ||
Данный пример чисто демонстрационный, так как его можно значительно улучшить. |
Данный пример чисто демонстрационный, так как его можно значительно улучшить. |
||
< |
<syntaxhighlight lang="python"> |
||
from urllib2 import urlopen # из модуля urllib2 импортируем функцию urlopen |
from urllib2 import urlopen # из модуля urllib2 импортируем функцию urlopen |
||
Строка 28: | Строка 28: | ||
for p in pairs[:10]: # печатаем первые 10 элементов списка |
for p in pairs[:10]: # печатаем первые 10 элементов списка |
||
print(p[0], p[1]) |
print(p[0], p[1]) |
||
</syntaxhighlight> |
|||
</source> |
|||
Текст для версии 3.7.1 |
Текст для версии 3.7.1 |
||
< |
<syntaxhighlight lang="python"> |
||
from urllib.request import urlopen # из модуля urllib импортируем функцию urlopen |
from urllib.request import urlopen # из модуля urllib импортируем функцию urlopen |
||
Строка 55: | Строка 55: | ||
for p in A[:10]: # печатаем первые 10 элементов списка |
for p in A[:10]: # печатаем первые 10 элементов списка |
||
print(p[0], p[1]) |
print(p[0], p[1]) |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Примеры работы с последовательностями === |
=== Примеры работы с последовательностями === |
||
Строка 61: | Строка 61: | ||
Иллюстрируют особенности индексации элементов и срезов: при взятии среза нумеруются не сами элементы, а промежутки между ними. |
Иллюстрируют особенности индексации элементов и срезов: при взятии среза нумеруются не сами элементы, а промежутки между ними. |
||
< |
<syntaxhighlight lang="python"> |
||
>>> l = ['A', 'B', 'C', 'D', 'E'] # исходный список |
>>> l = ['A', 'B', 'C', 'D', 'E'] # исходный список |
||
>>> # 0 1 2 3 4 5 # пронумерованные промежутки между элементами |
>>> # 0 1 2 3 4 5 # пронумерованные промежутки между элементами |
||
Строка 73: | Строка 73: | ||
>>> l[::-1] # все элементы в обратном порядке |
>>> l[::-1] # все элементы в обратном порядке |
||
['E', 'D', 'C', 'B', 'A'] |
['E', 'D', 'C', 'B', 'A'] |
||
</syntaxhighlight> |
|||
</source> |
|||
Функции подобные <code>range()</code> поддерживают то же правило (для версий языка 2.x): |
Функции подобные <code>range()</code> поддерживают то же правило (для версий языка 2.x): |
||
< |
<syntaxhighlight lang="python"> |
||
>>> range(2, 5) |
>>> range(2, 5) |
||
[2, 3, 4] |
[2, 3, 4] |
||
>>> range(5) |
>>> range(5) |
||
[0, 1, 2, 3, 4] |
[0, 1, 2, 3, 4] |
||
</syntaxhighlight> |
|||
</source> |
|||
Генерация коллекций: |
Генерация коллекций: |
||
< |
<syntaxhighlight lang="python"> |
||
>>> [0]*10 |
>>> [0]*10 |
||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] |
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] |
||
>>> [ i for i in range(5) if i%2==0] |
>>> [ i for i in range(5) if i%2==0] |
||
[0, 2, 4] |
[0, 2, 4] |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Реализация перегрузки функций === |
=== Реализация перегрузки функций === |
||
Строка 98: | Строка 98: | ||
базовой реализации. Поддерживается минимум возможностей (только фиксированное количество позиционных аргументов, нет именованных аргументов, нет приведения типов (например <code>int -> float</code>) и т. п.), но работает достаточно быстро. |
базовой реализации. Поддерживается минимум возможностей (только фиксированное количество позиционных аргументов, нет именованных аргументов, нет приведения типов (например <code>int -> float</code>) и т. п.), но работает достаточно быстро. |
||
< |
<syntaxhighlight lang="python"> |
||
import sys # для получения объектов из вышележащих фрэймов стека |
import sys # для получения объектов из вышележащих фрэймов стека |
||
Строка 158: | Строка 158: | ||
print f("1") # напечатает : 11 |
print f("1") # напечатает : 11 |
||
f(2,2) # напечатает : Default call |
f(2,2) # напечатает : Default call |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Управление контекстом выполнения === |
=== Управление контекстом выполнения === |
||
Строка 164: | Строка 164: | ||
Следующий пример из [http://www.python.org/dev/peps/pep-0343/ PEP343] иллюстрирует применение оператора <code>with</code> для защиты блока кода от одновременного выполнения двумя потоками: |
Следующий пример из [http://www.python.org/dev/peps/pep-0343/ PEP343] иллюстрирует применение оператора <code>with</code> для защиты блока кода от одновременного выполнения двумя потоками: |
||
< |
<syntaxhighlight lang="python"> |
||
from __future__ import with_statement # задействует оператор with в коде |
from __future__ import with_statement # задействует оператор with в коде |
||
from contextlib import contextmanager |
from contextlib import contextmanager |
||
Строка 186: | Строка 186: | ||
print "Охраняемый блок кода. Блокировка будет освобождена при любом выходе из этого блока." |
print "Охраняемый блок кода. Блокировка будет освобождена при любом выходе из этого блока." |
||
# |
# |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Генератор чисел Фибоначчи === |
=== Генератор чисел Фибоначчи === |
||
Пример генератора [[числа Фибоначчи | чисел Фибоначчи]] и его использования: |
Пример генератора [[числа Фибоначчи | чисел Фибоначчи]] и его использования: |
||
< |
<syntaxhighlight lang="python"> |
||
def fibonacci(max): # генератор (а не функция, т.к. оператор return заменён на yield) |
def fibonacci(max): # генератор (а не функция, т.к. оператор return заменён на yield) |
||
a, b = 0, 1 |
a, b = 0, 1 |
||
Строка 200: | Строка 200: | ||
for n in fibonacci(100): # используем генератор fibonacci() как итератор |
for n in fibonacci(100): # используем генератор fibonacci() как итератор |
||
print(n) # печатаем все числа Фибоначчи меньшие 100 через пробел |
print(n) # печатаем все числа Фибоначчи меньшие 100 через пробел |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Альтернативный синтаксис доступа к элементам словаря === |
=== Альтернативный синтаксис доступа к элементам словаря === |
||
Строка 206: | Строка 206: | ||
Можно определить словарь, который в дополнение к обычному синтаксису доступа к значению по ключу <code>d[key]</code> может предоставлять синтаксически более наглядный доступ к атрибуту <code>d.key</code> в случае алфавитно-цифровых ключей: |
Можно определить словарь, который в дополнение к обычному синтаксису доступа к значению по ключу <code>d[key]</code> может предоставлять синтаксически более наглядный доступ к атрибуту <code>d.key</code> в случае алфавитно-цифровых ключей: |
||
< |
<syntaxhighlight lang="python"> |
||
class Entity(dict): # наследуем класс от __builtin__.dict |
class Entity(dict): # наследуем класс от __builtin__.dict |
||
def __getattr__(self, key): # этот метод будет вызван, если атрибут |
def __getattr__(self, key): # этот метод будет вызван, если атрибут |
||
Строка 232: | Строка 232: | ||
d.b_100 = 100 |
d.b_100 = 100 |
||
assert d.a == d['a'] and d.b_100 == d['b_100'] |
assert d.a == d['a'] and d.b_100 == d['b_100'] |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Функтор с генерацией байтокода === |
=== Функтор с генерацией байтокода === |
||
Строка 245: | Строка 245: | ||
''Это только пример, он реализует всего одну операцию — сложение и имеет несколько других ограничений.'' |
''Это только пример, он реализует всего одну операцию — сложение и имеет несколько других ограничений.'' |
||
< |
<syntaxhighlight lang="python"> |
||
#------------------------------------------------------------------------------- |
#------------------------------------------------------------------------------- |
||
import byteplay # специальный модуль для удобной работы с Python-байтокодом |
import byteplay # специальный модуль для удобной работы с Python-байтокодом |
||
Строка 304: | Строка 304: | ||
self.func = functools.update_wrapper(self.func,self.ofunc) |
self.func = functools.update_wrapper(self.func,self.ofunc) |
||
return self.func |
return self.func |
||
</syntaxhighlight> |
|||
</source> |
|||
<code> |
<code> |
||
# Ниже представлено тестирование скорости объектов FastFunctor и SlowFunctor |
# Ниже представлено тестирование скорости объектов FastFunctor и SlowFunctor |
||
Строка 345: | Строка 345: | ||
Пример лаконичной реализации операции транспонирования матриц с использованием парадигмы [[Функциональное программирование|функционального программирования]]. |
Пример лаконичной реализации операции транспонирования матриц с использованием парадигмы [[Функциональное программирование|функционального программирования]]. |
||
< |
<syntaxhighlight lang="python"> |
||
from pprint import pprint # модуль pprint используется для удобного вывода на экран |
from pprint import pprint # модуль pprint используется для удобного вывода на экран |
||
matrix = [[0.5, 0, 0, 0, 0], |
matrix = [[0.5, 0, 0, 0, 0], |
||
Строка 357: | Строка 357: | ||
pprint(matrix) |
pprint(matrix) |
||
pprint(matrix_t) |
pprint(matrix_t) |
||
</syntaxhighlight> |
|||
</source> |
|||
Вывод: |
Вывод: |
||
Строка 375: | Строка 375: | ||
=== Нахождение Факториала === |
=== Нахождение Факториала === |
||
< |
<syntaxhighlight lang="python"> |
||
factorial = lambda x: factorial(x - 1) * x if x > 1 else 1 |
factorial = lambda x: factorial(x - 1) * x if x > 1 else 1 |
||
</syntaxhighlight> |
|||
</source> |
|||
[[Категория:Python (язык программирования)]] |
[[Категория:Python (язык программирования)]] |
Версия от 16:03, 16 апреля 2020
В этой статье собраны примеры небольших программ на языке программирования Python, демонстрирующих его синтаксис и некоторые из возможностей.
Нахождение 10 наиболее частых слов на web странице
Данный пример чисто демонстрационный, так как его можно значительно улучшить.
from urllib2 import urlopen # из модуля urllib2 импортируем функцию urlopen
u = urlopen("http://python.org") # открываем URL на чтение
words = {} # связываем имя words с пустым словарём
# (словарь — неупорядоченный [[ассоциативный массив]])
for line in u: # читаем u по строкам
line = line.strip(" \n") # отбрасываем начальные и конечные пробелы
for word in line.split(" "): # режем каждую строку на слова, ограниченные пробелами
try: # блок обработки исключений
words[word] += 1 # пытаемся увеличить words[word] на единицу
except KeyError: # если не получилось (раньше words[word] не было)
words[word] = 1 # присваиваем единицу
# теперь словарь words содержит частоту встречаемости каждого слова.
# Например, words может содержать {"яблоко":5, "апельсин": 12, "груша": 8}
pairs = words.items() # делаем из словаря список пар
# pairs == [("яблоко",5), ("апельсин",12), ("груша",8)]
pairs.sort(key=lambda x: x[1], reverse=True) # сортируем по убыванию второго элемента пары
for p in pairs[:10]: # печатаем первые 10 элементов списка
print(p[0], p[1])
Текст для версии 3.7.1
from urllib.request import urlopen # из модуля urllib импортируем функцию urlopen
u = urlopen("http://python.org") # открываем URL на чтение
words = {} # связываем имя words с пустым словарём
# (словарь — неупорядоченный [[ассоциативный массив]])
for line in u: # читаем u по строкам
line =line.decode("utf-8") # преобразуем байт-строку в строку
line = line.strip(" \n") # отбрасываем начальные и конечные пробелы
for word in line.split(" "): # режем каждую строку на слова, ограниченные пробелами
try: # блок обработки исключений
words[word] += 1 # пытаемся увеличить words[word] на единицу
except KeyError: # если не получилось (раньше words[word] не было)
words[word] = 1 # присваиваем единицу
# теперь словарь words содержит частоту встречаемости каждого слова.
# Например, words может содержать {"яблоко":5, "апельсин": 12, "груша": 8}
pairs = words.items() # делаем из словаря список пар
# pairs == [("яблоко",5), ("апельсин",12), ("груша",8)]
A= sorted (pairs, key=lambda x: x[1], reverse=True) # сортируем по убыванию второго элемента пары
for p in A[:10]: # печатаем первые 10 элементов списка
print(p[0], p[1])
Примеры работы с последовательностями
Иллюстрируют особенности индексации элементов и срезов: при взятии среза нумеруются не сами элементы, а промежутки между ними.
>>> l = ['A', 'B', 'C', 'D', 'E'] # исходный список
>>> # 0 1 2 3 4 5 # пронумерованные промежутки между элементами
>>> # -5 -4 -3 -2 -1 # нумерация с конца
>>> l[0:2] # срез от нулевого до второго промежутка
['A', 'B']
>>> l[1:-2] # срез от второго до второго с конца элемента
['B','C']
>>> l[1::2] # каждый второй элемент начиная с первого
['B', 'D']
>>> l[::-1] # все элементы в обратном порядке
['E', 'D', 'C', 'B', 'A']
Функции подобные range()
поддерживают то же правило (для версий языка 2.x):
>>> range(2, 5)
[2, 3, 4]
>>> range(5)
[0, 1, 2, 3, 4]
Генерация коллекций:
>>> [0]*10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> [ i for i in range(5) if i%2==0]
[0, 2, 4]
Реализация перегрузки функций
Это пример простой реализации поддержки перегрузки функций на Python.
Она демонстрирует, как, используя уже имеющиеся в Python средства, можно обойти одно из ограничений
базовой реализации. Поддерживается минимум возможностей (только фиксированное количество позиционных аргументов, нет именованных аргументов, нет приведения типов (например int -> float
) и т. п.), но работает достаточно быстро.
import sys # для получения объектов из вышележащих фрэймов стека
class CannotResolve(Exception): # класс исключения для случая ненахождения функции
pass
class Resolver(object): # класс, реализующий разрешение на этапе исполнения
emess = "Can't found appropriate signature of func %s() for call with" + \
" params %r" # сообщение об ошибке
def __init__(self,name): # конструктор
self.function_map = {} # словарь, отображающий типы параметров на функции
self.default = None # функция по умолчанию
self.name = name # имя функции для вывода сообщений об ошибках
def __call__(self,*dt): # имитируем функцию, принимающую любое количество
# позиционных параметров
cls = tuple(map(type,dt)) # создаем tuple из типов переданных аргументов
# функция type возвращает тип своего параметра
# map вызовет type для каждого элемента из dt
try:
x = self.function_map[cls] # пытаемся получить функцию из словаря
except KeyError: # если подходящей нет,
if self.default is not None: # используем функцию по умолчанию
x = self.default
else: # если её нет - возбуждаем исключение
raise CannotResolve(self.emess % (self.name,cls))
return x(*dt) # вызываем функцию и возвращаем результат
def overload(*dt): # декоратор для перегрузки в качестве параметров
# принимает типы параметров
def closure(func):
name = func.__name__ # получаем имя функции
fr = sys._getframe(1).f_locals.get(name,Resolver(name))
# опускаемся на один шаг вниз по стеку и находим
# локальную переменную с именем функции
# если же ее нет, то используем новый
# Resolver-объект
fr.function_map[dt] = func # добавляем новую функцию к словарю
# разрешения вызовов
return fr
return closure
def overdef(func): # для создания функции по умолчанию
name = func.__name__ # аналогично как и в функции overload
fr = sys._getframe(1).f_locals.get(name,Resolver(name))
fr.default = func
return fr
# теперь воспользуемся полученными декораторами
@overdef # это будет функция по умолчанию
def f(*dt,**mp):
print "Default call" # если нет явного return, то вернется None
@overload(int) # единственный параметр - целое
def f(x):
return x + 1
@overload(str) # единственный параметр - строка
def f(x):
return x + "1"
@overload(str,int) # строка и целое
def f(x,y):
return x + str(y)
print f(1) # напечатает : 2
print f("1") # напечатает : 11
f(2,2) # напечатает : Default call
Управление контекстом выполнения
Следующий пример из PEP343 иллюстрирует применение оператора with
для защиты блока кода от одновременного выполнения двумя потоками:
from __future__ import with_statement # задействует оператор with в коде
from contextlib import contextmanager
from threading import Lock
# Описание менеджера контекста
@contextmanager
def locked(lock):
lock.acquire()
try:
yield
finally:
lock.release()
# Определение блокировки
myLock = Lock()
# Применение оператора
with locked(myLock):
#
print "Охраняемый блок кода. Блокировка будет освобождена при любом выходе из этого блока."
#
Генератор чисел Фибоначчи
Пример генератора чисел Фибоначчи и его использования:
def fibonacci(max): # генератор (а не функция, т.к. оператор return заменён на yield)
a, b = 0, 1
while a < max:
yield a # return a, + запоминаем место рестарта для следующего вызова
a, b = b, a + b # параллельное присваивание, которое выполняется одновременно и параллельно
for n in fibonacci(100): # используем генератор fibonacci() как итератор
print(n) # печатаем все числа Фибоначчи меньшие 100 через пробел
Альтернативный синтаксис доступа к элементам словаря
Можно определить словарь, который в дополнение к обычному синтаксису доступа к значению по ключу d[key]
может предоставлять синтаксически более наглядный доступ к атрибуту d.key
в случае алфавитно-цифровых ключей:
class Entity(dict): # наследуем класс от __builtin__.dict
def __getattr__(self, key): # этот метод будет вызван, если атрибут
# с именем key не будет найден у экземпляра класса
try:
return self[key] # пытаемся вернуть элемент словаря
except KeyError, k: # если такого элемента нет, то возбуждаем
raise AttributeError, k # исключение AttributeError
# по договоренности __getattr__
# не должно возбуждать других исключений
def __setattr__(self, key, value): # этот метод будет вызван при присвоении
self[key] = value # атрибуту key значения value
def __delattr__(self, key): # а этот при удалении атрибута
try: # с помощью del mydict.g
del self[key]
except KeyError, k:
raise AttributeError, k
def __repr__(self): # используется функцией repr
return self.__class__.__name__ + "(" + dict.__repr__(self) + ")"
d = Entity(a=1)
d.b_100 = 100
assert d.a == d['a'] and d.b_100 == d['b_100']
Функтор с генерацией байтокода
Пример эффективной реализации функтора, основанный на генерации байтокода во время исполнения. Этот пример демонстрирует следующие возможности/особенности Python:
- Возможность реализации специфических средств функционального программирования наработками, уже имеющимися в языке
- Работать с байтокодом в Python достаточно просто
- Зачастую генерация байтокода способна значительно ускорить исполнение.
Это только пример, он реализует всего одну операцию — сложение и имеет несколько других ограничений.
#-------------------------------------------------------------------------------
import byteplay # специальный модуль для удобной работы с Python-байтокодом
import new # для создания функции во время исполнения
import functools # для update_wrapper
import inspect # для получения информации о параметрах, принимаемых функцией
#-------------------------------------------------------------------------------
class FastFunctor(object):
def __init__(self,func,code = None):
self.func = None # здесь будем хранить результирующую функцию
self.ofunc = func # а здесь исходную(original) функцию
if code is None:
# конструируем байтокод для вызова функции
self.code = [(byteplay.LOAD_CONST,func)]
rparams = inspect.getargspec(func)[0] # получаем список параметров, принимаемых функцией
self.code.extend((byteplay.LOAD_FAST,i) for i in rparams)
self.code.append((byteplay.CALL_FUNCTION,len(rparams)))
else:
# если же функтор создан из другого функтора,
# то только копируем переданный байтокод
self.code = code
# создаем новый объект кода
self.ocode = bp.Code.from_code(func.func_code)
def __add__(self,obj): # этот метод вызывается для операции '+'
code = self.code[:] # копируем байтокод
if isinstance(obj,FastFunctor): # если прибавляемый объект - функтор
# просто дописываем его код к нашему
# после своего исполнения он "оставит" в вершине стека результат
code.extend(obj.code)
else:
# иначе загружаем объект в стек
code.append((byteplay.LOAD_CONST,obj))
# дописываем байтокод, складывающий два верхних элемента в стеке
code.append((byteplay.BINARY_ADD ,None ))
# создаем новый функтор, с байтокодом получения суммы
return self.__class__(self.ofunc,code = code)
def __call__(self,*dt,**mp): # этот метод будет вызван для операции вызова object()
return self.fast()(*dt,**mp) # конструируем и вызываем функцию
def fast(self): # конструируем функцию из байтокода
if self.func is None: # если функция не была создана раннее
code = self.code + [(bp.RETURN_VALUE,None)] # добавляем байтокод возврата
oc = self.ocode
# создаем объект кода из байтокода и другой информации
bin_code = byteplay.Code(code,
oc.freevars,
oc.args,
oc.varargs,
oc.varkwargs,
oc.newlocals,
"<just_code_%s>" % id(self),
"<auto_gen_%s>" % id(self),
0,
"auto_generated code")
# конструируем новую функцию из объекта кода
self.func = new.function(bin_code.to_code(),globals())
# после этой операции для всех средств интроспекции
# созданная функция будет выглядеть как оригинальная
self.func = functools.update_wrapper(self.func,self.ofunc)
return self.func
# Ниже представлено тестирование скорости объектов FastFunctor и SlowFunctor
# (статья "Функциональное программирование на Python", см. сноску после блока кода)
# из IPython (для удобства чтения лог немного изменен)
# строки, начинающиеся с "In [XX]:" вводятся, остальные — вывод интерпретатора
In [1]: import fastfunctor
In [2]: func = lambda x : x + 1 # Создаем очень простую функцию
In [3]: vl = 1 # Переменная, для предотвращения оптимизации
In [4]: functor = fastfunctor.Functor(func)
In [5]: %timeit (functor + functor + 1)(vl) # Тестируем "лобовой" способ
1000 loops, best of 3: 661 mks per loop # Очень медленно
In [6]: functor2 = (functor + functor + 1) # Конструируем функтор один раз
In [7]: %timeit functor2(vl) # и тестируем только непосредственно вызов
100000 loops, best of 3: 4.52 mks per loop # Значительно лучше
In [8]: functor3 = (functor + functor + 1).fast() # Получаем результирующую функцию
In [9]: %timeit functor3(vl)
1000000 loops, best of 3: 1.42 mks per loop
In [10]: def of(vl): return x(vl) + x(vl) + 1 # Создаем функцию "вручную"
In [11]: %timeit of(vl)
1000000 loops, best of 3: 1.42 mks per loop # Скорость полностью совпадает со
# скоростью функтора
In [12]: sfunctor = SlowFunctor(func) # Простая реализация функтора
In [13]: sfunctor = sfunctor + sfunctor + 1 #
In [14]: %timeit sfunctor(vl) #
100000 loops, best of 3: 12.6 mks per loop # Примерно в 9 раз медленнее, чем статический
# вариант
Код SlowFunctor можно посмотреть здесь.
Приведенные значения времени следует рассматривать только в сравнении друг с другом.
ipython — расширение интерпретатора Python для интерактивной работы.
Используя эту технику, можно создать полноценный функтор, добавив функции для других операций
(__sub__, __div__
и другие) и расширив его на случай нескольких входных
функций с разными аргументами.
Транспонирование матрицы
Пример лаконичной реализации операции транспонирования матриц с использованием парадигмы функционального программирования.
from pprint import pprint # модуль pprint используется для удобного вывода на экран
matrix = [[0.5, 0, 0, 0, 0],
[ 1, 0.5, 0, 0, 0],
[ 1, 1, 0.5, 0, 0],
[ 1, 1, 1, 0.5, 0],
[ 1, 1, 1, 1, 0.5]]
matrix_t = list(zip(*matrix)) # непосредственно транспонирование
pprint(matrix)
pprint(matrix_t)
Вывод:
[[0.5, 0, 0, 0, 0],
[1, 0.5, 0, 0, 0],
[1, 1, 0.5, 0, 0],
[1, 1, 1, 0.5, 0],
[1, 1, 1, 1, 0.5]]
[[0.5, 1, 1, 1, 1],
[0, 0.5, 1, 1, 1],
[0, 0, 0.5, 1, 1],
[0, 0, 0, 0.5, 1],
[0, 0, 0, 0, 0.5]]
Нахождение Факториала
factorial = lambda x: factorial(x - 1) * x if x > 1 else 1