Функции и их аргументы
Содержание:
- 3 С параметром locals
- Функция логарифма log() в Python
- Тригонометрические функции в Python
- Для чего используется **kwargs в Python?
- Синтаксис lambda-функции в Python
- Сравнение функции с методом
- Замена сеттеров и геттеров на свойство Python
- Функция filter():
- Бесконечный итератор
- Каковы преимущества многопоточности в Python?
- Важность функций
3 С параметром locals
Когда мы передаем только параметр (словарь), по умолчанию все встроенные методы также становятся доступными до тех пор, пока мы явно не исключим их.
Посмотрите на пример ниже, хотя мы указали словарь все встроенные и математические методы модуля доступны в текущей области.
from math import * def squareNo(a): return a*a #global And local parameters exec('print(pow(4,3))', {"squareit": squareNo, "print": print}) exec("print(dir())")
Выход:
64
Следовательно, теперь явно исключая встроенные функции.
from math import * def squareNo(a): return a*a #explicitly excluding built-ins exec('print(pow(4,3))', {"__builtins__": None},{"squareit": squareNo, "print": print}) exec("print(dir())")
Выход:
Traceback (most recent call last): File "C:/Users/sneha/Desktop/test.py", line 7, in <module> exec('print(pow(4,3))', {"__builtins__": None},{"squareit": squareNo, "print": print}) File "<string>", line 1, in <module> TypeError: 'NoneType' object is not subscriptable
В приведенном выше коде ограничение метода на использование только переданных (локальных) методов практически делает недоступным метод . Следовательно, при его запуске мы получаем .
Функция логарифма log() в Python
Функция возвращает логарифм определенного числа. Натуральный логарифм вычисляется относительно основания . В следующем примере показано использование функции логарифма:
Python
import math
print(«math.log(10.43):», math.log(10.43))
print(«math.log(20):», math.log(20))
print(«math.log(math.pi):», math.log(math.pi))
1 |
importmath print(«math.log(10.43):»,math.log(10.43)) print(«math.log(20):»,math.log(20)) print(«math.log(math.pi):»,math.log(math.pi)) |
В скрипте выше методу передаются числовые значения с различными типами данных. Также рассчитывается натуральный логарифм константы . Вывод следующий:
Shell
math.log(10.43): 2.344686269012681
math.log(20): 2.995732273553991
math.log(math.pi): 1.1447298858494002
1 |
math.log(10.43)2.344686269012681 math.log(20)2.995732273553991 math.log(math.pi)1.1447298858494002 |
Тригонометрические функции в Python
Модуль math в Python поддерживает все тригонометрические функции. Самые популярные представлены ниже:
- : Возвращает синус в радианах;
- : Возвращает косинус в радианах;
- : Возвращает тангенс в радианах;
- : Возвращает инвертированный синус. Аналогичным образом работают и ;
- : Конвертирует угол из радиан в градусы;
- : Конвертирует угол из градусов в радианы.
Рассмотрим следующий пример:
Python
import math
angle_In_Degrees = 62
angle_In_Radians = math.radians(angle_In_Degrees)
print(‘Значение угла:’, angle_In_Radians)
print(‘sin(x) равен:’, math.sin(angle_In_Radians))
print(‘tan(x) равен:’, math.tan(angle_In_Radians))
print(‘cos(x) равен:’, math.cos(angle_In_Radians))
1 |
importmath angle_In_Degrees=62 angle_In_Radians=math.radians(angle_In_Degrees) print(‘Значение угла:’,angle_In_Radians) print(‘sin(x) равен:’,math.sin(angle_In_Radians)) print(‘tan(x) равен:’,math.tan(angle_In_Radians)) print(‘cos(x) равен:’,math.cos(angle_In_Radians)) |
Вывод
Shell
Значение угла: 1.0821041362364843
sin(x) равен: 0.8829475928589269
tan(x) равен: 1.8807264653463318
cos(x) равен: 0.46947156278589086
1 |
Значениеугла1.0821041362364843 sin(x)равен0.8829475928589269 tan(x)равен1.8807264653463318 cos(x)равен0.46947156278589086 |
Обратите внимание, что вначале мы конвертировали значение угла из градусов в радианы для осуществления дальнейших операций
Для чего используется **kwargs в Python?
Форма с двумя звездочками используется в качестве параметра для отправки в функции списка аргументов переменной длины без ключевого слова. Две звездочки () также являются важным элементом, так как представляет собой общепринятую идиому, хотя она и не принуждается к использованию языком.
Как и , может принимать столько аргументов, сколько вам нужно. Однако отличается от тем, что здесь требуется назначить ключевые слова.
Сначала просто выведем аргументы из , которые мы передаем функции. Создаем для этого короткую функцию:
print_kwargs.py
Python
def print_kwargs(**kwargs):
print(kwargs)
1 |
defprint_kwargs(**kwargs) print(kwargs) |
Затем мы вызываем функцию с разными аргументами которые передаются в функцию:
print_kwargs.py
Python
def print_kwargs(**kwargs):
print(kwargs)
print_kwargs(kwargs_1=»Shark», kwargs_2=4.5, kwargs_3=True)
1 |
defprint_kwargs(**kwargs) print(kwargs) |
Запустим код и посмотрим на результат вывода:
Shell
python print_kwargs.py
1 | python print_kwargs.py |
Вывод:
Shell
{‘kwargs_1’: ‘Shark’, ‘kwargs_2’: 4.5, ‘kwargs_3’: True}
1 | {‘kwargs_1»Shark’,’kwargs_2’4.5,’kwargs_3’True} |
В зависимости от используемой версии Python 3, словарь может быть неупорядоченным. В Python 3.6 и более поздних версиях вы будете получать пары ключ-значение по порядку в котором они были переданы функции, но в более ранних версиях пары будут выводиться в случайном порядке.
Стоит отметить, что здесь под названием , и мы можем работать с ним так же, как и с другими словарями.
Создадим еще одну короткую программу, чтобы показать, как можно использовать . Здесь мы создадим функцию приветствия для словаря с именами. Начнем со словаря с двумя именами:
print_values.py
Python
def print_values(**kwargs):
for key, value in kwargs.items():
print(«Значение для {} является {}».format(key, value))
print_values(my_name=»Sammy», your_name=»Casey»)
1 |
defprint_values(**kwargs) forkey,value inkwargs.items() print(«Значение для {} является {}».format(key,value)) print_values(my_name=»Sammy»,your_name=»Casey») |
Теперь мы можем запустить программу и посмотреть на результат вывода:
Shell
python print_values.py
1 | python print_values.py |
Вывод:
Shell
Значение для my_name является Sammy
Значение для your_name является Casey
1 |
Значениедляmy_nameявляетсяSammy Значениедляyour_nameявляетсяCasey |
Так как словари могут быть в хаотичном порядке, ваш вывод может начинаться с имени вместо .
Передадим дополнительные аргументы для функции, чтобы показать, что примет столько аргументов, сколько вам нужно:
print_values.py
Python
def print_values(**kwargs):
for key, value in kwargs.items():
print(«Значение для {} является {}».format(key, value))
print_values(
name_1=»Alex»,
name_2=»Gray»,
name_3=»Harper»,
name_4=»Phoenix»,
name_5=»Remy»,
name_6=»Val»
)
1 |
defprint_values(**kwargs) forkey,value inkwargs.items() print(«Значение для {} является {}».format(key,value)) print_values( name_1=»Alex», name_2=»Gray», name_3=»Harper», name_4=»Phoenix», name_5=»Remy», name_6=»Val» ) |
Сейчас при запуске программы мы получим следующий вывод, порядок которого у вас может отличаться:
Shell
Значение для name_1 является Alex
Значение для name_2 является Gray
Значение для name_3 является Harper
Значение для name_4 является Phoenix
Значение для name_5 является Remy
Значение для name_6 является Val
1 |
Значениедляname_1являетсяAlex Значениедляname_2являетсяGray Значениедляname_3являетсяHarper Значениедляname_4являетсяPhoenix Значениедляname_5являетсяRemy Значениедляname_6являетсяVal |
Использование параметра предоставляет гибкость при использовании аргументов с ключевыми словами в программе. Когда мы используем в качестве параметра, нам не нужно знать, сколько аргументов в конечном итоге будет передано функции.
Синтаксис lambda-функции в Python
Мы уже посмотрели, как объявляетcя lambda-функция в Python, но, как и все, что состоит из частей, ее объявление предполагает различные варианты. Так давайте же посмотрим, что мы можем, а что не можем делать с lambda-функцией.
a. Аргументы в Python
Одна или несколько переменных, присутствующих в выражении могут быть объявлены заранее. Но если речь идет об аргументах, то их значение должно быть либо задано по умолчанию, либо передано при вызове функции.
a,b=1,2 y=lambda a,b:a+b y() Traceback (most recent call last): File “<pyshell#167>”, line 1, in <module> y() TypeError: <lambda>() missing 2 required positional arguments: ‘a’ and ‘b’
Здесь отсутствуют значения и a и b
y=lambda a:a+b y() Traceback (most recent call last): File “<pyshell#169>”, line 1, in <module> y() TypeError: <lambda>() missing 1 required positional argument: ‘a’
У переменной a все еще отсутствует значение
y=lambda :a+b y() 3
Наконец здесь, так как нет аргументов с отсутствующим значением, все отлично работает.
Рекомендуем ознакомиться со статьями Ошибки и Исключения в Python(англ.) и Как исправить ошибки в Python (англ.).
b. Пропускаем аргументы
Указывать аргументы в lambda-функции не обязательно. Она отлично работает и без них.
y=lambda :2+3 y() 5
Во втором примере давайте в качестве выражения используем функцию print()
(lambda :print("Привет"))() Привет
Вывод напрашивается сам собой, — пропуск аргументов в lambda-функции является вполне приемлемым.
c. Пропускаем выражение
Теперь давайте попробуем запустить нашу функцию без выражения.
y=lambda a,b: SyntaxError: invalid syntax
Ясное дело ничего не сработало, да и почему оно должно было сработать, если значение выражение это как раз и есть то, что функция возвращает? Без выражения функция не имеет никакого смысла.
Сравнение функции с методом
- Функция Python является частью файла сценария Python, в котором она определена, тогда как методы определены внутри определения класса.
- Мы можем вызвать функцию напрямую, если она находится в том же модуле. Если функция определена в другом модуле, мы можем импортировать модуль, а затем вызвать функцию напрямую. Нам нужен класс или объект класса для вызова методов.
- Функция Python может обращаться ко всем глобальным переменным, тогда как методы класса Python могут обращаться к глобальным переменным, а также к атрибутам и функциям класса.
- Тип данных функций Python — это «функция», а тип данных методов Python — «метод».
Давайте посмотрим на простой пример функций и методов в Python.
class Data: def foo(self): print('foo method') def foo(): print('foo function') # calling a function foo() # calling a method d = Data() d.foo() # checking data types print(type(foo)) print(type(d.foo))
Вывод:
foo function foo method <class 'function'> <class 'method'>
Преимущества
- Возможность повторного использования кода, потому что мы можем вызывать одну и ту же функцию несколько раз
- Модульный код, поскольку мы можем определять разные функции для разных задач
- Улучшает ремонтопригодность кода
- Абстракция, поскольку вызывающему абоненту не нужно знать реализацию функции
Замена сеттеров и геттеров на свойство Python
Давайте представим, что у нас есть код, который написал кто-то, кто не очень понимает Python. Как и я, вы скорее всего, видели такого рода код ранее:
Python
# -*- coding: utf-8 -*-
from decimal import Decimal
class Fees(object):
«»»»»»
def __init__(self):
«»»Конструктор»»»
self._fee = None
def get_fee(self):
«»»
Возвращаем текущую комиссию
«»»
return self._fee
def set_fee(self, value):
«»»
Устанавливаем размер комиссии
«»»
if isinstance(value, str):
self._fee = Decimal(value)
elif isinstance(value, Decimal):
self._fee = value
1 |
# -*- coding: utf-8 -*- fromdecimalimportDecimal classFees(object) «»»»»» def__init__(self) «»»Конструктор»»» self._fee=None defget_fee(self) «»» Возвращаем текущую комиссию returnself._fee defset_fee(self,value) «»» Устанавливаем размер комиссии ifisinstance(value,str) self._fee=Decimal(value) elifisinstance(value,Decimal) self._fee=value |
Для использования этого класса, нам нужно использовать сеттеры и геттеры, которые определены как:
Python
f = Fees()
f.set_fee(«1»)
print(f.get_fee()) # Decimal(‘1’)
1 |
f=Fees() f.set_fee(«1») print(f.get_fee())# Decimal(‘1’) |
Если вам нужно добавить обычную точечную нотацию атрибутов в данный код без выведения из строя всех приложений в этой части кода, вы можете сделать это очень просто, добавив свойство:
Python
# -*- coding: utf-8 -*-
from decimal import Decimal
class Fees(object):
«»»»»»
def __init__(self):
«»»Конструктор»»»
self._fee = None
def get_fee(self):
«»»
Возвращаем текущую комиссию
«»»
return self._fee
def set_fee(self, value):
«»»
Устанавливаем размер комиссии
«»»
if isinstance(value, str):
self._fee = Decimal(value)
elif isinstance(value, Decimal):
self._fee = value
fee = property(get_fee, set_fee)
1 |
# -*- coding: utf-8 -*- fromdecimalimportDecimal classFees(object) «»»»»» def__init__(self) «»»Конструктор»»» self._fee=None defget_fee(self) «»» Возвращаем текущую комиссию returnself._fee defset_fee(self,value) «»» Устанавливаем размер комиссии ifisinstance(value,str) self._fee=Decimal(value) elifisinstance(value,Decimal) self._fee=value fee=property(get_fee,set_fee) |
Мы добавили одну строк в конце этого кода. Теперь мы можем делать что-то вроде этого:
Python
f = Fees()
f.set_fee(«1»)
print(f.fee) # Decimal(‘1’)
f.fee = «2»
print( f.get_fee() ) # Decimal(‘2’)
1 |
f=Fees() f.set_fee(«1») print(f.fee)# Decimal(‘1’) f.fee=»2″ print(f.get_fee())# Decimal(‘2’) |
Как мы видим, когда мы используем свойство таким образом, это позволяет свойству fee настраивать и получать значение без поломки наследуемого кода. Давайте перепишем этот код с использованием декоратора property, и посмотрим, можем ли мы получить его для разрешения установки.
Python
# -*- coding: utf-8 -*-
from decimal import Decimal
class Fees(object):
«»»»»»
def __init__(self):
«»»Конструктор»»»
self._fee = None
@property
def fee(self):
«»»
Возвращаем текущую комиссию — геттер
«»»
return self._fee
@fee.setter
def fee(self, value):
«»»
Устанавливаем размер комиссии — сеттер
«»»
if isinstance(value, str):
self._fee = Decimal(value)
elif isinstance(value, Decimal):
self._fee = value
if __name__ == «__main__»:
f = Fees()
1 |
# -*- coding: utf-8 -*- fromdecimalimportDecimal classFees(object) «»»»»» def__init__(self) «»»Конструктор»»» self._fee=None @property deffee(self) «»» Возвращаем текущую комиссию — геттер returnself._fee @fee.setter deffee(self,value) «»» Устанавливаем размер комиссии — сеттер ifisinstance(value,str) self._fee=Decimal(value) elifisinstance(value,Decimal) self._fee=value if__name__==»__main__» f=Fees() |
Данный код демонстрирует, как создать сеттер для свойства fee. Вы можете делать это, декорируя второй метод, который также называется fee с декоратором, под названием <@fee.setter>. Сеттер будет вызван, когда вы сделаете что-то вроде следующего:
Python
f = Fees()
f.fee = «1»
1 |
f=Fees() f.fee=»1″ |
Если вы взгляните на подписи под свойством, то это будут fget, fset, fdel и doc в качестве аргументов. Вы можете создать другой декорируемый метод, используя то же название связи с функцией delet при помощи <@fee.deleter*>*, если вы хотите поймать команду **del для атрибута.
Функция filter():
Функция filter() используется для создания списка, состоящего из значений, для которых функция возвращает true. Синтаксис этого следующий:
filter(function, iterables)
Так же, как и map(), эта функция может использовать в качестве параметра пользовательские функции, а также lambda-функции.
Пример:
def func(x): if x>=3: return x y = filter(func, (1,2,3,4)) print(y) print(list(y))
Результат:
<filter object at 0x00000284B9BBCC50>
Как видите, y — это объект типа функции filter, а выходной список — это список значений, которые являются истинными для условия (x>=3).
Использование lambda-функций совместно с filter():
Lambda-функция, которая используется в качестве параметра, фактически определяет условие, которое необходимо проверить.
Пример:
y = filter(lambda x: (x>=3), (1,2,3,4)) print(list(y))
Результат:
Приведенный выше код выдает тот же результат, что и предыдущая функция.
Бесконечный итератор
В Python действительно возможно создать итератор, который никогда не исчерпывается. Функция iter() может принимать другой аргумент, называемый «страж». Этот страж является точкой выхода и работает следующим образом: как только значение, возвращаемое итератором равно значению стража, итератор заканчивается.
Мы знаем, что функция int() без параметра внутри возвращает 0.
>>> int()
Теперь мы вызываем iter() с двумя аргументами — int и 1.
>>> a=iter(int,1)
Этот итератор Python никогда не исчерпает себя, он бесконечен. Это потому, что 0 никогда не равен 1. Серьезно, никогда.
>>> next(a) >>> next(a) >>> next(a) >>> next(a) >>> next(a)
И так далее.
Чтобы создать бесконечный итератор Python с использованием класса, рассмотрим следующий пример.
class Even: def __iter__(self): self.num=2 return self def __next__(self): num=self.num self.num+=2 return num >>> e=Even() >>> i=iter(e) >>> next(i) 2 >>> next(i) 4 >>> next(i) 6 >>> next(i) 8
Здесь Python перебирает четные числа, начинающиеся с 2 и никогда не заканчивающиеся. Таким образом, вы должны быть осторожны и обеспечить завершающее условие (точку выхода).
Каковы преимущества многопоточности в Python?
У создания многопоточных приложений есть немало преимуществ. Давайте посмотрим на некоторые преимущества:
- Эффективное использование ресурсов;
- Более отзывчивый;
- Совместное использование ресурсов делает его более экономичным;
- Эффективное использование многопроцессорной архитектуры за счет параллелизма;
- Экономит время;
- Потоки (поскольку они являются частью одного процесса) легче взаимодействуют друг с другом, чем если бы они были отдельными процессами;
- Они не требуют больших затрат памяти;
- Многопоточные серверы и интерактивные графические интерфейсы используют исключительно многопоточность.
Многопоточность используется случаях:
- Когда выходы подпрограмм нужно объединить с основной программой.
- Если основная программа содержит фрагмент кода, который относительно независим друг от друга.
- Когда выходы подпрограмм нужно объединить с основной программой.
- Основная программа содержит фрагмент кода, который относительно независим друг от друга.
Модуль Threading определяет множество функций, которые используются для получения данных, связанных с потоками, и эти функции выполняются автоматически.
threading.active_count()
Эта функция возвращает количество объектов Thread, которые в данный момент живы. Здесь возвращаемое количество равно длине списка, возвращаемого enumerate().
threading.current_thread()
Эта функция возвращает текущий объект Thread, и он соответствует потоку управления вызывающей стороны.
threading.get_ident()
Эта функция возвращает «идентификатор потока» текущего потока. Это ненулевое целое число.
threading.enumerate()
Эта функция возвращает список всех текущих объектов Thread, включая демонические потоки, функция current_thread() создает фиктивный поток и основной поток и исключает завершенные потоки и потоки, которые еще не были запущены.
threading.main_thread()
Эта функция возвращает основной объект Thread.
threading.settrace (Func)
Когда все потоки запускаются из модуля потоков, установите функцию трассировки. Перед вызовом метода run() эта функция передается в sys.settrace() для каждого потока.
threading.setprofile (FUNC)
Когда все потоки запускаются из модуля потоков, установите функцию профиля. Перед вызовом метода run() эта функция передается в sys.setprofile() для каждого потока.
threading.stack_size ()
Эта функция возвращает размер стека потоков и используется при создании новых потоков.
import threading def trace_function(): print("Passing the trace function") def profile(): print("PROFILE THREAD: " + str(threading.current_thread().getName())) class mythread(threading.Thread): def __init__(self, thread_name, thread_ID): threading.Thread.__init__(self) self.thread_name = thread_name self.thread_ID = thread_ID def run(self): print(str(self.thread_ID)); print("ACTIVE THREADS ARE: "+ str(threading.active_count())) print("CURRENT THREAD IS: " + str(threading.current_thread().getName())) my_thread1 = mythread("PP", 500) my_thread2 = mythread("PythonProgram", 1000); print("NAME OF THE MAIN THREAD: " + str(threading.main_thread().getName())) print("IDENTIFICATION OF MAIN THREAD: "+ str(threading.get_ident())) print("STACK SIZE = " + str(threading.stack_size())) print(threading.settrace(trace_function())) threading.setprofile(profile()) my_thread1.start() my_thread2.start() print("LIST OF ENUMERATION: ") print(threading.enumerate()) print("EXIT")
Эта константа имеет максимальное значение, допустимое для параметра времени ожидания функций блокировки (Lock.acquire(), RLock.acquire(), Condition.wait() и т. д.).
NAME OF THE MAIN THREAD: MainThread IDENTIFICATION OF MAIN THREAD: 5436 STACK SIZE = 0 Passing the trace function None PROFILE THREAD: MainThread 500 1000LIST OF ENUMERATION: ACTIVE THREADS ARE: 6 EXIT CURRENT THREAD IS: Thread-8 ACTIVE THREADS ARE: 5 CURRENT THREAD IS: Thread-9
Перейдем к созданию нашего первого многопоточного приложения.
Важность функций
Абстракция
Человек бежит, машина едет, корабль плывёт, а самолёт летит. Всё это – объекты реального мира, которые выполняют однотипные действия. В данном случае, они перемещаются во времени и пространстве. Мы можем абстрагироваться от их природы, и рассматривать эти объекты с точки зрения того, какое расстояние они преодолели, и сколько времени на это ушло.
Мы можем написать функцию, которая вычисляет скорость в каждом конкретном случае
Нам не важно, кто совершает движение: и для человека и для самолёта средняя скорость будет рассчитываться одинаково
Это простой пример и простая функция, но абстракции могут быть куда более сложными. И именно тогда раскрывается настоящая сила функций. Вместо того чтобы решать задачу для каждого конкретного случая, проще написать функцию, которая находит решение для целого ряда однотипных, в рамках применяемой абстракции, объектов. В случае сложных и длинных вычислений, это повлечёт за собой значительное сокращение объёмов кода, а значит и времени на его написание.
Возможность повторного использования
Функции были созданы ради возможности их многократного применения. Код без функций превратился бы в огромное нечитаемое полотно, на порядки превышающее по длине аналогичную программу с их использованием.
Например, при работе с массивами чисел, вам нужно часто их сортировать. Вместо того чтобы реализовать простой алгоритм сортировки (или использовать встроенную функцию), вам пришлось бы каждый раз перепечатывать тело этой или похожей функции:
Всего 10 таких сортировок, и привет, лишние 60 строк кода.
Модульность
Разбитие больших и сложных процессов на простые составляющие – важная часть, как кодинга, так и реальной жизни. В повседневности мы занимаемся этим неосознанно. Когда убираемся в квартире, мы пылесосим, моем полы и окна, очищаем поверхности от пыли и наводим блеск на всё блестящее. Всё это – составляющие одного большого процесса под названием «уборка», но каждую из них также можно разбить на более простые подпроцессы.
В программировании модульность строится на использовании функций. Для каждой подзадачи – своя функция. Такая компоновка в разы улучшает читабельность кода и уменьшает сложность его дальнейшей поддержки.
Допустим, мы работаем с базой данных. Нам нужна программа, которая считывает значения из базы, обрабатывает их, выводит результат на экран, а затем записывает его обратно в базу.
Без применения модульности получится сплошная последовательность инструкций:
Но если вынести каждую операцию в отдельную функцию, то текст главной программы получится маленьким и аккуратным.
Это и называется модульностью.
Пространство имен
Концепция пространства имён расширяет понятие модульности. Однако цель – не облегчить читаемость, а избежать конфликтов в названиях переменных.
Пример из жизни: в ВУЗе учатся два человека с совпадающими ФИО. Их нужно как-то различать. Если сделать пространствами имён группы этих студентов, то проблема будет решена. В рамках своей группы ФИО этих студентов будут уникальными.