Це четверта історія та продовження нашої попередньої розповіді з серії про Python. У цій історії ми розглянемо наступні теми:
- Простір імен
- Скрипти
- Модулі
- Пакети
Бібліотека -> Пакети -> Підпакети -> Модулі
Простір імен
Управління простором імен в Python гарантує, що змінні, функції та інші ідентифікатори, визначені всередині модуля або функції, випадково не перепишуть або не будуть перешкоджати іншим частинам програми. Це досягається за допомогою правил області видимості та просторів імен, які поділяються на різні рівні (або області).
В Python є кілька рівнів просторів імен:
- Глобальний простір імен: Це найвищий рівень простору імен для програми, що включає всі змінні та функції, визначені на глобальному рівні.
- Простір імен модуля: Кожен модуль має власний простір імен. Змінні, функції та класи, визначені в модулі, є частиною простору імен цього модуля.
- Простір імен функції: Коли ви визначаєте змінні або функції всередині функції, ці імена існують у власному локальному просторі імен функції.
- Вбудований простір імен: Python має вбудований простір імен для функцій та виключень (як-от
print()
,len()
,Exception
тощо).
% cat func_arg.py
x = 100 # Глобальна змінна
def my_function():
x = 10 # Локальна змінна
y = 20 # Локальна змінна
print(f"Локальний x всередині функції: {x}")
print(dir())
my_function()
print(f"Глобальний x поза функцією: {x}")
print(dir())
% python func_arg.py
Локальний x всередині функції: 10
['x', 'y']
Глобальний x поза функцією: 100
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'my_function', 'x']
- Змінна x всередині my_function є локальною і існує тільки
в межах області видимості функції (локальний простір імен).
- x, визначена поза функцією, є глобальною змінною та є частиною
глобального простору імен.
- Коли викликається my_function(), друкується локальна змінна x (значення 10),
але глобальна x (значення 100) залишається незмінною.
Функція dir()
в Python використовується для повернення списку дійсних атрибутів (імен) для об'єкта. Вона може бути використана для перевірки атрибутів та методів об'єкта, модуля, класу чи вбудованого простору імен - dir([object])
.
- Якщо передано аргумент
object
,dir()
повертає список атрибутів цього об'єкта. - Якщо аргумент не передано, функція повертає список імен в поточній області видимості (локальній або глобальній).
Python Скрипти
Python скрипт — це по суті Python програма, яка виконується безпосередньо інтерпретатором Python. Зазвичай це самостійні програми, які використовуються для автоматизації завдань або виконання специфічних операцій. __name__
— це спеціальна вбудована змінна в Python, яка вказує на ім'я модуля.
Характеристики Python скриптів:
Виконуваність: Скрипт зазвичай виконується безпосередньо через команду python, наприклад, python script.py.
Точка входу: В Python точка входу скрипту зазвичай визначається через конструкцію if __name__ == “__main__”:
. Умова if __name__ == "__main__":
дає значення True
, і викликається функція main()
.
Якщо скрипт імпортується як модуль, name встановлюється на ім'я скрипта (наприклад, script).
% cat func_arg.py
def greet(name):
print(f"Hello, {name}!")
print(f"Друкуємо ім'я модуля з функції greet: {__name__}")
def main():
# Основна логіка програми
user_name = input("Введіть ваше ім'я: ")
greet(user_name)
if __name__ == "__main__":
main()
% python func_arg.py
Введіть ваше ім'я: Arjun
Hello, Arjun!
Друкуємо ім'я модуля з функції greet: __main__
Модуль
Модуль — це Python файл з розширенням .py
, який призначений для імпорту в скрипти або інші модулі.
Це четверта історія та продовження нашої попередньої розповіді з серії про Python. У цій історії ми розглянемо наступні теми:
- Простір імен
- Скрипти
- Модулі
- Пакети
Бібліотека -> Пакети -> Підпакети -> Модулі
Простір імен
Управління простором імен в Python гарантує, що змінні, функції та інші ідентифікатори, визначені всередині модуля або функції, випадково не перепишуть або не будуть перешкоджати іншим частинам програми. Це досягається за допомогою правил області видимості та просторів імен, які поділяються на різні рівні (або області).
В Python є кілька рівнів просторів імен:
- Глобальний простір імен: Це найвищий рівень простору імен для програми, що включає всі змінні та функції, визначені на глобальному рівні.
- Простір імен модуля: Кожен модуль має власний простір імен. Змінні, функції та класи, визначені в модулі, є частиною простору імен цього модуля.
- Простір імен функції: Коли ви визначаєте змінні або функції всередині функції, ці імена існують у власному локальному просторі імен функції.
- Вбудований простір імен: Python має вбудований простір імен для функцій та виключень (як-от
print()
,len()
,Exception
тощо).
% cat func_arg.py
x = 100 # Глобальна змінна
def my_function():
x = 10 # Локальна змінна
y = 20 # Локальна змінна
print(f"Локальний x всередині функції: {x}")
print(dir())
my_function()
print(f"Глобальний x поза функцією: {x}")
print(dir())
% python func_arg.py
Локальний x всередині функції: 10
['x', 'y']
Глобальний x поза функцією: 100
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'my_function', 'x']
- Змінна x всередині my_function є локальною і існує тільки
в межах області видимості функції (локальний простір імен).
- x, визначена поза функцією, є глобальною змінною та є частиною
глобального простору імен.
- Коли викликається my_function(), друкується локальна змінна x (значення 10),
але глобальна x (значення 100) залишається незмінною.
Функція dir()
в Python використовується для повернення списку дійсних атрибутів (імен) для об'єкта. Вона може бути використана для перевірки атрибутів та методів об'єкта, модуля, класу чи вбудованого простору імен - dir([object])
.
- Якщо передано аргумент
object
,dir()
повертає список атрибутів цього об'єкта. - Якщо аргумент не передано, функція повертає список імен в поточній області видимості (локальній або глобальній).
Python Скрипти
Python скрипт — це по суті Python програма, яка виконується безпосередньо інтерпретатором Python. Зазвичай це самостійні програми, які використовуються для автоматизації завдань або виконання специфічних операцій. __name__
— це спеціальна вбудована змінна в Python, яка вказує на ім'я модуля.
Характеристики Python скриптів:
Виконуваність: Скрипт зазвичай виконується безпосередньо через команду python, наприклад, python script.py.
Точка входу: В Python точка входу скрипту зазвичай визначається через конструкцію if __name__ == “__main__”:
. Умова if __name__ == "__main__":
дає значення True
, і викликається функція main()
.
Якщо скрипт імпортується як модуль, name встановлюється на ім'я скрипта (наприклад, script).
% cat func_arg.py
def greet(name):
print(f"Hello, {name}!")
print(f"Друкуємо ім'я модуля з функції greet: {__name__}")
def main():
# Основна логіка програми
user_name = input("Введіть ваше ім'я: ")
greet(user_name)
if __name__ == "__main__":
main()
% python func_arg.py
Введіть ваше ім'я: Arjun
Hello, Arjun!
Друкуємо ім'я модуля з функції greet: __main__
Модуль
Модуль — це Python файл з розширенням .py
, який призначений для імпорту в скрипти або інші модулі.
Це дозволяє організувати наш код у кілька файлів для кращої підтримуваності, повторного використання та розподілу відповідальності.
Модуль — це Python файл з розширенням .py
, який призначений для імпорту в скрипти або інші модулі. Модуль — це просто файл, що містить визначення Python, функції, класи та виконуваний код.
# Виконання наступного коду нічого не дасть. Тому це класифікується як модуль.
cat module_add.py
-------------
def add (x,y):
return x+y
--------######--------#######--------#######--------#######--------
# Виконання наступного коду виконає функцію. Тому це класифікується як скрипт.
cat script_add.py
------------
def add (x,y):
return x+y
print(add (5,6))
% cat mymodule.py
# mymodule.py
def greet(name):
print(f"Hello, {name}!")
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"Hi, I'm {self.name} and I'm {self.age} years old.")
print(f"I am from module: {__name__}")
% cat main.py
import mymodule
mymodule.greet("Arjun")
person = mymodule.Person("Bob", 30)
person.introduce()
# Виконання модуля як скрипту
% python mymodule.py
I am from module: __main__
# Виклик модуля з скрипта
% python main.py
I am from module: mymodule
Hello, Arjun!
Hi, I'm Bob and I'm 30 years old.
Як імпортувати модуль
- Основний імпорт: Імпортуйте модуль в Python за допомогою інструкції
import
__name__
— це спеціальна змінна, яка вказує на ім'я Python модуля, встановлене інтерпретатором. Якщо ваш модуль викликається як скрипт, то рядок ‘__main__
’ автоматично буде призначений спеціальній змінній __name__
. Але якщо ви імпортуєте модуль в інший модуль, рядок ‘moduleadd’ буде призначений `name_`.
% cat script_add.py
import module_add
module_add.author = "Aadya"
print(f"Автор: {module_add.author}")
print(module_add.add(5,6))
% cat module_add.py
import sys
print(f"Імпортуємо модуль, ім'я встановлене інтерпретатором: {__name__}")
author = "Arjun Pandey"
def add (x,y):
print(f"Деталі модуля: {sys.modules[__name__]}")
return x+y
% python script_add.py
Імпортуємо модуль, ім'я встановлене інтерпретатором: module_add
Автор: Aadya
Деталі модуля:
11
2. Вибірковий імпорт: Імпорт специфічних змінних/функцій/класів. Ви можете імпортувати певну частину пакету або модуля за допомогою наступного синтаксису.
% cat module_add.py
import sys
print(f"Імпортуємо модуль, ім'я встановлене інтерпретатором: {__name__}")
author = "Arjun Pandey"
def add (x,y):
print(f"Деталі модуля: {sys.modules[__name__]}")
return x+y
% cat script_add.py
from module_add import author, add
print(f"Автор: {author}")
print(add(5,6))
% python script_add.py
Імпортуємо модуль, ім'я встановлене інтерпретатором: module_add
Автор: Arjun Pandey
Деталі модуля:
11
3. Імпорт з псевдонімом: Імпортуйте модуль та призначте псевдонім у Python
% cat module_add.py
import sys
print(f"Імпортуємо модуль, ім'я встановлене інтерпретатором: {__name__}")
author = "Arjun Pandey"
def add (x,y):
print(f"Деталі модуля: {sys.modules[__name__]}")
return x+y
% cat script_add.py
from module_add import author as auth, add as a
print(f"Автор: {auth}")
print(a(5,6))
% python script_add.py
Імпортуємо модуль, ім'я встановлене інтерпретатором: module_add
Автор: Arjun Pandey
Деталі модуля:
11
4. Імпортування всього за допомогою *
в Python: Щоб імпортувати всі об'єкти (функції, змінні, класи тощо) з модуля, можна використати інструкцію import *
.
Це дозволяє організувати наш код у кілька файлів для кращої підтримуваності, повторного використання та розподілу відповідальності.
Модуль — це Python файл з розширенням .py
, який призначений для імпорту в скрипти або інші модулі. Модуль — це просто файл, що містить визначення Python, функції, класи та виконуваний код.
# Виконання наступного коду нічого не дасть. Тому це класифікується як модуль.
cat module_add.py
-------------
def add (x,y):
return x+y
--------######--------#######--------#######--------#######--------
# Виконання наступного коду виконає функцію. Тому це класифікується як скрипт.
cat script_add.py
------------
def add (x,y):
return x+y
print(add (5,6))
% cat mymodule.py
# mymodule.py
def greet(name):
print(f"Hello, {name}!")
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"Hi, I'm {self.name} and I'm {self.age} years old.")
print(f"I am from module: {__name__}")
% cat main.py
import mymodule
mymodule.greet("Arjun")
person = mymodule.Person("Bob", 30)
person.introduce()
# Виконання модуля як скрипту
% python mymodule.py
I am from module: __main__
# Виклик модуля з скрипта
% python main.py
I am from module: mymodule
Hello, Arjun!
Hi, I'm Bob and I'm 30 years old.
Як імпортувати модуль
- Основний імпорт: Імпортуйте модуль в Python за допомогою інструкції
import
__name__
— це спеціальна змінна, яка вказує на ім'я Python модуля, встановлене інтерпретатором. Якщо ваш модуль викликається як скрипт, то рядок ‘__main__
’ автоматично буде призначений спеціальній змінній __name__
. Але якщо ви імпортуєте модуль в інший модуль, рядок ‘moduleadd’ буде призначений `name_`.
% cat script_add.py
import module_add
module_add.author = "Aadya"
print(f"Автор: {module_add.author}")
print(module_add.add(5,6))
% cat module_add.py
import sys
print(f"Імпортуємо модуль, ім'я встановлене інтерпретатором: {__name__}")
author = "Arjun Pandey"
def add (x,y):
print(f"Деталі модуля: {sys.modules[__name__]}")
return x+y
% python script_add.py
Імпортуємо модуль, ім'я встановлене інтерпретатором: module_add
Автор: Aadya
Деталі модуля:
11
2. Вибірковий імпорт: Імпортуйте специфічні змінні/функції/класи. Ви можете імпортувати певну частину пакету або модуля за допомогою наступного синтаксису.
% cat module_add.py
import sys
print(f"Імпортуємо модуль, ім'я встановлене інтерпретатором: {__name__}")
author = "Arjun Pandey"
def add (x,y):
print(f"Деталі модуля: {sys.modules[__name__]}")
return x+y
% cat script_add.py
from module_add import author, add
print(f"Автор: {author}")
print(add(5,6))
% python script_add.py
Імпортуємо модуль, ім'я встановлене інтерпретатором: module_add
Автор: Arjun Pandey
Деталі модуля:
11
3. Імпорт з псевдонімом: Імпортуйте модуль та призначте псевдонім у Python
% cat module_add.py
import sys
print(f"Імпортуємо модуль, ім'я встановлене інтерпретатором: {__name__}")
author = "Arjun Pandey"
def add (x,y):
print(f"Деталі модуля: {sys.modules[__name__]}")
return x+y
% cat script_add.py
from module_add import author as auth, add as a
print(f"Автор: {auth}")
print(a(5,6))
% python script_add.py
Імпортуємо модуль, ім'я встановлене інтерпретатором: module_add
Автор: Arjun Pandey
Деталі модуля:
11
4. Імпортування всього за допомогою *
в Python: Щоб імпортувати всі об'єкти (функції, змінні, класи тощо) з модуля, можна використати інструкцію import *
.
В Python використання інструкції import *
— тобто імпортування всього з модуля — загалом не рекомендується.
Проблеми з import *
Можливі конфлікти імен:
% cat module_a.py
def greet():
print("Hello from module A!")
% cat module_b.py
def greet():
print("Hello from module B!")
% cat main.py
from module_a import *
from module_b import *
greet() # Яка функція greet буде викликана? Python використовуватиме останню імпортовану.
% python main.py
Hello from module B!
Забруднення простору імен (Namespace Pollution): Коли ми використовуємо import *
, ми імпортуємо всі функції, класи, змінні та об'єкти з модуля в поточний простір імен. Це означає, що будь-які функції, змінні чи об'єкти з модуля будуть доступні без префікса модуля.
- Можна ненавмисно перезаписати змінні або функції, які вже були визначені в скрипті.
- Це ускладнює читання та налагодження коду.
# module.py
x = 42
y = 100
def print_x():
print(x)
# main.py
% cat main.py
from module import * # Імпортує x, y та print_x() в глобальний простір імен
print(x) # Без проблем, виводить 42
print_x() # Без проблем, виводить 42
x = 10 # Перезаписує x з модуля в головному просторі імен
print_x() # Проблема, виводить 42 замість 20
print(dir()) # Перевірка атрибутів в поточному просторі імен головного скрипту
print(x) # Виводить 10
% python main.py
42
42
42
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__',
'__loader__', '__name__', '__package__', '__spec__', 'print_x', 'x', 'y']
10
- Важливо, що це присвоєння “x = 10” не впливає на
x
вmodule.py
, який залишиться рівним42
. Зміннаx
вmain.py
тепер затінюєx
зmodule.py
в межахmain.py
. - Однак це переназначення
x
не впливає на функціюprint_x()
, яка вже була імпортована зmodule.py
. - Коли функція
print_x()
визначена вmodule.py
, вона використовує зміннуx
в просторі імен модуля (яка дорівнює42
). - Навіть якщо ім'я
x
затінено вmain.py
, функціяprint_x()
все одно використовуєx
зmodule.py
, а не локальну зміннуx
вmain.py
. - Змінна
x
вmain.py
є окремою змінною і не перезаписуєx
вmodule.py
для функцій, імпортованих зmodule.py
.
Приватні методи та змінні: В Python приватні методи та змінні — це ті, що призначені для використання тільки всередині модуля або класу та часто позначаються за допомогою початкового підкреслення (_
) або подвійного підкреслення (__
) у назві змінної чи методу. Згідно з конвенцією, до них не повинно звертатися безпосередньо ззовні модуля або класу.
Однак Python не суворо контролює приватність (це конвенція, а не особливість мови), і ці змінні або методи все ще доступні. Але зазвичай вони призначені для внутрішнього використання.
- Приватні методи та змінні (ті, що мають початкове підкреслення) не повинні імпортуватися безпосередньо за допомогою
import *
. - Якщо ви використовуєте
import *
, вони не будуть імпортовані, якщо не вказано явно в атрибуті__all__
модуля.
% cat module.py
_priv_x = 100 # Приватна змінна
def _secret(): # Приватна функція
print("This is a secret function.")
pub_y = 10
% cat main.py
from module import _secret
_secret()
from module import * # Імпортує тільки публічні елементи, _x і _secret не імпортуються
print(pub_y)
print(_priv_x) # Викликає помилку NameError: name '_x' is not defined
% python main.py
This is a secret function.
10
Traceback (most recent call last):
File "/Users/arjunpandey/python/scrape/module-story/main.py", line 5, in
print(_priv_x) # Викликає помилку NameError: name '_x' is not defined
^^^^^^^
NameError: name '_priv_x' is not defined
__all__
і контроль імпорту:
Щоб явно контролювати, що імпортується за допомогою import *
, модуль може визначити спеціальний список під назвою __all__
.
В Python використання інструкції import *
— тобто імпортування всього з модуля — загалом не рекомендується.
Проблеми з import *
Можливі конфлікти імен:
% cat module_a.py
def greet():
print("Hello from module A!")
% cat module_b.py
def greet():
print("Hello from module B!")
% cat main.py
from module_a import *
from module_b import *
greet() # Яка функція greet буде викликана? Python використовуватиме останню імпортовану.
% python main.py
Hello from module B!
Забруднення простору імен (Namespace Pollution): Коли ми використовуємо import *
, ми імпортуємо всі функції, класи, змінні та об'єкти з модуля в поточний простір імен. Це означає, що будь-які функції, змінні чи об'єкти з модуля будуть доступні без префікса модуля.
- Можна ненавмисно перезаписати змінні або функції, які вже були визначені в скрипті.
- Це ускладнює читання та налагодження коду.
# module.py
x = 42
y = 100
def print_x():
print(x)
# main.py
% cat main.py
from module import * # Імпортує x, y та print_x() в глобальний простір імен
print(x) # Без проблем, виводить 42
print_x() # Без проблем, виводить 42
x = 10 # Перезаписує x з модуля в головному просторі імен
print_x() # Проблема, виводить 42 замість 20
print(dir()) # Перевірка атрибутів в поточному просторі імен головного скрипту
print(x) # Виводить 10
% python main.py
42
42
42
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__',
'__loader__', '__name__', '__package__', '__spec__', 'print_x', 'x', 'y']
10
- Важливо, що це присвоєння “x = 10” не впливає на
x
вmodule.py
, який залишиться рівним42
. Зміннаx
вmain.py
тепер затінюєx
зmodule.py
в межахmain.py
. - Однак це переназначення
x
не впливає на функціюprint_x()
, яка вже була імпортована зmodule.py
. - Коли функція
print_x()
визначена вmodule.py
, вона використовує зміннуx
в просторі імен модуля (яка дорівнює42
). - Навіть якщо ім'я
x
затінено вmain.py
, функціяprint_x()
все одно використовуєx
зmodule.py
, а не локальну зміннуx
вmain.py
. - Змінна
x
вmain.py
є окремою змінною і не перезаписуєx
вmodule.py
для функцій, імпортованих зmodule.py
.
Приватні методи та змінні: В Python приватні методи та змінні — це ті, що призначені для використання тільки всередині модуля або класу та часто позначаються за допомогою початкового підкреслення (_
) або подвійного підкреслення (__
) у назві змінної чи методу. Згідно з конвенцією, до них не повинно звертатися безпосередньо ззовні модуля або класу.
Однак Python не суворо контролює приватність (це конвенція, а не особливість мови), і ці змінні або методи все ще доступні. Але зазвичай вони призначені для внутрішнього використання.
- Приватні методи та змінні (ті, що мають початкове підкреслення) не повинні імпортуватися безпосередньо за допомогою
import *
. - Якщо ви використовуєте
import *
, вони не будуть імпортовані, якщо не вказано явно в атрибуті__all__
модуля.
% cat module.py
_priv_x = 100 # Приватна змінна
def _secret(): # Приватна функція
print("This is a secret function.")
pub_y = 10
% cat main.py
from module import _secret
_secret()
from module import * # Імпортує тільки публічні елементи, _x і _secret не імпортуються
print(pub_y)
print(_priv_x) # Викликає помилку NameError: name '_x' is not defined
% python main.py
This is a secret function.
10
Traceback (most recent call last):
File "/Users/arjunpandey/python/scrape/module-story/main.py", line 5, in
print(_priv_x) # Викликає помилку NameError: name '_x' is not defined
^^^^^^^
NameError: name '_priv_x' is not defined
__all__
і контроль імпорту:
Щоб явно контролювати, що імпортується за допомогою import *
, модуль може визначити спеціальний список під назвою __all__
.
Цей список містить імена всіх об'єктів, які повинні вважатися публічними і доступними для імпорту, коли використовується from module import *
.
- Якщо в модулі визначено
__all__
, то будуть імпортовані лише імена, зазначені в__all__
, незалежно від того, чи мають вони початкове підкреслення чи ні. - Якщо
__all__
не визначено, імпортуються всі імена, які не починаються з підкреслення (_
).
% cat main.py
from module import * # Імпортуються тільки публічні елементи, _x і _secret виключені
_secret()
print(pub_y) # Викликає помилку NameError: name 'pub_y' is not defined
print(_priv_x)
% cat module.py
__all__ = ['_priv_x','_secret'] # pub_y не включено до списку публічних об'єктів
_priv_x = 100 # Приватна змінна
def _secret(): # Приватна функція
print("This is a secret function.")
pub_y = 10
% python main.py
This is a secret function.
Traceback (most recent call last):
File "/Users/arjunpandey/python/scrape/module-story/main.py", line 3, in
print(pub_y)
^^^^^
NameError: name 'pub_y' is not defined
Бібліотеки Python
Бібліотеки використовуються для розширення функціональності Python без необхідності переписувати звичайні функції з нуля. Бібліотека Python може містити:
- Модулі: Модуль — це окремий файл Python, часто реалізуючий конкретну функціональність або можливість.
- Пакети: Пакет — це каталог, який містить кілька модулів і файл
__init__.py
, щоб вказати, що це пакет. - Підпакети: Пакет може містити інші пакети всередині себе, що веде до ієрархії модулів і пакетів.
Бібліотека Python може бути як один модуль, так і велика колекція модулів та підпакетів.
Модулі стандартної бібліотеки Python
Python постачається з вбудованими модулями, які надають функціональність для взаємодії з операційною системою, роботи з датами та часом, виконання математичних операцій та іншого.
% cat main.py
import math
from datetime import datetime
import os
print(math.sqrt(16)) # Вивід: 4.0
now = datetime.now()
print(now)
print(os.getcwd()) # Отримання поточної робочої директорії
% python main.py
4.0
2024-12-29 10:58:31.594759
/Users/arjunpandey/python/scrape/module-story
Шлях пошуку модулів (sys.path
)
Python шукає модулі в списку директорій.
Цей список містить імена всіх об'єктів, які повинні вважатися публічними і доступними для імпорту, коли використовується from module import *
.
- Якщо в модулі визначено
__all__
, будуть імпортовані лише імена, зазначені в__all__
, незалежно від того, чи мають вони початкове підкреслення чи ні. - Якщо
__all__
не визначено, імпортуються всі імена, які не починаються з підкреслення (_
).
% cat main.py
from module import * # Імпортуються тільки публічні елементи, _x і _secret виключені
_secret()
print(pub_y) # Викликає помилку NameError: name 'pub_y' is not defined
print(_priv_x)
% cat module.py
__all__ = ['_priv_x','_secret'] # pub_y не включено до списку публічних об'єктів
_priv_x = 100 # Приватна змінна
def _secret(): # Приватна функція
print("This is a secret function.")
pub_y = 10
% python main.py
This is a secret function.
Traceback (most recent call last):
File "/Users/arjunpandey/python/scrape/module-story/main.py", line 3, in
print(pub_y)
^^^^^
NameError: name 'pub_y' is not defined
Бібліотека Python
Бібліотеки використовуються для розширення функціональності Python без необхідності переписувати звичайні функції з нуля. Бібліотека Python може містити:
- Модулі: Модуль — це окремий файл Python, який часто реалізує конкретну функціональність або можливість.
- Пакети: Пакет — це каталог, що містить кілька модулів і файл
__init__.py
, щоб вказати, що це пакет. - Підпакети: Пакет може містити інші пакети всередині себе, що створює ієрархію модулів і пакетів.
Бібліотека Python може бути одним модулем або великою колекцією модулів та підпакетів.
Модулі стандартної бібліотеки Python
Python постачається з вбудованими модулями, які надають функціональність для взаємодії з операційною системою, роботи з датами та часом, виконання математичних операцій та інше.
% cat main.py
import math
from datetime import datetime
import os
print(math.sqrt(16)) # Вивід: 4.0
now = datetime.now()
print(now)
print(os.getcwd()) # Отримати поточну робочу директорію
% python main.py
4.0
2024-12-29 10:58:31.594759
/Users/arjunpandey/python/scrape/module-story
Шлях пошуку модулів (sys.path
)
Python шукає модулі в списку директорій.
Цей список зберігається в sys.path
, який ініціалізується при запуску Python.
- Якщо ви імпортуєте модуль, Python шукає його в директоріях, зазначених у
sys.path
. - Ви можете додавати директорії до
sys.path
під час виконання, використовуючиsys.path.append()
:
% cat main.py
import sys
print(sys.path)
sys.path.append('/Users/arjunpandey/python/scrape/')
import func_arg
func_arg.greet("Arjun")
% cat /Users/arjunpandey/python/scrape/func_arg.py
def greet(name):
print(f"Hello, {name}!")
print(f"Printing Name of the module from function greet: {__name__}")
def main():
# Основна логіка програми
user_name = input("Enter your name: ")
greet(user_name)
if __name__ == "__main__":
main()
%
% python main.py
['/Users/arjunpandey/python/scrape/module-story', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python312.zip', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/lib-dynload', '/Users/arjunpandey/python/project-x/lib/python3.12/site-packages']
Hello, Arjun!
Printing Name of the module from function greet: func_arg
Динамічний імпорт
Ми можемо динамічно імпортувати модулі за допомогою модуля importlib
, що корисно, коли ми не знаємо, який модуль потрібно імпортувати під час компіляції.
% cat main.py
import importlib
import os
def load_plugin(plugin_name):
try:
plugin = importlib.import_module(f"plugins.{plugin_name}")
plugin.run() # Припускаємо, що кожен плагін має функцію `run()`
except ModuleNotFoundError:
print(f"Plugin {plugin_name} not found.")
if __name__ == "__main__":
plugin_name = input("Enter the plugin to load (plugin_a/plugin_b): ").strip()
load_plugin(plugin_name)
% cat plugins/plugin_a.py
# plugin_a.py
def run():
print("Plugin A is running!")
% cat plugins/plugin_b.py
# plugin_b.py
def run():
print("Plugin B is running!")
% python main.py
Enter the plugin to load (plugin_a/plugin_b): plugin_a
Plugin A is running!
% python main.py
Enter the plugin to load (plugin_a/plugin_b): plugin_b
Plugin B is running!
Імпорт непотрібних модулів або імпорт усіх модулів
Збільшене використання пам'яті: Python завантажує весь модуль у пам'ять. Якщо ви імпортуєте всі модулі в великому пакеті або імпортуєте модулі, які не використовуєте, ви витрачаєте ресурси пам'яті.
Приклад: import pandas # імпортує всю бібліотеку pandas (дуже велику)
Повільний час запуску: Кожного разу, коли модуль імпортується, Python повинен завантажити його з диска, виконати ініціалізаційний код (включаючи визначення функцій та класів) і зберегти його в пам'яті. Імпорт великої кількості непотрібних модулів може значно уповільнити час запуску вашого застосунку.
Приклад: Якщо нашому скрипту потрібна лише невелика частина цих бібліотек (скажімо, лише os і time), Python все одно має завантажити та ініціалізувати всі інші модулі. Це збільшує час запуску скрипту і може стати помітним у великих застосунках.
import os
import time
import logging
import math
import numpy
import pandas # велика бібліотека
Витрачені ресурси процесора: Деякі бібліотеки виконують код при імпорті (наприклад, налаштовують значення за замовчуванням, ініціалізують внутрішні структури даних). Це може призвести до непотрібного використання процесора. Приклад: numpy
— потужна бібліотека, вона виконує чимало ініціалізаційних процесів під час першого імпорту. Якщо ви не використовуєте numpy
у вашому коді, але все одно імпортуєте його, ви витрачаєте ресурси процесора на його ініціалізацію.
Неекономне використання дискового вводу/виводу
Збільшений ризик циклів імпортів
Великі Docker-образи або віртуальні середовища
Ризик конфліктів чи зіткнень в просторах імен
Пакет Python
Пакет Python — це каталог, який містить кілька модулів Python і може також містити інші підпакети. В Python існують два основних типи пакетів: Namespace Packages та Traditional Packages.
Цей список зберігається в sys.path
, який ініціалізується при запуску Python.
- Якщо ви імпортуєте модуль, Python шукає його в директоріях, зазначених у
sys.path
. - Ви можете додавати директорії до
sys.path
під час виконання, використовуючиsys.path.append()
:
% cat main.py
import sys
print(sys.path)
sys.path.append('/Users/arjunpandey/python/scrape/')
import func_arg
func_arg.greet("Arjun")
% cat /Users/arjunpandey/python/scrape/func_arg.py
def greet(name):
print(f"Hello, {name}!")
print(f"Printing Name of the module from function greet: {__name__}")
def main():
# Основна логіка програми
user_name = input("Enter your name: ")
greet(user_name)
if __name__ == "__main__":
main()
%
% python main.py
['/Users/arjunpandey/python/scrape/module-story', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python312.zip', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12', '/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/lib-dynload', '/Users/arjunpandey/python/project-x/lib/python3.12/site-packages']
Hello, Arjun!
Printing Name of the module from function greet: func_arg
Динамічний імпорт
Ми можемо динамічно імпортувати модулі за допомогою модуля importlib
, що корисно, коли ми не знаємо, який модуль потрібно імпортувати під час компіляції.
% cat main.py
import importlib
import os
def load_plugin(plugin_name):
try:
plugin = importlib.import_module(f"plugins.{plugin_name}")
plugin.run() # Припускаємо, що кожен плагін має функцію `run()`
except ModuleNotFoundError:
print(f"Plugin {plugin_name} not found.")
if __name__ == "__main__":
plugin_name = input("Enter the plugin to load (plugin_a/plugin_b): ").strip()
load_plugin(plugin_name)
% cat plugins/plugin_a.py
# plugin_a.py
def run():
print("Plugin A is running!")
% cat plugins/plugin_b.py
# plugin_b.py
def run():
print("Plugin B is running!")
% python main.py
Enter the plugin to load (plugin_a/plugin_b): plugin_a
Plugin A is running!
% python main.py
Enter the plugin to load (plugin_a/plugin_b): plugin_b
Plugin B is running!
Імпорт непотрібних модулів або імпорт всіх модулів
Збільшене використання пам'яті: Python завантажує весь модуль у пам'ять. Якщо ви імпортуєте всі модулі великого пакету або імпортуєте модулі, які насправді не використовуєте, ви витрачаєте ресурси пам'яті.
Приклад: import pandas # імпортує всю бібліотеку pandas (дуже велику)
Повільний час запуску: Кожного разу, коли модуль імпортується, Python має завантажити його з диска, виконати ініціалізаційний код (включаючи визначення функцій та класів) і зберегти його в пам'яті. Імпортування великої кількості непотрібних модулів може значно уповільнити час запуску вашої програми.
Приклад: Якщо нашому скрипту потрібна лише невелика частина цих бібліотек (наприклад, тільки os і time), Python все одно має завантажити та ініціалізувати всі інші модулі. Це збільшує час, необхідний для запуску скрипту, і може стати помітним у більших програмах.
import os
import time
import logging
import math
import numpy
import pandas # велика бібліотека
Витрачені ресурси процесора: Деякі бібліотеки виконують код при імпорті (наприклад, налаштовують значення за замовчуванням, ініціалізують внутрішні структури даних). Це може призвести до непотрібного використання процесора. Приклад: numpy
— потужна бібліотека, яка виконує чимало ініціалізацій під час першого імпорту. Якщо ви не використовуєте numpy
у вашому коді, але все одно імпортуєте його, ви витрачаєте ресурси процесора на його ініціалізацію.
Неекономне використання дискового вводу/виводу
Збільшений ризик циклічних імпортів
Великі Docker-образи або віртуальні середовища
Ризик конфліктів просторів імен
Пакет Python
Пакет Python — це каталог, що містить кілька модулів Python і може також містити інші підпакети. В Python існують два основних типи пакетів: Namespace Packages та Traditional Packages.
Обидва типи служать для організації модулів Python, але мають різну поведінку та структуру.
Модуль — це один файл, що містить Python код, тоді як пакет — це колекція пов'язаних між собою модулів, організованих у вигляді структури директорій.
Пакет Namespace
У Python пакети namespace дозволяють одному логічному пакету охоплювати кілька директорій на файловій системі. Ця можливість особливо корисна для великих програм або модульних систем, де компоненти одного пакету можуть бути розподілені по різних директоріях, або навіть різних проектах Python.
Пакет namespace — це тип пакету, для якого не потрібен файл __init__.py
. Замість цього Python автоматично об'єднує всі директорії, що належать до одного простору імен. Це особливо корисно для розподілу великих пакетів або систем, заснованих на плагінах. Завдяки пакетам namespace можна розділити пакет на кілька директорій, причому кожна з них може знаходитися в різному місці.
% cat /Users/arjunpandey/python/scrape/random/ext_project/core/db.py
def func():
print("This is function from core.db")
(project-x) arjunpandey@Arjuns-MacBook-Pro app % cat /Users/arjunpandey/python/scrape/pkgstory/ext_project/core/module_a.py
# core/module_a.py
def func():
print("This is function from core.module_a")
(project-x) arjunpandey@Arjuns-MacBook-Pro app % cat /Users/arjunpandey/python/scrape/pkgstory/ext_project/plugin/module_b.py
# plugin/module_b.py
def func():
print("This is function from plugin.module_b")
% cat main.py
import sys
sys.path.append('/Users/arjunpandey/python/scrape/pkgstory/ext_project')
sys.path.append('/Users/arjunpandey/python/scrape/random/ext_project')
# main.py
import core.module_a
import plugin.module_b
import core.db
import lib.lib
core.module_a.func() # Output: This is function from core.module_a
plugin.module_b.func() # Output: This is function from plugin.module_b
core.db.func() # This is function from core.db
lib.lib.func() # This is function from lib.lib
app % cat lib/lib.py
def func():
print("This is function from lib.lib")
% python main.py
This is function from core.module_a
This is function from plugin.module_b
This is function from core.db
This is function from lib.lib
ext-project
: Це каталог і представляє пакет namespace.core
: Це підкаталог в межахext-project
. Він не потребує файлу__init__.py
, оскількиext-project
є пакетом namespace.module_a.py
: Це Python файл (модуль) всередині каталогуcore
. Він містить функції, класи або інший Python код.
Додавання підмодулю
. secret.py
знаходиться в іншій директорії, доданій до sys.path
, переконайтеся, що використовуєте абсолютний імпорт (абсолютний шлях від директорії програми) — lib/secret.py
або з директорії lib: from lib.secret import
або from .secret import *
. Якщо ми використовуємо явний імпорт, нам не потрібно використовувати список __all__
.
# У наведеному коді ми робимо явний/вибірковий імпорт.
# Не потрібно використовувати список __all__.
Обидва служать для організації модулів Python, але мають різну поведінку та структуру.
**Модуль** — це один файл, що містить Python код, тоді як **пакет** — це колекція пов'язаних модулів, організованих у вигляді структури директорій.
## Пакет Namespace
У Python **пакети namespace** дозволяють одному логічному пакету охоплювати кілька директорій на файловій системі. Ця можливість особливо корисна для великих програм або модульних систем, де компоненти одного пакету можуть бути розподілені по різних директоріях або навіть різних проектах Python.
**Пакет namespace** — це тип пакету, для якого не потрібен файл `__init__.py`. Замість цього Python автоматично об'єднує всі директорії, що належать до одного простору імен. Це особливо корисно для розподілу великих пакетів або систем, заснованих на плагінах. Завдяки пакетам namespace можна розділити пакет на кілька директорій, причому кожна з них може знаходитися в різному місці.
% cat /Users/arjunpandey/python/scrape/random/extproject/core/db.py
def func():
print("This is function from core.db")
(project-x) arjunpandey@Arjuns-MacBook-Pro app % cat /Users/arjunpandey/python/scrape/pkgstory/extproject/core/module_a.py
core/module_a.py
def func():
print("This is function from core.module_a")
(project-x) arjunpandey@Arjuns-MacBook-Pro app % cat /Users/arjunpandey/python/scrape/pkgstory/extproject/plugin/moduleb.py
plugin/module_b.py
def func():
print("This is function from plugin.module_b")
% cat main.py
import sys
sys.path.append('/Users/arjunpandey/python/scrape/pkgstory/extproject')
sys.path.append('/Users/arjunpandey/python/scrape/random/extproject')
main.py
import core.modulea
import plugin.moduleb
import core.db
import lib.lib
core.modulea.func() # Output: This is function from core.modulea
plugin.moduleb.func() # Output: This is function from plugin.moduleb
core.db.func() # This is function from core.db
lib.lib.func() # This is function from lib.lib
app % cat lib/lib.py
def func():
print("This is function from lib.lib")
% python main.py
This is function from core.modulea
This is function from plugin.moduleb
This is function from core.db
This is function from lib.lib
```
ext-project
: Це каталог і представляє пакет namespace.core
: Це підкаталог всерединіext-project
. Він не потребує файлу__init__.py
, оскількиext-project
є пакетом namespace.module_a.py
: Це Python файл (модуль) всередині каталогуcore
. Він містить функції, класи або інший Python код.
Додавання підмодуля
. secret.py
знаходиться в іншій директорії, доданій до sys.path
, переконайтеся, що використовуєте абсолютний імпорт (абсолютний шлях від директорії програми) — lib/secret.py
або з директорії lib: from lib.secret import
або from .secret import *
. Якщо ми використовуємо явний імпорт, нам не потрібно використовувати список __all__
.
# У наведеному коді ми робимо явний/вибірковий імпорт.
# Не потрібно використовувати список __all__.
% cat lib/lib.py
from lib.secret import _secret_key, _access_key
def func():
print("This is function from lib.lib")
print(f"Secret and Access* {_secret_key} {_access_key}")
# Ми використовуємо імпорт *, тому нам потрібен список __all__
app % cat lib/secret.py
__all__ = ['_secret_key', '_access_key','info']
info="Entering to DevOps"
_secret_key="AWSYEKIAMOK"
_access_key="SUMECONBETO23498KEY"
app % cat lib/lib.py
from lib.secret import * # або from .secret import *
def func():
print("This is function from lib.lib")
print(f"Secret and Access: {_secret_key} {_access_key}")
% cat main.py
import sys
sys.path.append('/Users/arjunpandey/python/scrape/pkgstory/ext_project')
sys.path.append('/Users/arjunpandey/python/scrape/random/ext_project')
# main.py
import core.module_a
import plugin.module_b
import core.db
import lib.lib
core.module_a.func() # Вивід: This is function from core.module_a
plugin.module_b.func() # Вивід: This is function from plugin.module_b
core.db.func() # This is function from core.db
lib.lib.func() # This is functionn from lib.lib
print(lib.secret.info)
####Оскільки ми вже імпортували модуль secret у lib.py, нам не потрібно імпортувати його знову у main.py
% python main.py
Secret and Access: AWSYEKIAMOK SUMECONBETO23498KEY
This is function from core.module_a
This is function from plugin.module_b
This is function from core.db
This is function from lib.lib
Entering to DevOps
Традиційний пакет
Традиційний пакет у Python відноситься до структури директорії, яка містить колекцію модулів і, можливо, підмодулів. Кожен пакет зазвичай містить файл __init__.py
, що робить директорію дійсним пакетом Python і дозволяє імпортувати його вміст структуровано.
- Каталог пакету: Пакет представляється директорією, що містить один або кілька Python файлів (
.py
). __init__.py
: Цей файл необхідний для позначення директорії як пакету Python. Він виконується під час імпорту пакету або будь-якого з його модулів. Він може бути порожнім або містити ініціалізаційний код.- Модулі: Python файли всередині пакету називаються модулями. Ці модулі можуть містити функції, класи та змінні.
- Підпакети: Пакет може також містити підпакети, які є власними директоріями, що містять файл
__init__.py
.
Я все ще намагаюся зрозуміти, як назвати приклад нижче. Особисто я вважаю його пакетом namespace, але деякі стверджують, що це просто традиційний пакет, в якому я видалив файл __init__.py
. Які твої думки з цього приводу? 🤪
lib
— це пакет верхнього рівня.
db
— це підпакет всередині lib
.
Нам не потрібно використовувати `__init__.py` у наведеному випадку, оскільки це схоже на пакет на основі простору імен.
% cat lib/lib.py
from lib.secret import _secret_key, _access_key
def func():
print("This is function from lib.lib")
print(f"Secret and Access* {_secret_key} {_access_key}")
# Ми використовуємо імпорт *, тому нам потрібен список __all__
app % cat lib/secret.py
__all__ = ['_secret_key', '_access_key','info']
info="Entering to DevOps"
_secret_key="AWSYEKIAMOK"
_access_key="SUMECONBETO23498KEY"
app % cat lib/lib.py
from lib.secret import * # або from .secret import *
def func():
print("This is function from lib.lib")
print(f"Secret and Access: {_secret_key} {_access_key}")
% cat main.py
import sys
sys.path.append('/Users/arjunpandey/python/scrape/pkgstory/ext_project')
sys.path.append('/Users/arjunpandey/python/scrape/random/ext_project')
# main.py
import core.module_a
import plugin.module_b
import core.db
import lib.lib
core.module_a.func() # Вивід: This is function from core.module_a
plugin.module_b.func() # Вивід: This is function from plugin.module_b
core.db.func() # This is function from core.db
lib.lib.func() # This is functionn from lib.lib
print(lib.secret.info)
####Оскільки ми вже імпортували модуль secret у lib.py, нам не потрібно імпортувати його знову у main.py
% python main.py
Secret and Access: AWSYEKIAMOK SUMECONBETO23498KEY
This is function from core.module_a
This is function from plugin.module_b
This is function from core.db
This is function from lib.lib
Entering to DevOps
Традиційний пакет
Традиційний пакет у Python відноситься до структури директорії, яка містить колекцію модулів і, можливо, підмодулів. Кожен пакет зазвичай містить файл __init__.py
, що робить директорію дійсним пакетом Python і дозволяє імпортувати його вміст структуровано.
- Каталог пакету: Пакет представляється директорією, що містить один або кілька Python файлів (
.py
). __init__.py
: Цей файл необхідний для позначення директорії як пакету Python. Він виконується під час імпорту пакету або будь-якого з його модулів. Він може бути порожнім або містити ініціалізаційний код.- Модулі: Python файли всередині пакету називаються модулями. Ці модулі можуть містити функції, класи та змінні.
- Підпакети: Пакет може також містити підпакети, які є власними директоріями, що містять файл
__init__.py
.
Я все ще намагаюся зрозуміти, як назвати приклад нижче. Особисто я вважаю його пакетом namespace, але деякі стверджують, що це просто традиційний пакет, в якому я видалив файл __init__.py
. Які твої думки з цього приводу? 🤪
lib
— це пакет верхнього рівня.
db
— це підпакет всередині lib
.
Нам не потрібно використовувати `__init__.py` у наведеному випадку, оскільки це схоже на пакет на основі простору імен.
lib/
module_a.py # Модуль у пакеті
module_b.py # Інший модуль
db/
db.py # Підпакет у пакеті lib
tradition % cat main.py
import lib.module_a
import lib.module_b
import lib.db.db
lib.module_a.func()
lib.module_a.func()
lib.db.db.func()
% cat lib/*.py
# lib/module_a.py
def func():
print("This is function from lib/module_a")
# lib/module_b.py
def func():
print("This is function from lib/module_b")
% cat lib/db/db.py
def func():
print("This is function from lib/db/db")
tradition % python main.py
This is function from lib/module_a
This is function from lib/module_a
This is function from lib/db/db
Перетворення на Традиційний пакет
Використання вибіркового імпорту: Ми можемо бачити функції окремих модулів.
% cat main.py
import lib
lib.module_a.func()
lib.module_b.func()
lib.db.db.func()
% cat lib/__init__.py
from .module_a import func
from .module_b import func
from .db.db import func
% cat lib/db/__init__.py
from .db import func
(project-x) arjunpandey@Arjuns-MacBook-Pro tradition %
% python main.py
This is function from lib/module_a
This is function from lib/module_b
This is function from lib/db/db
*Використання імпорту **
# За умовчанням викликається остання імпортована функція
% cat main.py
from lib import *
func()
% python main.py
This is function from lib/db/db
---------------------------------------
# Щоб явно викликати функцію іншого модуля, використовуйте наступний формат
% cat main.py
from lib import *
module_b.func() # Останній імпортований модуль має пріоритет, щоб викликати конкретно module_b.func()
func()
% python main.py
This is function from lib/module_b
This is function from lib/db/db
Різниця між Namespace та Звичайними пакетами
Знайшли щось неправильне/неправильно подане в статті? Вибачте!! Будь ласка, допоможіть мені виправити це якомога швидше 🙇♂️
Думки/пропозиції, висловлені в цій та будь-яких попередніх історіях, є виключно моїми і не мають відношення до інших….
lib/
modulea.py # Модуль у пакеті
moduleb.py # Інший модуль
db/
db.py # Підпакет у пакеті lib
tradition % cat main.py
import lib.modulea
import lib.moduleb
import lib.db.db
lib.modulea.func()
lib.modulea.func()
lib.db.db.func()
% cat lib/*.py
lib/module_a.py
def func():
print("This is function from lib/module_a")
lib/module_b.py
def func():
print("This is function from lib/module_b")
% cat lib/db/db.py
def func():
print("This is function from lib/db/db")
tradition % python main.py
This is function from lib/modulea
This is function from lib/modulea
This is function from lib/db/db
```
Перетворення на Традиційний пакет
Використання вибіркового імпорту: Ми можемо бачити функції окремих модулів.
% cat main.py
import lib
lib.module_a.func()
lib.module_b.func()
lib.db.db.func()
% cat lib/__init__.py
from .module_a import func
from .module_b import func
from .db.db import func
% cat lib/db/__init__.py
from .db import func
(project-x) arjunpandey@Arjuns-MacBook-Pro tradition %
% python main.py
This is function from lib/module_a
This is function from lib/module_b
This is function from lib/db/db
*Використання імпорту **
# За умовчанням викликається остання імпортована функція
% cat main.py
from lib import *
func()
% python main.py
This is function from lib/db/db
---------------------------------------
# Щоб явно викликати функцію іншого модуля, використовуйте наступний формат
% cat main.py
from lib import *
module_b.func() # Останній імпортований модуль має пріоритет, щоб викликати конкретно module_b.func()
func()
% python main.py
This is function from lib/module_b
This is function from lib/db/db
Різниця між Namespace та Звичайними пакетами
Знайшли щось неправильне/неправильно подане в статті? Вибачте!! Будь ласка, допоможіть мені виправити це якомога швидше 🙇♂️
Думки/пропозиції, висловлені в цій та будь-яких попередніх історіях, є виключно моїми і не мають відношення до інших….
Перекладено з: Entering into DevOps-37 Python04