pjn-2024-cw/00_czysty_kod.ipynb

199 lines
7.0 KiB
Plaintext
Raw Permalink Normal View History

2024-10-01 11:35:14 +02:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Czysty kod"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Gorąco zachęcam do przeczytania książki: Czysty kod. Podręcznik dobrego programisty"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Co to znaczy \"czysty kod\"?\n",
"\n",
"Czysty kod to taki zapis kodu, który będzie czytelny/przyjazny dla innych osób (lub samego siebie przy powrocie do danego kodu po kilku miesiącach przerwy)\n",
"\n",
"Czysty kod powinien być:\n",
"* poprawnie sformatowany (dla chętnych dokument PEP 8 opisujący formatowanie kodu w Pythonie https://peps.python.org/pep-0008/)\n",
"* samoopisywalny - nazwy zmiennych/funkcji powinny opisywać, co dzieje się w danym fragmencie kodu\n",
"* możliwie krótki i prosty (brak wielokrotnych zagnieżdżeń, wielu różnych wariantów w blokach if-elif-else itp.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**1. Nazwy:**\n",
"\n",
"* **Znaczące i opisowe:** Nazwy zmiennych, funkcji i klas powinny jasno wskazywać ich przeznaczenie (czyli definiować, z czym mamy doczynienia). Krótka nazwa to nie zawsze dobra nazwa! Przykłady:\n",
" * `words` zamiast `w`\n",
" * `number_of_ill_patients` jako liczba chorych pacjentów. Jeśli chcielibyśmy przetrzymywać listę/zbiór chorych pacjentów (obiektów posiadających informacje o pacjentach), wtedy możemy skorzystać ze zmiennej `ill_patients`.\n",
" * `calculate_sum()` zamiast `calc()`\n",
" * nazwy takie jak `x` czy `y` możemy wykorzystywać w takich zastosowaniach jak indeks podczas iterowania pętli\n",
"* **Konwencja:** Używaj `snake_case` dla nazw zmiennych i funkcji (małe litery, podkreślenia). Klasy piszemy w `CamelCase` (duże litery na początku każdego słowa).\n",
"* **Unikaj skrótów:** `unique_elements` zamiast `uni_elem`, wyjątek stanowią skróty, które są jednoznaczne, powszechnie przyjęte i rozumiane przez zdecydowaną większość osób mających styczność z kodem (np. number -> num, dataframe -> df, vocabulary -> vocab, character -> char).\n",
"\n",
"**2. Formatowanie:**\n",
"\n",
"* **Wcięcia:** Używaj 4 spacji na każde wcięcie.\n",
"* **Puste linie:** Oddzielaj bloki kodu pustymi liniami dla lepszej czytelności (funkcje, klasy, oraz fragmenty kodu staniowące pewną logiczną spójność).\n",
"* **Długość linii:** Staraj się, aby linie kodu nie były dłuższe niż 80 znaków.\n",
"\n",
"**3. Funkcje:**\n",
"\n",
"* **Jedno zadanie:** Każda funkcja powinna wykonywać tylko jedno, konkretne zadanie.\n",
"* **Krótkie i zwięzłe:** Funkcje powinny być krótkie i łatwe do zrozumienia (tak samo ich nazwy).\n",
"\n",
"**4. Komentarze:**\n",
"* **Podstawowa zasada:** W komentarzu umieszczaj informacje, których nie da się wyrazić w kodzie, a które są ważne. \n",
"* **Unikaj nadmiaru komentarzy:** Zbyt wiele komentarzy może utrudnić czytanie kodu.\n",
"\n",
"**5. Moduły i pakiety:**\n",
"\n",
"* **Organizacja:** Dziel duży kod na mniejsze moduły i pakiety, aby ułatwić jego zarządzanie.\n",
"* **Import:** Importuj tylko niezbędne moduły.\n",
"\n",
"**Narzędzia:**\n",
"\n",
"* **Linters:** Używaj linterów, takich jak `pylint` lub `flake8`, aby automatycznie sprawdzać styl i jakość kodu.\n",
"* **Formatery:** Używaj formaterów kodu, takich jak `black` lub `autopep8`, aby automatycznie formatować kod zgodnie z ustalonymi konwencjami.\n",
"\n",
"**Pamiętaj:** Celem czystego kodu jest jego zrozumienie i utrzymanie. Inwestycja w czysty kod zaoszczędzi Ci (oraz Twoim współpracownikom) czasu i wysiłku w przyszłości."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Przykład nieczytelnego kodu"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open(\"file1.txt\", \"r\") as f:\n",
" b = f.readlines()\n",
" b = [x.strip() for x in b]\n",
" b = set(b)\n",
"with open(\"file2.txt\", \"r\") as f:\n",
" a = f.readlines()\n",
" a = [x.strip() for x in a]\n",
" a = \" \".join(a)\n",
2024-10-03 09:46:02 +02:00
"\n",
2024-10-01 11:35:14 +02:00
"a = a.split()\n",
"\n",
"aa = []\n",
"for a1 in a:\n",
" aaa = \"\".join([c for c in a1 if c.isalpha()])\n",
" aa.append(aaa)\n",
2024-10-03 09:46:02 +02:00
"\n",
2024-10-01 11:35:14 +02:00
"o = []\n",
"for a2 in aa:\n",
" if a2 not in b:\n",
" o.append(a2)\n",
" \n",
"print(o)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Przykład wyżej po poprawie"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def remove_nonletters_chars(words):\n",
" filtered_words = []\n",
"\n",
" for word in words:\n",
" filtered_word = \"\".join([char for char in word if char.isalpha()])\n",
" filtered_words.append(filtered_word)\n",
" \n",
" return filtered_words\n",
"\n",
"\n",
"def get_out_of_vocab_words(text, vocab):\n",
" words = text.split()\n",
" words = remove_nonletters_chars(words)\n",
2024-10-03 09:46:02 +02:00
" \n",
2024-10-01 11:35:14 +02:00
" out_of_vocab_words = []\n",
" for word in words:\n",
" if word not in vocab:\n",
" out_of_vocab_words.append(word)\n",
" \n",
" return out_of_vocab_words"
]
},
{
"cell_type": "code",
2024-10-01 13:47:49 +02:00
"execution_count": null,
2024-10-01 11:35:14 +02:00
"metadata": {},
2024-10-01 13:47:49 +02:00
"outputs": [],
2024-10-01 11:35:14 +02:00
"source": [
"with open(\"vocabulary.txt\", \"r\") as file:\n",
" vocab = file.readlines()\n",
" vocab = [x.strip() for x in vocab]\n",
" vocab = set(vocab)\n",
"\n",
"with open(\"article.txt\", \"r\") as file:\n",
" article = file.readlines()\n",
" article = [x.strip() for x in article]\n",
" article = \" \".join(article)\n",
"\n",
"out_of_vocab_words = get_out_of_vocab_words(article, vocab)\n",
"print(out_of_vocab_words)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### W powyższym kodzie:\n",
"* zmienne jednoznacznie wskazują \"czym\" są\n",
"* nazwy funkcji opisują co w nich jest wykonywane\n",
"* fragmenty kodu są właściwie oddzielone nowymi liniami\n",
2024-10-03 09:46:02 +02:00
"* kod nie zawiera komentarzy, ponieważ strukturę działania programu dało się wyrazić poprzez nadanie właściwych nazw zmiennym oraz funkcjom"
2024-10-01 11:35:14 +02:00
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
2024-10-03 09:46:02 +02:00
"version": "undefined.undefined.undefined"
2024-10-01 11:35:14 +02:00
}
},
"nbformat": 4,
"nbformat_minor": 2
}