Python: деректен өз есебіңізге дейін 11-сабақ (барлығы 56)
Файлдар мен pathlib: бөтен машинада сынбайтын жол
Python курсының он бірінші сабағы. Бағдарлама деректі жазады, оны жол-жолмен оқиды да, есепті қасына қояды. Жолды жолдарды жабыстыру емес, `Path` құрайды: Windows-та сол жол кері қиғаш сызықпен жазылады. Ал кодтауды әрқашан көрсетеді — онсыз оны сіз емес, жүйе таңдайды.
Не үшін керек
Өткен сабақта FileNotFoundError-ды ұстап, сол жерде тоқтадық. Бүгін файл шындап ашылады — әрі оқуға дейін-ақ мұны екі тәсілмен бұзуға болатыны белгілі болады.
Біріншісі: жол. "data/2026/cpi.csv" деген жол сізде жұмыс істейді, ал бағдарламаны басқа қалтадан немесе басқа жүйеде іске қосқан адамда істемеуі мүмкін.
Екіншісі: кодтау. Дискідегі файл — байттар; оларды мәтінге айналдыратын нәрсе — сол байттарды қалай оқу керегі туралы келісім. Келісімді атамасаңыз, оны сіздің орныңызға операциялық жүйе таңдайды, ал қазақ мәтіні танымайтын таңбалармен келеді.
Бірден тұтас
fail.py файлы. Іске қосу: ортадан python fail.py.
Міндеттісі — алғашқы екі блок: Path, жазу, with пен encoding арқылы оқу. Үшінші блок есепті жазады да, өзінен кейін жинайды; ол бағдарлама жасаған файлды бағдарламаның өзі өшіре білуге тиіс екенін де көрсетеді.
"""11-сабақ: файл — жол, кодтау және ішіндегі туралы келісім.
Жолды жолдарды жабыстырып емес, Path арқылы құрады: бір бағдарлама macOS-та да,
Windows-та да жұмыс істеуге тиіс. Кодтауды әрқашан жазады: онсыз оны жүйе таңдайды.
"""
from pathlib import Path
# Бағдарламаның өзі жатқан қалта. Ағымдағы қалта емес: ол бағдарламаны қайдан
# іске қосқаныңызға тәуелді, әрі салыстырмалы жол сонда сынады.
HERE = Path(__file__).parent
data = HERE / "dannye.csv" # мұндағы / бөлмейді, жолдың бөліктерін қосады
report = HERE / "otchet.txt"
rows = ["2021;8.0", "2022;15,0", "2023;n/a", "2024;8.7"]
data.write_text("\n".join(rows) + "\n", encoding="utf-8")
print("== не жаздық")
print(f"аты: {data.name}")
print(f"нүктесіз: {data.stem}, кеңейтімі: {data.suffix}")
print(f"бар: {data.exists()}, көлемі: {data.stat().st_size} байт")
print()
print("== жол-жолмен оқимыз")
good = []
bad = []
with data.open(encoding="utf-8") as source:
for line in source:
year, _, value = line.strip().partition(";")
try:
good.append((int(year), float(value.replace(",", "."))))
except ValueError:
bad.append(year)
print("талданды: ", good)
print("шықпады: ", bad)
print()
print("== есепті деректің қасына жазамыз")
lines = []
for year, value in good:
lines.append(f"{year}: {value:.1f}%")
report.write_text("\n".join(lines) + "\n", encoding="utf-8")
print(report.read_text(encoding="utf-8"), end="")
# Оқу файлдарын өзімізден кейін жинаймыз.
data.unlink()
report.unlink()
print(f"жиналды, қалған файл: {len(list(HERE.glob('*.csv')))}")
Шығатыны:
== не жаздық
аты: dannye.csv
нүктесіз: dannye, кеңейтімі: .csv
бар: True, көлемі: 37 байт
== жол-жолмен оқимыз
талданды: [(2021, 8.0), (2022, 15.0), (2024, 8.7)]
шықпады: ['2023']
== есепті деректің қасына жазамыз
2021: 8.0%
2022: 15.0%
2024: 8.7%
жиналды, қалған файл: 0
Талдау
Қосатын қиғаш сызық
data = HERE / "dannye.csv"
Path / таңбасының мағынасын өзгертеді: жол мен аттың арасында ол бөлу емес, қосу. Бөлгішті жүйенің өзі қояды, әрі бір ғана жол код әр жерде әртүрлі болады:
Windows: data\2026\cpi.csv
macOS/Linux: data/2026/cpi.csv
Жолдарды жолдармен жабыстырмайтыны да сондықтан. "data" + "/" + "2026" Windows-та data/2026 береді — әдетте істейді, бірақ жол кері қиғаш күтетін жерге түскен күні тоқтайды.
Елестетіп көріңіз. Конверттегі мекенжай. Сіз көше мен үйді жазасыз, жүріп өтетін жолдың картасын салмайсыз: пошта қайда бұрылу керегін өзі біледі.
Бағдарламаның қалтасы, іске қосу қалтасы емес
HERE = Path(__file__).parent
Path("dannye.csv") — ағымдағы қалтаға қатысты жол, ал ағымдағы қалта — бағдарлама жатқан емес, оны іске қосқан қалта. Оны көрші директориядан іске қосыңыз — файл қасында жатса да, табылмайды.
__file__ — бағдарлама файлының өзіне апаратын жол, .parent — оның қалтасы. Қалғанының бәрін содан бастап құрады, сонда бағдарлама оны қайдан шақырғанға тәуелді болуын қояды.
with: файл өзі жабылады
with data.open(encoding="utf-8") as source:
for line in source:
with блоктан шыққанда файлды жабады — бәрі тегіс өткенде де, ішінде қате болғанда да. Өткен сабақта finally керек болмағаны да осы себептен.
Ұмытылған close — зиянсыз ұсақ нәрсе емес: жазылған дерек буферде қалып, дискіге жетпей қалуы мүмкін, ал процестің ашық файл саны шектеулі. with екі сұрақты да жабады.
Осылай ашылған файл жол-жолмен оқылады: for line in source оны жадқа түгел тартпайды. Гигабайттық деректер экспорты үшін бұл — «істейді» мен «істемейдінің» айырмасы; оған генераторлар сабағында ораламыз.
encoding="utf-8" — әшекей емес
Дискіде байттар жатыр. Кодтау — қай байтты қай әріп деп санау керегі туралы келісім. Көрсетпесеңіз, Python жүйенің кодтауын алады, ал ол әртүрлі: macOS пен қазіргі Linux-та бұл UTF-8, Windows-та тарихи түрде олай емес.
Бөтен кодтаудың нәтижесі бәріне таныс: «дерек жоқ» дегеннің орнына дерек жоқ. Одан жаманы — бағдарлама бұл кезде құламайды: ол оқы деп айтылғанды адал оқып тұр.
Python 3.15-тен бастап UTF-8 әдепкі режим болады (PEP 686). encoding="utf-8" деп жазу бәрібір дұрыс: кодыңызды ескілеу нұсқаларда да іске қосады, әрі анық аталған келісім үнсіз әдепкіден жақсы оқылады.
Тұтас оқу мен жазу
data.write_text("\n".join(rows) + "\n", encoding="utf-8")
report.read_text(encoding="utf-8")
Шағын файл үшін open де, цикл де керек емес: write_text пен read_text бәрін бір жолмен істейді. Шекара қарапайым — файл жадқа сыя ма. Жүз жолдық есеп сыяды; гигабайттық деректер экспорты сыймайды, оны жол-жолмен оқиды.
Соңындағы + "\n"-ға назар аударыңыз: мәтіндік файлды жол ауыстырумен аяқтау қабылданған. Онсыз соңғы жол артынан жазылғанмен жабысып қалады.
Path тағы не істей алады
Шығудан: .name — кеңейтімімен қоса аты, .stem — онсыз, .suffix — кеңейтімі, .exists() — файл бар ма, .stat().st_size — байтпен көлемі. Қасында .parent, қалта жасайтын .mkdir(parents=True, exist_ok=True), файлдарды маска бойынша аралайтын .glob("*.csv") және өшіретін .unlink() тұр.
Мұның бәрі — ескі os.path модуліндегі ондаған функцияның орнына бір объект. Бөтен кодтан os.path.join(a, b) кездессе — бұл pathlib-ке дейін жазылған сол нәрсе.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптары — сабақтың соңында.
- Жолды неге жолдарды жабыстырып емес,
Pathарқылы құрады? Path(__file__).parentағымдағы қалтадан немен өзгеше?- Файл UTF-8-пен жазылған болса, оны
encoding-сіз ашсақ не болады?
Жаттығу
Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, жөндеу. Жауаптары — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.
1. Болжаңыз. Бұл бағдарлама не басып шығарады? Байтты санаудың қажеті жоқ — сан неден құралатынын айтыңыз.
from pathlib import Path
HERE = Path(__file__).parent
data = HERE / "dannye.txt"
data.write_text("520\n546\n", encoding="utf-8")
print(data.name, data.suffix, data.stat().st_size)
data.unlink()
2. Бос орынды толтырыңыз. ... орнына бағдарламаның қасындағы dannye.csv файлына апаратын жолды құрыңыз.
from pathlib import Path
HERE = Path(__file__).parent
data = ...
data.write_text("8.0\n", encoding="utf-8")
print(data.exists(), data.name)
data.unlink()
3. Жөндеңіз. Файлды өзі жазса да, бағдарлама әріптердің орнына танымайтын таңбалар шығарады. Келісім бұзылған жолды табыңыз.
from pathlib import Path
HERE = Path(__file__).parent
data = HERE / "dannye.txt"
data.write_text("дерек жоқ\n", encoding="utf-8")
print(data.read_text(encoding="cp1251"))
data.unlink()
Тапсырма
Міндетті. Берілгені:
rows = ["қаңтар;520", "ақпан;546,5", "наурыз;бағасы жоқ", "сәуір;498"]
Жолдарды Path(__file__).parent-тен бастап құрыңыз. Жолдарды encoding="utf-8"-пен ceny.csv файлына жазып, атын және байтпен көлемін басып шығарыңыз. Файлды with арқылы жол-жолмен оқып, әр жолды ; бойынша талдаңыз (сандағы үтір нүкте деп саналады), жарамсыз айларды бөлек жинаңыз. Жарамдылар бойынша есепті екі таңбамен, содан кейін аттап өтілгендердің тізімін басып шығарыңыз, ал соңында екі файлды да өзіңізден кейін жинаңыз.
Күтілетін шығу:
жазылды: ceny.csv, 82 байт
қаңтар: 520.00
ақпан: 546.50
сәуір: 498.00
аттап өтілді: наурыз
жиналды, қасындағы файл: 0
Дайын болғаны: шығу жол-жолмен сәйкес келеді; бірде-бір жол жолдарды жабыстырып құралмаған; әр оқу мен әр жазуда кодтау аталған; жұмыстан кейін бағдарламаның қасында оқу файлдары қалмаған.
Өз деректеріңізде. Өзінің қасында өз сандарыңыз жазылған файл жасайтын (жыл мен мәні нүктелі үтір арқылы), оны with пен encoding="utf-8" арқылы жол-жолмен оқитын, жолдарды талдап, есепті екінші файлға жазатын бағдарлама жазыңыз. Жолдарды Path(__file__).parent-тен бастап құрыңыз.
Мұның бәрі step-4 ішінде жиналған — өзіңіз жазып болғаннан кейін салыстырыңыз.
Қалауыңызша.
- Бағдарламаны басқа қалтадан іске қосып (
python жол/бағдарлама.py), ол өз файлын бәрібір табатынына көз жеткізіңіз. - Оқудан
encoding-ті алып тастап,PYTHONUTF8=0 python …арқылы іске қосыңыз да, не болатынын көріңіз. - Бағдарламаның қасындағы барлық
*.csvфайлдыglobарқылы жинап, көлемдерін басып шығарыңыз.
Жобада бұл қайда тұрады
Шолу дискіні алады. Желіден алынған дерек бағдарламаның қасындағы файлға жатады, есеп екінші файлға жазылады, ал аттап өтілген жолдарды — кеше экранға басылғандарын — енді журналға салуға болады.
Қарыздар. Біз ескі файлдың үстінен жазып отырмыз: бағдарлама жазудың ортасында құласа, бұрынғы деректен ештеңе қалмайды. Нағыз жазу уақытша файлға жүреді де, содан кейін орнына атын ауыстырады — оған шолу кесте бойынша жұмыс істей бастағанда жетеміз.
Жауаптар
Жауаптарды көрсету
Сұрақтарға
- Өйткені жүйелердің жол бөлгіші әртүрлі, ал
Pathкеректісін өзі қояды. Жолдарды жабыстыру автордың өзінде істейтін, оқырманда сынатын жол береді. - Ағымдағы қалта — бағдарламаны іске қосқан қалта; ол әр іске қосуда өзгереді.
Path(__file__).parent— бағдарлама файлының өзі жатқан қалта, әрі ол оны қайдан шақырғанға тәуелді емес. - Python жүйенің кодтауын алады. macOS пен қазіргі Linux-та бұл UTF-8, бәрі сәйкес келеді, ал Windows-та әріптер бұрмаланып келеді — оның үстіне қатесіз, сондықтан мұны тек адам байқайды.
Жаттығуға
dannye.txt .txt 8. Көлем — дискідегі байттар:520\n546\nдегендегі сегіз таңба, әрі олардың әрқайсысы UTF-8-де бір байт алады.
dannye.txt .txt 8
HERE / "dannye.csv".Path-тағы қиғаш сызық бөлмейді, қосады, ал бөлгішті жүйенің өзі қояды.
from pathlib import Path
HERE = Path(__file__).parent
data = HERE / "dannye.csv"
data.write_text("8.0\n", encoding="utf-8")
print(data.exists(), data.name)
data.unlink()
True dannye.csv
- Файл UTF-8-пен жазылған, ал
cp1251деп оқылған: байттар сол, келісім басқа — әрі бағдарлама құламайды, өйткені ол үшін бұлар заңды әріптер. Немен жазса, сонымен оқиды:
from pathlib import Path
HERE = Path(__file__).parent
data = HERE / "dannye.txt"
data.write_text("дерек жоқ\n", encoding="utf-8")
print(data.read_text(encoding="utf-8"))
data.unlink()
дерек жоқ
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.