Commit b720e193 by Patryk Czarnik

przykłady dzien9

parent 0317802f
...@@ -42,3 +42,4 @@ try: ...@@ -42,3 +42,4 @@ try:
print(f'Nie istnieje waluta o kodzie {kod}') print(f'Nie istnieje waluta o kodzie {kod}')
except Exception as e: except Exception as e:
print('Błąd:', e) print('Błąd:', e)
exit(2)
with open('plik.txt', mode='rb') as plik:
bajty = plik.read()
print(type(bajty), 'rozmiar:', len(bajty))
print('Pierwszy bajt:', bajty[0]) # wartość liczbowa
print()
for b in bajty:
print(b, end=', ')
print()
print()
print(bajty)
print()
# zamień na tekst (odkoduj) zgodnie z konkretnym kodowaniem znaków
txt = bajty.decode('UTF-8')
print(txt)
# zgodnie z kodowaniem systemowym
txt = bajty.decode()
print(txt)
WEJSCIE = 'plik.txt'
WYJSCIE = 'kopia.txt'
SIZE = 50
with open(WEJSCIE, mode='rb') as wejscie,\
open(WYJSCIE, mode='wb') as wyjscie:
bajty = wejscie.read(SIZE)
print('porcja rozmiaru', len(bajty))
wyjscie.write(bajty)
print('Gotowe')
WEJSCIE = '/dev/random'
WYJSCIE = 'random.dat'
BUFSIZE = 1024
SIZE = 5000
with open(WEJSCIE, mode='rb') as wejscie,\
open(WYJSCIE, mode='wb') as wyjscie:
pozostalo = SIZE
while pozostalo > 0:
bajty = wejscie.read(min(pozostalo, BUFSIZE))
if not bajty: # koniec pliku przed wczytaniem całego SIZE
break
print('porcja rozmiaru', len(bajty))
pozostalo -= len(bajty)
wyjscie.write(bajty)
print('Gotowe')
# Tutaj argumenty uruchomienia programu podaje się w wierszu poleceń
import sys
# argumentem nr 0 jest nazwa programu
if len(sys.argv) < 3:
print('Nalezy podac wejscie, wyjscie i opcjonalnie ilosc bajtow')
exit(1)
BUFSIZE = 4096
WEJSCIE = sys.argv[1]
WYJSCIE = sys.argv[2]
SIZE = None
if len(sys.argv) >= 4:
SIZE = int(sys.argv[3])
with open(WEJSCIE, mode='rb') as wejscie,\
open(WYJSCIE, mode='wb') as wyjscie:
skopiowano = 0
while not SIZE or skopiowano < SIZE:
ileczytac = min(SIZE - skopiowano, BUFSIZE) if SIZE else BUFSIZE
bajty = wejscie.read(ileczytac)
if not bajty: # koniec pliku przed wczytaniem całego SIZE
break
print('porcja rozmiaru', len(bajty))
skopiowano += len(bajty)
wyjscie.write(bajty)
print(f'Skopiowano {skopiowano} bajtow')
Ala ma kota
Żaneta ma żółwie
Ola ma psa
Ela ma rybki
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include "err.h"
void syserr(const char *fmt, ...)
{
va_list fmt_args;
fprintf(stderr, "ERROR: ");
va_start(fmt_args, fmt);
vfprintf(stderr, fmt, fmt_args);
va_end (fmt_args);
fprintf(stderr," (%d; %s)\n", errno, strerror(errno));
exit(1);
}
void fatal(const char *fmt, ...)
{
va_list fmt_args;
fprintf(stderr, "ERROR: ");
va_start(fmt_args, fmt);
vfprintf(stderr, fmt, fmt_args);
va_end (fmt_args);
fprintf(stderr,"\n");
exit(1);
}
#ifndef _ERR_
#define _ERR_
/* Print system call error message and terminate.
* Uses errno to identify the error type. */
extern void syserr(const char *fmt, ...);
/* Print error message and terminate. */
extern void fatal(const char *fmt, ...);
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "err.h"
#include "towar.h"
/** Do rekordu Towar wpisuje podane wartości. */
void zainicjuj_towar(Towar *towar, const char *nazwa, int cena, int stan) {
strncpy(towar->nazwa, nazwa, DLUGOSC_NAZWY_TOWARU);
towar->cena = cena;
towar->stan = stan;
}
/** Wypisuje towar na konsolę. */
void wypisz_towar(const Towar *towar) {
printf("towar: %s, cena: %d, stan: %d\n", towar->nazwa, towar->cena, towar->stan);
}
void odczytaj_towar(int fd, Towar *towar) {
if(read(fd, towar, sizeof(Towar)) == -1)
syserr("read 1");
}
void zapisz_towar(int fd, const Towar *towar) {
if(write(fd, towar, sizeof(Towar)) == -1)
syserr("write 1");
}
/* Alokuje tablicę towarów i wspisuje wskaźnik do niej pod wskaznik_do_tablicy, a rozmiar pod zmienną rozmiar_tablicy.
* Wywołujący jest odpowiedzialny za zwolnienie tablicy. */
void odczytaj_plik_towary(const char *plik, Towar **wskaznik_do_tablicy, int *rozmiar_tablicy) {
int fd = open(plik, O_RDONLY, 0);
if(fd < 0) {
syserr("open w odczytaj_plik_towary, plik = %s", plik);
}
if(read(fd, rozmiar_tablicy, sizeof(int)) < 0) {
syserr("read rozmiar w odczytaj_plik_towary");
}
Towar *towary = (Towar*)malloc(*rozmiar_tablicy * sizeof(Towar));
if(towary == NULL) {
syserr("malloc w odczytaj_plik_towary, rozmiar = %d", *rozmiar_tablicy);
}
*wskaznik_do_tablicy = towary;
for(int i = 0; i < *rozmiar_tablicy; i++) {
if(read(fd, towary+i, sizeof(Towar)) < 0) {
syserr("read Towar w odczytaj_plik_towary, i = %d", i);
}
}
if(close(fd) == -1) {
syserr("close w odczytaj_plik_towary, fd = %d", fd);
}
}
void zapisz_plik_towary(const char *plik, Towar *towary, int rozmiar_tablicy) {
int fd = open(plik, O_WRONLY | O_CREAT, 0644);
if(fd < 0) {
syserr("open w zapisz_plik_towary, plik = %s", plik);
}
if(write(fd, &rozmiar_tablicy, sizeof(int)) < 0) {
syserr("write rozmiar w zapisz_plik_towary");
}
for(int i = 0; i < rozmiar_tablicy; i++) {
if(write(fd, towary+i, sizeof(Towar)) < 0) {
syserr("write Towar w odczytaj_plik_towary, i = %d", i);
}
}
if(close(fd) == -1) {
syserr("close w zapisz_plik_towary, fd = %d", fd);
}
}
#ifndef _TOWAR_H_
#define _TOWAR_H_
#define DLUGOSC_NAZWY_TOWARU 20
#define PLIK_TOWARY "towary.dat"
typedef struct towar {
char nazwa[DLUGOSC_NAZWY_TOWARU];
int cena;
int stan;
} Towar;
extern void zainicjuj_towar(Towar *towar, const char *nazwa, int cena, int stan);
extern void wypisz_towar(const Towar *towar);
extern void odczytaj_towar(int fd, Towar *towar);
extern void zapisz_towar(int fd, const Towar *towar);
extern void odczytaj_plik_towary(const char *plik, Towar **wskaznik_do_tablicy, int *rozmiar_tablicy);
extern void zapisz_plik_towary(const char *plik, Towar *towary, int rozmiar_tablicy);
#endif
#include <stdio.h>
#include <stdlib.h>
#include "towar.h"
#include "err.h"
int main(int argc, char **argv) {
printf("Startujemy\n");
char* wejscie = argc >= 3 ? argv[1] : "towary.dat";
char* wyjscie = argc >= 3 ? argv[2] : "towary2.dat";
int ile_towarow;
Towar *towary;
odczytaj_plik_towary(wejscie, &towary, &ile_towarow);
printf("Odczytałem %d towarów\n", ile_towarow);
for(int i = 0; i < ile_towarow; i++) {
towary[i].stan += 3;
wypisz_towar(towary+i);
}
printf("Zapisuję...\n");
zapisz_plik_towary(wyjscie, towary, ile_towarow);
free(towary);
printf("Koniec\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include "towar.h"
#include "err.h"
int main(int argc, char **argv) {
printf("Startujemy\n");
char* wejscie = argc >= 2 ? argv[1] : "towary.dat";
int ile_towarow;
Towar *towary;
odczytaj_plik_towary(wejscie, &towary, &ile_towarow);
printf("Odczytałem %d towarów\n", ile_towarow);
for(int i = 0; i < ile_towarow; i++) {
wypisz_towar(towary+i);
}
free(towary);
printf("Koniec\n");
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include "towar.h"
#include "err.h"
void zapisz_towar_parametry(int fd, const char *nazwa, int cena, int stan) {
Towar towar;
zainicjuj_towar(&towar, nazwa, cena, stan);
zapisz_towar(fd, &towar);
}
int main(int argc, char **argv) {
if(argc < 2) {
fatal("Za malo argumentow, podaj nazwę pliku\n");
}
int fd = open(argv[1], O_WRONLY | O_CREAT, 0644);
if(fd == -1)
syserr("open");
int rozmiar = 6;
if(write(fd, &rozmiar, sizeof(int)) == -1)
syserr("write 0");
zapisz_towar_parametry(fd, "Pralka", 1200, 5);
zapisz_towar_parametry(fd, "Odkurzacz", 250, 20);
zapisz_towar_parametry(fd, "Telewizor", 2000,15);
zapisz_towar_parametry(fd, "Kuchenka", 1500, 10);
zapisz_towar_parametry(fd, "Zelazko", 300, 30);
zapisz_towar_parametry(fd, "Czajnik", 219, 10);
close(fd);
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include "towar.h"
#include "err.h"
// Zapisuje do pliku tylko jeden rekord Towar
int main(int argc, char **argv) {
if(argc < 2) {
fatal("Za malo argumentow, podaj nazwę pliku\n");
}
int fd = open(argv[1], O_WRONLY | O_CREAT, 0644);
if(fd == -1)
syserr("open");
Towar towar;
zainicjuj_towar(&towar, "Pralka", 1250, 10);
zapisz_towar(fd, &towar);
close(fd);
}
import struct
# Tutaj cały plik zawiera jeden rekord
with open('towar.dat', mode='rb') as plik:
bajty = plik.read()
print(f'Odczytalem {len(bajty)} bajtów')
print(bajty)
print()
format_rekordu = '20sii'
wynik = struct.unpack(format_rekordu, bajty)
print(wynik)
print(type(wynik))
print(type(wynik[0]), type(wynik[1]))
nazwa = wynik[0].decode('UTF-8')
print(nazwa)
import struct
# W tej wersji plik na początku ma jednego inta - liczba rekordów
# a następnie wiele rekordów.
# Program wczyta cały plik do pamięci, a potem w pętli odczyta rekordy z tablicy bajtów.
format_naglowka = 'i'
format_rekordu = '20sii'
dl_naglowka = struct.calcsize(format_naglowka)
dl_rekordu = struct.calcsize(format_rekordu)
print('Rozmiar nagłówka:', dl_naglowka)
print('Rozmiar rekordu:', dl_rekordu)
with open('towary.dat', mode='rb') as plik:
bajty = plik.read()
# Teraz nie można przekazać całej tablicy do unpack, bo jest za długa
# wynik = struct.unpack(format_naglowka, bajty)
# Można przekazać początkowy fragment
wynik = struct.unpack(format_naglowka, bajty[:4])
print(wynik)
# Lepiej będzie tu jednak użyć unpack_from, który czyta fragment od podanej pozycji
# i działa również wtedy, gdy tablica zawiera dalsze dane
ile, = struct.unpack_from(format_naglowka, bajty, 0)
print(f'W pliku jest {ile} rekordów')
pozycja = dl_naglowka
for i in range(ile):
nazwab, cena, sztuk = struct.unpack_from(format_rekordu, bajty, pozycja)
nazwa = nazwab.decode()
print(f'Towar nr {i}: {nazwa} za {cena}. W magazynie {sztuk} sztuk.')
pozycja += dl_rekordu
import struct
format_naglowka = 'i'
format_rekordu = '20sii'
kodowanie = 'UTF-8'
dl_naglowka = struct.calcsize(format_naglowka)
dl_rekordu = struct.calcsize(format_rekordu)
print('Rozmiar nagłówka:', dl_naglowka)
print('Rozmiar rekordu:', dl_rekordu)
with open('towary.dat', mode='rb') as plik:
(ilosc,) = struct.unpack(format_naglowka, plik.read(dl_naglowka))
print('Liczba rekordów:', ilosc)
for i in range(ilosc):
rekord = struct.unpack(format_rekordu, plik.read(dl_rekordu))
nazwa = rekord[0].decode(kodowanie).strip('\x00')
print(f'Rekord nr {i}: {nazwa} za {rekord[1]}, {rekord[2]} sztuk na magazynie.')
import struct
from collections import namedtuple
format_naglowka = 'i'
format_rekordu = '20sii'
kodowanie = 'UTF-8'
dl_naglowka = struct.calcsize(format_naglowka)
dl_rekordu = struct.calcsize(format_rekordu)
print('Rozmiar nagłówka:', dl_naglowka)
print('Rozmiar rekordu:', dl_rekordu)
Towar = namedtuple('Towar', ['nazwab', 'cena', 'stan'])
towary = []
with open('towary.dat', mode='rb') as plik:
(ilosc,) = struct.unpack(format_naglowka, plik.read(dl_naglowka))
print('Liczba rekordów:', ilosc)
for i in range(ilosc):
towar = Towar(*struct.unpack(format_rekordu, plik.read(dl_rekordu)))
#print(towar)
towary.append(towar)
for towar in towary:
nazwa = towar.nazwab.decode().strip("\x00")
print(f'{nazwa} za {towar.cena}, stan {towar.stan} sztuk')
import struct
from collections import namedtuple
format_naglowka = 'i'
format_rekordu = '20sii'
kodowanie = 'UTF-8'
dl_naglowka = struct.calcsize(format_naglowka)
dl_rekordu = struct.calcsize(format_rekordu)
print('Rozmiar nagłówka:', dl_naglowka)
print('Rozmiar rekordu:', dl_rekordu)
Towar = namedtuple('Towar', ['nazwab', 'cena', 'stan'])
towary = []
with open('towary2.dat', mode='rb') as plik:
(ilosc,) = struct.unpack(format_naglowka, plik.read(dl_naglowka))
print('Liczba rekordów:', ilosc)
for i in range(ilosc):
towar = Towar(*struct.unpack(format_rekordu, plik.read(dl_rekordu)))
#print(towar)
towary.append(towar)
ZMIANA = 100
towary = [towar._replace(cena = towar.cena + ZMIANA) for towar in towary]
with open('towary2.dat', mode='wb') as plik:
plik.write(struct.pack(format_naglowka, len(towary)))
for towar in towary:
print(towar)
plik.write(struct.pack(format_rekordu, *towar))
print('Gotowe')
def rodzynki(przepis):
def zmieniona_funkcja():
przepis()
print('I jeszcze dodaj rodzynki!')
return zmieniona_funkcja
def sernik_klasyczny():
print('Weź zmielony twaróg')
print('Dodaj cukier i aromaty')
print('Oddzielnie przygotuj ciasto')
print('Połóż masę serową na ciasto')
# Tu wywołam orygonalną funkcję - bez rodzynek
print('Normalny przepis:')
sernik_klasyczny()
print()
# Funkcja rodzynki bierze "normalną funkcję" i zwraca nową funkcję (inną wersję),
# która na końcu wypisuje jeszcze tekst o rodzynkach.
zmieniony_przepis = rodzynki(sernik_klasyczny)
print('Zmieniony przepis:')
zmieniony_przepis()
print()
# Właśnie taka funkcja jak "rodzynki", która zmienia inne funkcje, może byc używana jako dekorator.
@rodzynki
def sernik_brzoskwiniowy():
print('Weż masę serową')
print('Dodaj kawałki brzoswkiń')
# Teraz pod nazwą sernik_brzoskwiniowy od razu jest wersja z rodzynkami
print('Brzoskwiniowy:')
sernik_brzoskwiniowy()
# Funkcja poczatek_i_koniec jest "funkcją wyższego rzędu", tzn.
# jako parameter przyjmuje i jako wynik zwraca inną funkcję.
# Operuje na funkcjach, a nie na zwykłych wartościach.
# Funkcja poczatek_i_koniec jako parametr przyjmuje pewną funkcję bezargumentową.
# W wyniku zwraca zmienioną funkcję, która działa tak jak funkcja, ale dodatkowo na początku
# i na końcu swojego działania wypisuje POCZATEK i KONIEC.
def dopisz_poczatek_i_koniec(funkcja):
def zmieniona_funkcja():
print('POCZATEK')
funkcja()
print('KONIEC')
return zmieniona_funkcja
def powitaj():
print('Witamy serdecznie')
def pozdrow():
print('Na zdrowie!')
print('Normalne powitaj:')
powitaj()
print()
zmienione_powitaj = dopisz_poczatek_i_koniec(powitaj)
print('Zmienione powitaj:')
zmienione_powitaj()
print()
zmienione_pozdrow = dopisz_poczatek_i_koniec(pozdrow)
print('Zmienione pozdrów:')
zmienione_pozdrow()
zmienione_pozdrow()
print()
# Można też wywołać zmienioną funkcję bez wpisywania na zmienną:
dopisz_poczatek_i_koniec(powitaj)()
def dopisz_poczatek_i_koniec(funkcja):
def zmieniona_funkcja():
print('POCZATEK')
funkcja()
print('KONIEC')
return zmieniona_funkcja
# Gdy mamy funkcję wyższego rzędu, czyli taką, które bierze funkcję i w wyniku zwraca inną (zmienioną) funkcję,
# to można jej używać jako dekoratora przed definicjami zwykłych funkcji.
@dopisz_poczatek_i_koniec
def powitaj():
print('Witamy serdecznie')
# Dekorator robi coś takiego:
# powitaj = dopisz_poczatek_i_koniec(powitaj)
@dopisz_poczatek_i_koniec
def pozdrow():
print('Na zdrowie!')
# Teraz pod oryginalnymi nazwami powitaj i pozdrów mamy zmienione funkcje.
powitaj()
powitaj()
print()
pozdrow()
# W tej wersji dekorator zadziała tylko dla funkcji jednoargumentowych.
def pomiar_czasu(f):
from datetime import datetime
def wrapper(n):
poczatek = datetime.now()
wynik = f(n)
koniec = datetime.now()
print('czas działania:', koniec - poczatek)
return wynik
return wrapper
@pomiar_czasu
def petla(n):
suma = 0
for i in range(n):
suma += i
return suma
suma = petla(1000)
print(suma)
suma = petla(1000_000)
print(suma)
suma = petla(100_000_000)
print(suma)
def pomiar_czasu(f):
from datetime import datetime
def wrapper(*args, **kwargs):
poczatek = datetime.now()
try:
return f(*args, **kwargs)
finally:
koniec = datetime.now()
print('czas działania:', koniec - poczatek)
return wrapper
@pomiar_czasu
def petla(n):
suma = 0
for i in range(n):
suma += i
return suma
suma = petla(1000)
print(suma)
suma = petla(100_000_000)
print(suma)
def neg(f):
def wrapper(*args, **kwargs):
wynik = f(*args, **kwargs)
return -wynik
return wrapper
@neg
def silnia(n):
iloczyn = 1
for i in range(2, n+1):
iloczyn *= i
return iloczyn
print(silnia(5))
print(silnia(10))
def bold(f):
def wrapper(arg):
napis = f(arg)
return f'<b>{napis}</b>'
return wrapper
# Zmodyfikowana wersja funkcji, którą zwraca dekorator, może być zdefiniowana
# nie tylko konstrukcją def
def italic(f):
return lambda arg: f'<i>{f(arg)}</i>'
@bold
@italic
def foo(arg):
return f'To jest {arg}'
foo('Ala')
print(foo('Ola'))
def bold(f):
def wrapper(*args, **kwargs):
napis = f(*args, **kwargs)
return f'<b>{napis}</b>'
return wrapper
# Zmodyfikowana wersja funkcji, którą zwraca dekorator, może być zdefiniowana
# nie tylko konstrukcją def
def italic(f):
return lambda *args, **kwargs: f'<i>{f(*args, **kwargs)}</i>'
@bold
@italic
def foo(arg):
return f'To jest {arg}'
foo('Ala')
print(foo('Ola'))
@italic
@bold
def zaproszenie(jezyk, miasto, czas):
return f'Zapraszamy na kurs języka {jezyk}, który odbędzie się w {miasto} i będzie trwać {czas} dni.'
print(zaproszenie('Python', 'Warszawa', 20))
print(zaproszenie('SQL', 'Kraków', 8))
# Przykłady od Agaty ;)
import os
from datetime import datetime
from time import sleep
def debug(funkcja):
def wrapper(*args, **kwargs):
print(f'[debug] user:{os.getlogin()} '
f'time:({datetime.now()}) '
f'function:{funkcja.__name__}, '
f'args:{args}, kwargs:{kwargs}' )
wynik= funkcja(*args, **kwargs)
print('czas po wykonaniu funkcji:', datetime.now())
return wynik
return wrapper
def dodaj1000(funkcja_do_wywolania):
def opakowanie(*args,**kwargs):
tmp = funkcja_do_wywolania(*args,**kwargs)
return tmp+1000
return opakowanie
print()
@dodaj1000
@debug
def dodaj(a,b):
return a+b
@dodaj1000
@debug
def pomnoz(a,b=10):
return a*b
@debug
def abc(a, b, c):
print('Tu abc',a, b, c)
sleep(0.5)
print('papa...')
print(dodaj(11,22))
print(pomnoz(3,4))
abc('Ala', 'Basia', 'Celina')
# Podmiana funkcji na zupełnie inną
def haha(*args, **kwargs):
print('hahaha')
# Gdybyśmy chcieli, aby fake mógł być wywołany z dowolnymi parametrami, to:
# def fake(*args, **kwargs):
# print('hahaha')
# Prawdziwej funkcji w ogóle nie uruchamia,
# zamiast niej podstawia fake
def oszukaj(funkcja):
return haha
@oszukaj
def bardzo_wazna_rzecz():
print('To są bardzo poważne sprawy')
print('itd itp')
bardzo_wazna_rzecz() # hahaha
print()
#######
# dekorator blokuje przekazywanie parametru równego 0 - w tym przypadku zgłosi wyjątek
def nie_zero(funkcja):
def wrapper(liczba, *args, **kwargs):
if liczba == 0:
raise ValueError('Liczba nie może być zerem!')
funkcja(liczba, *args, **kwargs)
return wrapper
@nie_zero
def wplata(kwota):
print('Wpłacam wartość ', kwota)
@nie_zero
def wyplata(kwota):
print('Wypłacam wartość ', kwota)
@nie_zero
def wiecej_parametrow(liczba, napis, lista):
for i in range(liczba):
print(napis)
try:
wplata(100)
wyplata(50)
wplata(0)
except Exception as e:
print(e)
def powitaj():
print('Witaj serdecznie!')
def pozegnaj():
print('Do widzenia.')
print('Początek programu')
powitaj()
# Funkcję można wpisać do zmiennej
f = powitaj
# Teraz w zmiennej f mamy funkcję i możemy ją wywołać
f()
f = pozegnaj
f()
print()
# Funkcja może być elementem kolekcji (lista, słownik...)
funkcje = [powitaj, lambda: print('Mówię coś'), pozegnaj]
print(funkcje)
for funkcja in funkcje:
funkcja()
print("=" * 20)
# Teraz funkcje, które biorą dwa argumenty i zwracają wynik, jak działąnia matematyczne.
def dodaj(a, b):
return a+b
def pomnoz(x, y):
return x*y
def liczba_z_cyfr(a, b):
return 10*a + b
arg1 = 5
arg2 = 3
for funkcja in dodaj, pomnoz, liczba_z_cyfr:
wynik = funkcja(arg1, arg2)
print(f'Funkcja {funkcja.__name__} dla argumentów {arg1} i {arg2} dała wynik {wynik}')
# Funkcję w Pythonie można zdefiniować za pomocą def
# Wówczas ta funkcja jest wpisywana do zmienne globalnej o podanej nazwie
def kwadrat(x):
return x**2
def szescian(x):
return x**3
print(globals())
print(kwadrat(5))
print(szescian(5))
# Funkcję można też jednak zdefiniować za pomocą "wyrażenia lambda" (lambda expression)
kw = lambda x: x**2
print(kw(5))
# Wyrażeń lambda używa się najczęściej, gdy funkcję trzeba przekazać jako parametr do innej funkcji
# lub gdy dodajemy funkcje do kolekcji
funkcje = [kwadrat,
szescian,
lambda arg: 10*arg,
lambda x: x - 1
]
liczby = list(range(1, 6))
print(funkcje)
print(liczby)
for liczba in liczby:
print(liczba, end=': ')
for funkcja in funkcje:
# print(funkcja(liczba), end=', ')
print(f'{funkcja(liczba):3}, ', end='')
print()
from datetime import datetime
# Do poniższej funkcji inną funkcję przekazuje się jako argument.
# Przekazana funkcja zostanie wykonana, przy czy zostanie zmierzony czas działania
def zmierz_czas_1(funkcja):
start = datetime.now()
funkcja()
stop = datetime.now()
print(f'Funkcja {funkcja.__name__} wykonała się w czasie {stop - start}')
def petla_10milionowa():
for i in range(10_000_000):
pass
zmierz_czas_1(petla_10milionowa)
print(20*"=")
# Jeśli tak przekazaną funkcję chcemy uruchomić, ale z parametrami:
def zmierz_czas_2(funkcja, *args):
start = datetime.now()
funkcja(*args)
stop = datetime.now()
print(f'Funkcja {funkcja.__name__} z argumentami {args} wykonała się w czasie {stop - start}')
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2)
zmierz_czas_2(fib, 35)
zmierz_czas_2(fib, 36)
print(20*"=")
# Funkcja wykonuje przekazaną funkcję f tyle razy, ile wynosi ileRazy
# Tutaj przekazywane są wszystkie argumenty: pozycyjne *args oraz z nazwami **kwargs
def powtorz(f, ileRazy, *args, **kwargs):
for i in range(ileRazy):
f(*args, **kwargs)
def powitaj():
print('Witamy serdecznie')
powtorz(powitaj, 3)
print()
# następny krok: dodaj do funkcji powtórz takie elementy, aby można byo uruchamiać również funkcje z argumentami
powtorz(print, 5, 'Ala ma kota')
print()
powtorz(print, 4, 'Ala', 'Ela', 'Ola', sep=';')
from random import randint
liczby = [randint(1, 100) for i in range(20)]
print(liczby)
# Aby wypisać tylko liczby spełniające warunek, np. tylko podzielne przez 2,
# można:
for liczba in liczby:
if liczba % 2 == 0:
print(liczba, end=' ')
print()
print('#' * 40)
# Można też uzyskać listę parzystych za pomocą list comprehension ("wyrażenie listotwórcze")
parzyste = [x for x in liczby if x % 2 == 0]
print(parzyste)
# Istnieje też funkcja filter, która zwraca zetaw tych elementów listy (lub innej kolekcji),
# które spełniają podany warunek.
# Warunek podaje się w formie funkcji, która dostaje wartość i zwraca True/False.
# Na takie funkcje mówi się "predykat".
parzyste2 = filter(lambda x: x%2 == 0, liczby)
print(parzyste2)
for p in parzyste2:
print(p, end=', ')
print()
# Wyjaśnie dlaczego dodatkowa pętla:
# filter zwraca w wyniku "generator", czyli obiekt, który zwraca wartości dopiero, gdy jest o to proszony, np. w pętli for
# Można też od razu zrzutować to na listę
print(list(filter(lambda x: x%2 == 0, liczby)))
print()
# Z kolei gdy chcemy zastosować jakąśfunkcję ,np. podnoszenie do kwadratu, dla każdego elementu listy,
# to możemy:
# napisać klasyczną pętlę
for liczba in liczby:
print(liczba**2, end=', ')
print()
# możemy użyć list comprehension
kwadraty = [x**2 for x in liczby]
print(kwadraty)
# albo użyć map
kwadraty2 = map(lambda x: x**2, liczby)
print(kwadraty2)
for k in kwadraty2:
print(k, end=', ')
print()
print(list(map(lambda x: x**2, liczby)))
# połączenie obu technik
for liczba in liczby:
if liczba % 2 == 0:
print(liczba**2, end=' ')
print()
parzyste_kwadraty = [x**2 for x in liczby if x % 2 ==0]
print(parzyste_kwadraty)
pk2 = list(map(lambda x: x**2, filter(lambda x: x % 2 ==0, liczby)))
print(pk2)
# To staje się łądniejsze w zapisie, gdy mamy funkcję, której chcemy użyć
def jest_parzysta(liczba):
return liczba % 2 == 0
def kwadrat(x):
return x**2
pk3 = list(map(kwadrat, filter(jest_parzysta, liczby)))
print(pk3)
print()
miasta = ['Warszawa', 'Kraków', 'Gdańsk']
for m in map(str.upper, miasta):
print(m)
print()
print('Poznań'.upper())
print(str.upper('Łódź')) # Łódź jest parametrem self
dodaj = int.__add__
print(dodaj(13, 43))
x = int(input('Podaj pierwszą liczbę: '))
y = int(input('Podaj drugą liczbę: '))
op = input('Podaj rodzaj operacji: ')
if op == '+':
wynik = x + y
elif op == '-':
wynik = x - y
elif op == '*':
wynik = x * y
elif op == '^':
wynik = x ** y
elif op == '/':
if y == 0:
wynik = 'Dzielenie przez zero!'
else:
wynik = x / y
else:
wynik = 'Nieznana operacja'
print('Wynik:', wynik)
def dodaj(x, y):
return x + y
def odejmij(x, y):
return x - y
dzialania = {
'+': dodaj,
'-': odejmij,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y,
}
x = int(input('Podaj pierwszą liczbę: '))
y = int(input('Podaj drugą liczbę: '))
op = input('Podaj rodzaj operacji: ')
funkcja = dzialania[op]
wynik = funkcja(x, y)
print('Wynik:', wynik)
dzialania = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y,
'^': lambda x, y: x ** y,
}
x = int(input('Podaj pierwszą liczbę: '))
y = int(input('Podaj drugą liczbę: '))
op = input('Podaj rodzaj operacji: ')
if op not in dzialania:
print('Nieznana operacja', op)
else:
wynik = dzialania[op](x, y)
print('Wynik:', wynik)
# Jeśli odwołamy się do modułu operator, można nie pisać wyrażeń lambda, tylko bezpośrednio wskazać istniejące funkcje Pythona
import operator
dzialania = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv,
'^': operator.pow,
}
x = int(input('Podaj pierwszą liczbę: '))
y = int(input('Podaj drugą liczbę: '))
op = input('Podaj rodzaj operacji: ')
if op not in dzialania:
print('Nieznana operacja', op)
else:
wynik = dzialania[op](x, y)
print('Wynik:', wynik)
# Gdy w funkcji zamiast return użyjemy operacji yield, to
# - w wyniku powstaje "generator", który obrazowo działa tak, że
# po zwróceniu wyniku, funkcja działa dalej i może zwrócić kolejne wyniki za pomocą kolejnych yield
def abc():
yield 'Ala'
yield 'Basia'
yield 'Celina'
generator = abc()
print(generator)
# Generator jest iterowalny i najczęściej korzysta z niego porzez pętlę for
for x in generator:
print(x)
print()
def cba():
print('> 0')
yield 'Celina'
print('> 1')
yield 'Basia'
print('> 2')
yield 'Ala'
print('> 3')
print('Starujemy')
for x in cba():
print(x)
print('*')
print('Koniec\n')
# wszystkie wyniki na raz: rzutowanie na listę:
imiona = list(abc())
print(imiona)
print()
# Jak to działa? Generator jest jednocześnie iteratorem, czyli można na nim wywoływać next,
# co daje kolejne elementy zwracane przez yield, aż do StopIteration
g = abc()
print(g.__next__())
# Istnieje globalna funkcja Pythona, która to robi i "ładniej" używać tej funkcji, niż wołać __next__
print(next(g))
print(next(g))
#print(next(g)) #ERR
# Nieskończony generator liczb parzystych
def parzyste():
liczba = 0
while True:
yield liczba
liczba += 2
# Samo wywołanie nie wykonuje tej pętli. Tworzony jest generator.
g = parzyste()
print(g)
# Dopiero umieszczenie w pętli for, albo wielokrotne wywoływanie next, albo konwersja na listę / zbióre / itp.
# spowoduje wykonanie tej pętli i dostarczanie kolejnych wartości.
for x in parzyste():
print(x)
def parzyste(limit):
liczba = 0
while liczba <= limit:
yield liczba
liczba += 2
for x in parzyste(1000):
print(x)
from typing import Generator
def parzyste(limit: int) -> Generator[int, None, None]:
liczba = 0
while liczba < limit:
yield liczba
liczba += 2
for x in parzyste(1000):
print(x)
# Gdy definiujemy funkcję, ale w jej treści zamiast return użyjemy yield,
# to funkcja zwraca w wyniku "generator", czyli obiekt, który dostarcza kolejnej wartości dopiero wtedy, gdy jest o to proszony.
def abc():
yield 'Ala'
yield 'Basia'
print('Jestem w funkcji abc między Basią a Celiną')
yield 'Celina'
print(abc)
generator = abc()
print(generator)
# generator zwróci wartości (które w nim są zwracane za pomocą yield) wtedy, gdy wywołamy funkcję next
pierwszy_wynik = next(generator)
print(pierwszy_wynik)
print('Zaraz zapytam o Basię...')
nastepny_wynik = next(generator)
print(nastepny_wynik)
print('Zaraz zapytam o Celinę...')
nastepny_wynik = next(generator)
print(nastepny_wynik)
# Gdy nie ma już elementów, to wtedy pojawia się wyjątek StopIteration
try:
nastepny_wynik = next(generator)
print(nastepny_wynik)
except StopIteration:
print('To już koniec')
print((40*'-'))
# Najczęściej z generatorów i iteratorów korzysta się tak, że umieszcza się po prawej stronie wyrażenia for
# i wtedy pętla for wykona się dla każdego elementu zwracanego przez ten generator.
for imie in abc():
print('Kolejna osoba to', imie)
print((40*'-'))
# Najczęściej yield umieszcza się w pętli, a nie pisze jeden pod drugim.
# Ten generator wygeneruje określoną liczbę liczb nieparzystych.
def nieparzyste(ile):
x = 1
for i in range(ile):
yield x
x += 2
for n in nieparzyste(10):
print(n, end=', ')
print()
print(sum(nieparzyste(7)))
def nasz_range(start, stop, step=1):
i = start
while i < stop:
yield i
i += step
print(list(nasz_range(100, 150, 5)))
# Jak wiemy, w Pythonie pętla for pozwala przeglądać listy, zbiory, linie z otwartego pliku, elementy range...
# O tym czy dany obiekt może być użyty "po prawej stronie w pętli for" decyduje to, czy ten obiekt jest "iterowalny" (iterable).
# Iterowalne są te obiekty, które posiadają metodę __iter__(), która z kolei zwraca iterator.
# Iterator to jest taki obiekt, na który można wielokrotnie wywoływać metodę __next__()
# a ta metoda zwraca wtedy kolejne elementy, które idą do pętli for.
# W tym przykładzie IteratorParzystych pełni rolę iteratora
# Parzyste to jest klasa iterowalna (tak jak iterowalna jest np. lista)
# W tym przykładzie iterator jest nieskończony.
# Gdy Python uruchamia pętlę for x in ZRODLO: , to postępuje tak:
# wywołuje ZRODLO.__iter__()
# dostaje w wyniku jakiś obiekt it
# i na tym obiekcie wielokrotnie wywołuje it.__next__()
# (aż dojdzie do wyjątku...)
class IteratorParzystych:
def __init__(self):
self.current = 0
def __next__(self):
try:
return self.current
finally:
self.current += 2
class Parzyste:
def __iter__(self):
return IteratorParzystych()
obiekt = Parzyste()
for x in obiekt:
print(x)
class IteratorParzystych:
def __init__(self, start, stop):
self.current = start
self.stop = stop
def __next__(self):
if self.current > self.stop:
# sygnał dla Pythona, że należy zakończyć iterację
raise StopIteration
try:
return self.current
finally:
self.current += 2
class Parzyste:
def __init__(self, limit):
self.limit = limit
def __iter__(self):
return IteratorParzystych(0, self.limit)
obiekt = Parzyste(100)
for x in obiekt:
print(x)
print('koniec pętli\n')
# druga iteracja działa, bo z tego samego obiektu Parzyste ponownie pobierany jest IteratorParzystych
for x in obiekt:
print(x)
print()
print()
obiekt2 = Parzyste(20)
# Technicznie działa to tak, że
# gdy napiszemy for element in obiekt2: ... Python robi tak:
# najpierw pobierany jest iterator
it = obiekt2.__iter__()
print(it)
# a następnie, dopóki nie nastapi wyjątek StopIteration, powtarzane jest pobieranie następnego elementu za pomocą next
try:
while True:
element = it.__next__()
print(element, end=', ')
except StopIteration:
print('\nKoniec\n')
# Jeśli faktycznie chcemy bezpośrednio wykonywać operacje na iteratorach, to "ładniej" jest robić to za pomocą globalnych funkcji Pythona
it = iter(obiekt2)
print(it)
try:
while True:
print(next(it), end='; ')
except StopIteration:
print('\nKoniec\n')
# Ale zdecydowanie częściej używa się pętli for.
# Czasami można uprościć uznając, że ten sam obiekt iterowalny jest jednocześnie swoim iteratorem.
class Parzyste:
def __init__(self, limit = 1000):
self.liczba = -2
self.limit = limit
def __iter__(self):
return self
def __next__(self):
self.liczba += 2
if self.liczba >= self.limit:
# gdy chcemy powiadomić Pythona, że iterator już nie da więcej elementów, że to już koniec
# wtedy wyrzucamy wyjątek StopIteration
raise StopIteration
return self.liczba
def reset(self):
self.liczba = -2
obiekt = Parzyste()
for i in obiekt:
print(i)
print()
obiekt = Parzyste(100)
for i in obiekt:
print(i)
print('----------')
for i in obiekt:
print(i)
# przy tym podejściu obiekt potrafi przeiterować elementy tylko raz. kolejna pętla na tym samym obiekcie nei wykona się ani razu
# tak działają pliki - po otwarciu linie można odczytać tylko raz (chyba, że potem zrobimy seek(0))
# chyba, że wprowadzimy dodatkową metodę resetującą, która ustawia licznik na 0
print('**********')
obiekt.reset()
for i in obiekt:
print(i)
class A:
pass
a = A()
print(a)
# print(a.imie)
# Do obiektu można dodać atrybut, nawet, gdy nie było o nim mowy w treści klasy.
a.imie = 'Ala'
a.wiek = 30
print(a.imie)
aa = A()
# print(aa.imie)
class Osoba:
def __init__(self, imie, nazwisko, wiek):
self.imie = imie
self.nazwisko = nazwisko
self.wiek = wiek
o = Osoba('Jan', 'Kowalski', 40)
o.numer_buta = 44
slownik = o.__dict__
print(slownik)
# slownik jest wciąż powiązany z tym obiektem
# zmiany w obiekcie są widoczne w słowniku są widoczne w obiekcie i viceversa
o.wiek += 1
print(slownik)
slownik['wiek'] += 10
slownik['telefon'] = '321321321'
print(o.wiek)
print(o.telefon)
print()
# Przykład zastosowania: wypisywanie wszystkich pól obiektu jako linii tekstu "a la CSV"
# Nie wiedząc, jakie pola ma obiekt, mogę napisać unowersalną funkcję
def wypisz(obiekt, sep=';'):
print(*obiekt.__dict__.values(), sep=sep)
wypisz(o)
class Klasa:
def __init__(self, a, b, c):
self.a = a
self._b = b # konwencja
self.__c = c # name mangling
k = Klasa('Ala', 'Basia', 'Celina')
print(k.__dict__)
print(k.a)
print(k._b)
# print(k.__c)
print(k._Klasa__c)
k._Klasa__c = 'Cezary'
print(k._Klasa__c)
# My uczyliśmy się tworzenia atrybutów w metodzie init
# Ale w Pythonie można też definiować atrybuty na poziomie klasy, jka np. w C++ czy Javie.
# Ale to działa dziwnie...
class Osoba:
imie = 'IMIĘ'
nazwisko = 'NAZWISKO'
def __str__(self):
return f'{self.imie} {self.nazwisko}'
class Student(Osoba):
# ta lista będzie współdzielona przez wszystkie obiekty
# analogia: zmienne statyczne w Javie czy C#
oceny = []
def dodaj_ocene(self, ocena):
# dwie pierwsze wersje dają efekt "wspólnej listy dla wszystkich studentów"
self.oceny.append(ocena)
# self.oceny += [ocena]
# trzecia wersja działa poprawnie, ale to mało wydajne...
# self.oceny = self.oceny + [ocena]
def srednia(self):
return sum(self.oceny) / len(self.oceny)
def __str__(self):
return super().__str__() + f' z ocenami {self.oceny}'
o = Osoba()
print(o.imie)
print(o)
print('etap1, atrybuty obiektu:', o.__dict__)
print('atrybuty klasy:', Osoba.__dict__)
o.imie = 'Jan'
o.nazwisko = 'Kowalski'
print(o.imie)
print(o)
print('etap2, atrybuty obiektu:', o.__dict__)
print('atrybuty klasy:', Osoba.__dict__)
print()
a = Student()
print(a)
a.imie = 'Adam'
a.nazwisko = 'Abacki'
print(a)
print()
b = Student()
print(b)
b.imie = 'Bartek'
b.nazwisko = 'Babecki'
print(b)
print()
print(a)
print(b)
# Do tej pory to działało dobrze
a.dodaj_ocene(5)
a.dodaj_ocene(5)
a.oceny.append(5)
print(a, a.srednia())
print()
b.dodaj_ocene(3)
print(a, a.srednia())
print('Oceny Adama:', a.oceny)
print('Oceny Bartka:', b.oceny)
# Morał: to jest TA SAMA lista
# Atrybut oceny jest tworzony w klasie!!!
# Różne obiekty mają do niego dostęp, ale to jest ten sam obiekt
# Ze stringami nie ma problemu, bo stringi sa "niemutowalne" i w obiektach możemy wpisac inne stringi - ale to będą nowe obiekty
# Ale lista jest "mutowalna" i obiekty mogą modyfikować wspólny obiekt - wspólną listą.
class Klasa:
# W Pythonie, podobnie jak w C++ czy Javie, można deklarować atrybuty w ciele klasy (a nie w init).
# Jednak w Pythonie działa to w sposób specyficzny, nieoczywisty.
# Te zmienne są przechowywane w klasie, a nie w obiekcie, a obiekty mają do nich dostęp.
# Jednak zapisanie atrybutu o tej samej nazwie w obiekcie (poprzez self) przesłania definicję z poziomu klasy.
x = 100
s = 'Ala ma kota'
lista = []
def __init__(self, y):
self.y = y
def __str__(self):
return f'x = {self.x} , y = {self.y}, s = {self.s}, lista: {self.lista}'
def dodajZwierze(self, zwierze):
self.s += f' oraz {zwierze}'
a = Klasa(1)
print('a:', a)
b = Klasa(2)
print('b:', b)
print()
print("x z różnych perspektyw:")
print(a.x)
print(b.x)
print(Klasa.x)
print()
# Tutaj operacja jest wykonywana na zmiennej klasy
# Obiekty - jeśli nie "przesłoniły" tej zmiennej, to widzą tę zmianę.
# x jest atrybutem klasowym, do którego dostęp jest możliwy także poprzez obiekty
Klasa.x += 3
print(a.x)
print(b.x)
print(Klasa.x)
print('a.__dict__:', a.__dict__)
print('Klasa.__dict__:', Klasa.__dict__)
print()
# Teraz obiekt a tworzy własny atrybut, który przesłoni dostep do x klasowego
# a.x += 5 jest traktowane jako a.x = a.x + 5 w tym przypadku a.x = Klasa.x + 5
a.x += 5
print(a.x)
print(b.x)
print(Klasa.x)
# od tej pory a ma swojego własnego x
# natomiast b.x oznacza odwołanie do Klasa.x
print('a.__dict__:', a.__dict__)
print('Klasa.__dict__:', Klasa.__dict__)
print()
Klasa.x += 1
print(a.x)
print(b.x)
print(Klasa.x)
print()
print(a.lista)
print(b.lista)
# operacja modyfikująca listę modyfikuje listę przechowywaną w klasie , zmiany będą widoczne dla wszystkich obiektów klasy
a.lista.append('Ala')
b.lista.append('Ola')
Klasa.lista.append('Ela')
print(a.lista)
print(b.lista)
print(Klasa.lista)
print()
print(a)
print(b)
print()
Klasa.s = 'Ola ma psa'
# a i b widzą tę zmianę
print(a)
print(b)
b.dodajZwierze('rybki')
# od teraz b używa swojej kopii napisu s
print(a)
print(b)
Klasa.s = 'Ela ma królika'
# Tylko a widzi zmianę, b już nie, bo używa swojej kopii napisu
print(a)
print(b)
# Przedefiniowując metodę setattr możemy zmienić zachowanie Pythona
# w zakresie ustawiana atrybutów.
# Możemy np. zabronić ustawiania niektórych atrybutów, albo stworzyć klasę niemutowalną.
class C:
def __init__(self, imie, nazwisko):
self.imie = imie
self.nazwisko = nazwisko
def __str__(self):
return f'Osoba {self.imie} {self.nazwisko}'
def __setattr__(self, key, value):
print(f'Próba ustawienia atrybutu {key} na wartość {value}')
if key in ['imie', 'nazwisko']:
print('OK, atrybut dopuszczalny')
super().__setattr__(key, value)
else:
print('Niepoprawny atrybut')
raise AttributeError(f'nie wolno ustawiać atrybutu {key}')
c = C('Ala', 'Kowalska')
c.imie = 'Alicja'
print('Udało się ustawić imię', c.imie)
try:
c.zwierze = 'kot'
print('Udało się ustawić zwierze', c.zwierze)
except AttributeError as e:
print(f'Nie udało się. Wyjątek typu {type(e)} o treści {e}')
print('Koniec')
class C:
def __init__(self, imie, nazwisko):
self.imie = imie
self.nazwisko = nazwisko
self._freezed = True
def __str__(self):
return f'Osoba {self.imie} {self.nazwisko}'
def __setattr__(self, key, value):
if hasattr(self, '_freezed') and self._freezed:
raise AttributeError(f'nie wolno już zmieniać obiektu')
super().__setattr__(key, value)
c = C('Ala', 'Kowalska')
print('Jest obiekt:', c)
try:
c.imie = 'Alicja'
print('Udało się ustawić normalnie imię', c.imie)
except Exception as e:
print('Nie udało się ustawić imienia normalnie')
# da się to objeść wbudowanym słownikiem
try:
c.__dict__['imie'] = 'Alicja'
print('Udało się ustawić słownikiem imię', c.imie)
except Exception as e:
print('Nie udało się ustawić imienia słownikiem')
print(c)
\ No newline at end of file
class C:
def __init__(self, imie, nazwisko):
self.imie = imie
self.nazwisko = nazwisko
self._freezed = True
def __str__(self):
return f'Osoba {self.imie} {self.nazwisko}'
def __setattr__(self, key, value):
if hasattr(self, '_freezed') and self._freezed:
raise AttributeError(f'nie wolno już zmieniać obiektu')
super().__setattr__(key, value)
def __getattribute__(self, item):
print('próba odczytu', item)
if item == '__dict__':
raise AttributeError('nie wolno ruszać dict!')
return super().__getattribute__(item)
c = C('Ala', 'Kowalska')
print('Jest obiekt:', c)
try:
c.imie = 'Alicja'
print('Udało się ustawić normalnie imię', c.imie)
except Exception as e:
print('Nie udało się ustawić imienia normalnie')
# teraz nie da się słownikiem
try:
c.__dict__['imie'] = 'Alicja'
print('Udało się ustawić słownikiem imię', c.imie)
except Exception as e:
print('Nie udało się ustawić imienia słownikiem')
print(c)
# ale pewnie da się obejść inaczej -> temat "introspekcja"
class Osoba:
def __init__(self, imie, nazwisko, wiek):
self.imie = imie
self.nazwisko = nazwisko
self.wiek = wiek
def przedstaw_sie(self):
print(f'Jestem Osobą. Nazywam się {self.imie} {self.nazwisko} i mam {self.wiek} lat.')
def pelnoletnia(self):
return self.wiek >= 18
def __str__(self):
return f'{self.imie} {self.nazwisko} ({self.wiek} lat)'
def __repr__(self):
return f'Osoba({repr(self.imie)}, {repr(self.nazwisko)}, {repr(self.wiek)})'
class BrakSrodkow(Exception):
def __init__(self, numer, kwota, saldo):
super().__init__(f'Brak środków na koncie nr {numer}. Próbowano wypłacić {kwota}, a na koncie jest {saldo}')
self.numer = numer
self.kwota = kwota
self.saldo = saldo
class Konto:
def __init__(self, numer, wlasciciel, saldo=0):
if saldo < 0:
raise ValueError('ujemne saldo')
self._numer = numer
self._wlasciciel = wlasciciel
self._saldo = saldo
def __str__(self):
return f'Konto nr {self._numer}, saldo = {self._saldo}, wł. {self._wlasciciel}'
def wplata(self, kwota):
if kwota <= 0:
raise ValueError('niedodatnia kwota we wplata')
self._saldo += kwota
def wyplata(self, kwota):
if kwota <= 0:
raise ValueError('niedodatnia kwota w wyplata')
if kwota > self._saldo:
raise BrakSrodkow(self._numer, kwota, self._saldo)
self._saldo -= kwota
def proba(lista, napis, liczba):
lista += ['Ola', 'Ela']
napis += ' ma kota'
liczba += 33
print('na koniec funkcji:\n', lista, napis, liczba, '\n')
def main():
lista = ['Ala', 'Ula']
napis = 'Ala'
liczba = 1000
print('na początku:\n', lista, napis, liczba, '\n')
proba(lista, napis, liczba)
print('na końcu:\n', lista, napis, liczba)
# Tylko efekt zmiany listy jest widoczny, a str i int nie
# str, int - to są klasy NIEMUTOWALNE (immutable)
# obiekty tych klas nie mogą zmieniać swojego wewnątrznego stanu
# a operacje takie jak +, replace zwracają w wyniku nowy obiekt
# += dla napisów do zmiennej wpisuje adres nowego obiektu
main()
from klasy import *
a = Konto(1, 'Ala', 1000)
b = Konto(2, 'Ola', 2000)
c = b
print('a:', a)
print('b:', b)
print('c:', c)
print()
b.wplata(48)
print('a:', a)
print('b:', b)
print('c:', c)
print()
b = a
print('a:', a)
print('b:', b)
print('c:', c)
print()
# Tracimy referencję do konta nr 2
c = b
print('a:', a)
print('b:', b)
print('c:', c)
print()
# Aby ostatecznie stracić referencję do obiektu, można też do zmiennej przypisać None
a = b = None
# W Pythonie można też jawnie usunąć zmienną
del c
# To usuwa zmienną, a nie obiekt. Obiekt na normalnych zasadach MOŻE być postprzątany przez garbage collecotra.
# Teraz odwołanie do zmiennej c kończy się błedem
print('a:', a)
print('b:', b)
#ERR print('c:', c)
from klasy import *
def funkcja(a, b, c, x):
print('Początek funkcji:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
x += 55
# modyfikujemy obiekt wewnątrz, zmieniamy jego stan, atrybut saldo
b.wplata(44)
# do zmiennej lokalnej wpisujemy referencję do innego obiektu
# tę zmianę widzi tylko funkcja, a main nie widzi
a = Konto(a._numer, a._wlasciciel, a._saldo)
a.wplata(24)
a._wlasciciel.imie = 'Alicja'
print('Koniec funkcji:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
def main():
ala = Osoba('Ala', 'Kowalska', 20)
ola = Osoba('Ola', 'Malinowska', 30)
a = Konto(1, ala, 1000)
b = Konto(2, ola, 2000)
c = b
x = 5000
print('Początek main:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
funkcja(a, b, c, x)
print('Koniec main:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
if __name__ == '__main__':
main()
from klasy import *
def funkcja(a, b, c, x):
print('Początek funkcji:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
x += 55
# modyfikujemy obiekt wewnątrz, zmieniamy jego stan, atrybut saldo
b.wplata(44)
# do zmiennej lokalnej wpisujemy referencję do innego obiektu
# tę zmianę widzi tylko funkcja, a main nie widzi
a = b
print('Koniec funkcji:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
def main():
ala = Osoba('Ala', 'Kowalska', 20)
ola = Osoba('Ola', 'Malinowska', 30)
a = Konto(1, ala, 1000)
b = Konto(2, ola, 2000)
c = b
x = 5000
print('Początek main:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
funkcja(a, b, c, x)
print('Koniec main:')
print('a:', a)
print('b:', b)
print('c:', c)
print('x:', x)
print()
if __name__ == '__main__':
main()
import random
def dopisz_i_wypisz(n, lista=[]):
# do przekazanej listy dopisuje losową wartość i wypisuje całą listę
# domyślnie lista jest pusta
# przy takim zapisie wszystkie ywołania funkcji, w któyrch nie podaje się drugiego arguemntu, będą korzystać z tego samego obiektu lista
for i in range(n):
lista.append(random.randint(1, 100))
print(lista)
dopisz_i_wypisz(1, [5, 10, 15])
dopisz_i_wypisz(3, [11, 12, 13, 14, 15])
dopisz_i_wypisz(5)
dopisz_i_wypisz(2)
dopisz_i_wypisz(1, [100, 200])
dopisz_i_wypisz(3)
print(30 * '=')
# rozwiązanie poprawne, aby za każdym razem powstała pusta lista:
def dopisz_i_wypisz2(n, lista=None):
# do przekazanej listy dopisuje losową wartość i wypisuje całą listę
# domyślnie lista jest pusta
if lista is None:
lista = []
for i in range(n):
lista.append(random.randint(1, 100))
print(lista)
dopisz_i_wypisz2(5)
dopisz_i_wypisz2(2)
dopisz_i_wypisz2(1, [100, 200])
dopisz_i_wypisz2(3)
\ No newline at end of file
class Student:
def __init__(self, imie, nazwisko, oceny=[]):
self.imie = imie
self.nazwisko = nazwisko
self.oceny = oceny
def dodaj_ocene(self, ocena):
self.oceny.append(ocena)
def srednia_ocen(self):
return sum(self.oceny) / len(self.oceny)
adam = Student('Adam', 'Abacki', [3,4,5])
print('adam:', adam.srednia_ocen())
basia = Student('Barbara', 'Rabarbar')
basia.dodaj_ocene(5)
basia.dodaj_ocene(5)
print('basia:', basia.srednia_ocen())
# Podczas tworzenia obiektu cezary zostaje użyta ta ama lista (ten sam obiekt),
# która została już użyta dla obiektu basia
cezary = Student('Cezary', 'Inny')
cezary.dodaj_ocene(2)
cezary.dodaj_ocene(3)
cezary.dodaj_ocene(2)
print('cezary:', cezary.srednia_ocen())
print('basia:', basia.srednia_ocen())
print()
print('oceny adama:', adam.oceny)
print('oceny basi:', basia.oceny)
print('oceny cezarego:', cezary.oceny)
l = [3,3,3]
dorota = Student('Dorota', 'X', l)
print('dorota:', dorota.srednia_ocen())
l.append(5)
print('dorota:', dorota.srednia_ocen())
dorota.dodaj_ocene(4)
print('dorota:', dorota.srednia_ocen())
print('l:', l)
# Wersja poprawiona - wewnątrz init tworzona jest zawsze nowa lista, być może wypełniona początkowymi elementami.
class Student:
def __init__(self, imie, nazwisko, oceny=()):
self.imie = imie
self.nazwisko = nazwisko
self.oceny = list(oceny)
def init_inna_wersja(self, imie, nazwisko, oceny=None):
self.imie = imie
self.nazwisko = nazwisko
if oceny:
self.oceny = list(oceny)
else:
self.oceny = []
def dodaj_ocene(self, ocena):
self.oceny.append(ocena)
def srednia_ocen(self):
return sum(self.oceny) / len(self.oceny)
adam = Student('Adam', 'Abacki', [3,4,5])
print('adam:', adam.srednia_ocen())
basia = Student('Barbara', 'Rabarbar')
basia.dodaj_ocene(5)
basia.dodaj_ocene(5)
print('basia:', basia.srednia_ocen())
cezary = Student('Cezary', 'Inny')
cezary.dodaj_ocene(2)
cezary.dodaj_ocene(3)
cezary.dodaj_ocene(2)
print('cezary:', cezary.srednia_ocen())
print('basia:', basia.srednia_ocen())
print()
print('oceny adama:', adam.oceny)
print('oceny basi:', basia.oceny)
print('oceny cezarego:', cezary.oceny)
l = [3,3,3]
dorota = Student('Dorota', 'X', l)
print('dorota:', dorota.srednia_ocen())
l.append(5)
print('dorota:', dorota.srednia_ocen())
dorota.dodaj_ocene(4)
print('dorota:', dorota.srednia_ocen())
print('l:', l)
import tkinter
root = tkinter.Tk()
root.title('Rozmowa')
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Jak masz na imię?', fg='black', font=('Arial', 24, 'bold'))
label1.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), bg='white')
poleTekstowe.pack()
def akcja():
imie = poleTekstowe.get()
label2.configure(text=f'Witaj {imie}!')
button1 = tkinter.Button(master=root, text='OK', font=('Arial', 24, 'bold'), command=akcja)
button1.pack()
label2 = tkinter.Label(master=root, text='', fg='blue', font=('Arial', 24, 'bold'))
label2.pack()
root.mainloop()
# odczytanie aktualnej wartości pola: poleTekstowe.get()
# ustawienie nowej wartości w label-u : label2.configure(text='nowy tekst')
import tkinter
# w tej wersji program podzieliłem na funkcje, a wspólne zmienne zadeklarowałem jako global
def main():
global poleTekstowe, label2
root = tkinter.Tk()
root.title('Rozmowa')
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Jak masz na imię?', fg='black', font=('Arial', 24, 'bold'))
label1.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), bg='white')
poleTekstowe.pack()
button1 = tkinter.Button(master=root, text='OK', font=('Arial', 24, 'bold'), command=akcja)
button1.pack()
label2 = tkinter.Label(master=root, text='', fg='blue', font=('Arial', 24, 'bold'))
label2.pack()
root.mainloop()
def akcja():
global poleTekstowe, label2
imie = poleTekstowe.get()
label2.configure(text=f'Witaj {imie}!')
if __name__ == '__main__':
main()
import tkinter
# w tej wersji oprócz kliknięcia guzika obsłużymy także naciśnięcie enter gdy jesteśmy w polu tekstowym
def main():
global poleTekstowe, label2
root = tkinter.Tk()
root.title('Rozmowa')
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Jak masz na imię?', fg='black', font=('Arial', 24, 'bold'))
label1.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), bg='white')
poleTekstowe.pack()
button1 = tkinter.Button(master=root, text='OK', font=('Arial', 24, 'bold'))
button1.pack()
label2 = tkinter.Label(master=root, text='', fg='blue', font=('Arial', 24, 'bold'))
label2.pack()
# ustawiam obsługę zdarzenia "kliknięcie guzika"
button1.configure(command=akcja_guzikowa)
# aby dodać obsługę zdarzenia dla pola tekstowego, trzeba zastosować ogólną technikę "bind"
poleTekstowe.bind('<Return>', akcja_returnowa)
root.mainloop()
# akcja ustawiania jako command nie powinna przyjmować żadnych parametrów
def akcja_guzikowa():
global poleTekstowe, label2
imie = poleTekstowe.get()
label2.configure(text=f'Witaj {imie}!', fg='blue')
# akcja ustawiana za pomocą bind przyjmuje jeden parametr "event" - szczegóły zdarzenia
def akcja_returnowa(event):
global poleTekstowe, label2
imie = poleTekstowe.get()
label2.configure(text=f'Witaj {imie}!', fg='red')
if __name__ == '__main__':
main()
import tkinter
# w tej wersji oprócz kliknięcia guzika obsłużymy także naciśnięcie enter gdy jesteśmy w polu tekstowym
def main():
global poleTekstowe, label2
root = tkinter.Tk()
root.title('Rozmowa')
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Jak masz na imię?', fg='black', font=('Arial', 24, 'bold'))
label1.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), bg='white')
poleTekstowe.pack()
button1 = tkinter.Button(master=root, text='OK', font=('Arial', 24, 'bold'))
button1.pack()
label2 = tkinter.Label(master=root, text='', fg='blue', font=('Arial', 24, 'bold'))
label2.pack()
# ustawiam obsługę zdarzenia "kliknięcie guzika"
button1.configure(command=akcja)
# aby dodać obsługę zdarzenia dla pola tekstowego, trzeba zastosować ogólną technikę "bind"
poleTekstowe.bind('<Return>', akcja)
root.mainloop()
# można zdefiniować tylko jedną funkcję z domyślnym parametrem - ona będzie działać w obu przypadkach
def akcja(event=None):
global poleTekstowe, label2
imie = poleTekstowe.get()
label2.configure(text=f'Witaj {imie}!')
if __name__ == '__main__':
main()
import tkinter
# w tej wersji oprócz kliknięcia guzika obsłużymy także naciśnięcie enter gdy jesteśmy w polu tekstowym
def main():
global poleTekstowe, label2
root = tkinter.Tk()
root.title('Rozmowa')
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Jak masz na imię?', fg='black', font=('Arial', 24, 'bold'))
label1.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), bg='white')
poleTekstowe.pack()
button1 = tkinter.Button(master=root, text='OK', font=('Arial', 24, 'bold'))
button1.pack()
label2 = tkinter.Label(master=root, text='', fg='blue', font=('Arial', 24, 'bold'))
label2.pack()
# ustawiam obsługę zdarzenia "kliknięcie guzika"
button1.configure(command=lambda: label2.configure(text=f'Witaj {poleTekstowe.get()}!'))
# aby dodać obsługę zdarzenia dla pola tekstowego, trzeba zastosować ogólną technikę "bind"
poleTekstowe.bind('<Return>', lambda event: label2.configure(text=f'Witaj {poleTekstowe.get()}!'))
root.mainloop()
if __name__ == '__main__':
main()
import tkinter
# Ta wersja funkcji akcja jest uniwersalna: może zostać wywołana bez paramtru (jak robi button)
# oraz z parametrem (jak robi bind)
def akcja(event = None):
global poleTekstowe, label2
imie = poleTekstowe.get()
if imie.strip():
label2.configure(text=f'Witaj {imie}')
else:
label2.configure(text='')
def main():
global poleTekstowe, label2
root = tkinter.Tk()
root.title('Rozmowa')
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Jak masz na imię?', fg='black', font=('Arial', 24, 'bold'))
label1.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), bg='white')
poleTekstowe.pack()
button1 = tkinter.Button(master=root, text="OK", font=('Arial', 24, 'bold'), command=akcja)
button1.pack()
poleTekstowe.bind('<Return>', akcja)
label2 = tkinter.Label(master=root, text='', fg='blue', font=('Arial', 24, 'bold'))
label2.pack()
root.mainloop()
if __name__ == '__main__':
main()
import tkinter
root = tkinter.Tk()
root.mainloop()
# tkinter jest Pythonową nakładką na technologię TK (TCL-TK)
# tkinter jest częścią biblioteki standardowej Pythona
# Oprócz tego w Pythonie dostępne (po doinstalowaniu!) są także biblioteki
# pygtk - nakładka na technologię GTK (GTK to m.in. system okienkowy Gnome (Ubuntu), program Gimp...)
# pyqt - nakładka na QT (QT to m.in. system okienkowy KDE)
import tkinter as tk
# nazwę tego modułu często się skraca przy imporcie
print('Początek programu')
# Utworzenie obiektu "całe okno" - korzeń całej struktury komponentów
root = tk.Tk()
# Utworzenie komponentu typu Label, który "należy do" okna
label1 = tk.Label(master=root, text='Pierwszy napis')
# Dodanie do okna - komponent staje się widoczny
label1.pack()
# Jeśli potrzebuję późniejszego dostępu do tego komponentu, to zapisuję go na zmienną.
label2 = tk.Label(master=root, text='Drugi napis')
label2.pack()
# A jeśli dalszy los komponentu mnie nie interesuje, to mogę tak, bez zapisywanie na zmienną...
tk.Label(master=root, text='Trzeci napis').pack()
button1 = tk.Button(master=root, text="Klik Klik")
button1.pack()
button2 = tk.Button(master=root, text="Guzik 2")
button2.pack()
print('Zaraz wyświetlę okno')
# Wyświetlenie okna. Od tej pory aplikacja działa na zasadzie zasadzie obsługi zdarzeń.
root.mainloop()
print('Koniec programu')
import tkinter
root = tkinter.Tk()
root.geometry('800x600')
# Różne parametry (np. wygląd) można podać od razu podczas tworzenia komponentu.
label1 = tkinter.Label(master=root, text='Pierwszy napis',
fg='blue', font='Arial 40 bold')
label1.pack()
label2 = tkinter.Label(master=root, text='Drugi napis')
label2.pack()
tkinter.Label(master=root, text='Trzeci napis', font='Roboto 40').pack()
# Za pomocą configure w dowolnym momencie można zmienić parametry komponentu: wygląd, tekst itp.
# Z grubsza te same parametry, które ustawia się podczas towrzenia obiektu.
label2.configure(text='Nowy drugi napis', font='Times 33 italic', fg='red')
# specyfikację czcionki można też podać w formie tupli lub listy
button1 = tkinter.Button(master=root, text='Klik Klik', font=('Arial', 24, 'bold'))
button1.pack()
button2 = tkinter.Button(master=root, text='Guzik 2')
button2.pack()
# kolory można też podawać jak w CSS #RRGGBB (red green blue, każdy w zakresie od 00 do FF = 255)
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), fg='#880000', bg='#FFFFEE')
poleTekstowe.pack()
root.mainloop()
import tkinter
from tkinter import messagebox
def co_ma_sie_stac1():
messagebox.showinfo(title='Informacja',
message='Ojej naciśnięto pierwszy guzik')
def co_ma_sie_stac2():
'''Ta funkcja zostanie wywołana, gdy użytkownik naciśnie guzik 2'''
print('Kliknięto guzik 2')
root = tkinter.Tk()
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Pierwszy napis',
fg='blue', font='Arial 40 bold')
label1.pack()
label2 = tkinter.Label(master=root, text='Drugi napis')
label2.pack()
tkinter.Label(master=root, text='Trzeci napis', font='Roboto 40').pack()
label2.configure(text='Nowy drugi napis', font='Times 33 italic', fg='red')
button1 = tkinter.Button(master=root, text='Klik Klik', font=('Arial', 24, 'bold'), command=co_ma_sie_stac1)
button1.pack()
# Jako paramter command przekazujemy funkcję.
# Przkazujemy funkcję jako wartość - nie wywołujemy tej funkcji TERAZ, tylko ją przekazujemy.
# To tkinter wywoła tę funkcję, gdy użytkownik naciśnie guzik.
button2 = tkinter.Button(master=root, text='Guzik 2', command=co_ma_sie_stac2)
button2.pack()
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), fg='#880000', bg='#FFFFEE')
poleTekstowe.pack()
root.mainloop()
import tkinter
from tkinter import messagebox
licznik = 0
def co_ma_sie_stac1():
global licznik
licznik += 1
messagebox.showinfo(title='Informacja',
message=f'Naciśnięto pierwszy guzik po raz {licznik}')
root = tkinter.Tk()
root.geometry('800x600')
label1 = tkinter.Label(master=root, text='Pierwszy napis',
fg='blue', font='Arial 40 bold')
label1.pack()
label2 = tkinter.Label(master=root, text='Drugi napis')
label2.pack()
tkinter.Label(master=root, text='Trzeci napis', font='Roboto 40').pack()
button1 = tkinter.Button(master=root, text='Licznik', font=('Arial', 24, 'bold'), command=co_ma_sie_stac1)
button1.pack()
label2.configure(text='Jak masz na imię?', font='Times 33 italic', fg='red')
poleTekstowe = tkinter.Entry(root, font=('Consolas', 24), fg='#880000', bg='#FFFFEE')
poleTekstowe.pack()
button2 = tkinter.Button(master=root, text='Powitaj', font=('Arial', 24, 'bold'))
button2.pack()
label4 = tkinter.Label(master=root, font='Roboto 40', fg='green')
label4.pack()
def co_ma_sie_stac2():
imie = poleTekstowe.get()
label4.configure(text=f'Witaj {imie}')
button2.configure(command=co_ma_sie_stac2)
root.mainloop()
import tkinter
root = tkinter.Tk()
root.title('Nasza przykładowa apka')
root.geometry('800x600')
# atrybuty komponentów graficznych można ustawiać od razu podczas ich tworzenia:
label1 = tkinter.Label(master=root,
text='Ala ma kota',
font='Arial 40 bold',
fg='#0000FF',
bg='#AAFFFF')
label1.pack()
# atrybuty komponentów graficznych można też ustawiać
# wywołując metodę configure na już istniejącym obiekcie
label2 = tkinter.Label(master=root)
label2.configure(text='Ola ma psa', font=('Times New Roman', 37, 'italic'))
label2.configure(fg='red', bg='yellow')
label2.pack()
# Funkcję obsługującą zdarzenie można też stworzyć "w miejscu" za pomocą wyrażenia lambda.
button1 = tkinter.Button(master=root, text='Kliknij mnie',
font='Roboto 40 bold',
fg='blue', bg='#FFCCFF',
command=lambda: print('ojej, ktoś nacisnął guzik'))
button1.pack()
root.mainloop()
from tkinter import Tk, Label, Button
def co_ma_sie_stac():
global licznik, label2
licznik += 1
label2.configure(text=f'Licznik: {licznik}')
licznik = 0
root = Tk()
root.title('Nasza przykładowa apka')
root.geometry('800x600')
# atrybuty komponentów graficznych można ustawiać od razu podczas ich tworzenia:
label1 = Label(master=root,
text='Ala ma kota',
font='Arial 40 bold',
fg='#0000FF',
bg='#AAFFFF')
label1.pack()
# atrybuty komponentów graficznych można też ustawiać
# wywołując metodę configure na już istniejącym obiekcie
label2 = Label(master=root)
label2.configure(text='Licznik: 0', font=('Arial', 36, 'bold'))
label2.configure(fg='red', bg='white')
label2.pack()
# Funkcja co_ma_sie_stac zostanie odpalona gdy użytkownik naciśnie guzik
button1 = Button(master=root, text='Kliknij mnie',
font='Roboto 40 bold',
fg='blue', bg='#FFCCFF',
command=co_ma_sie_stac)
button1.pack()
root.mainloop()
import tkinter
import tkinter.ttk
import tkinter.messagebox
# główne okno
root = tkinter.Tk()
root.title('Nasza pierwsza apka')
root.geometry('800x600')
# komponenty okna
# pierwszy parametr root oznacza, że komponent należy do tego okna
# poza nim można przekazywać wiele innych parametrów (technicznie: **kwargs),
# za pomocą których ustala się styl i zawartość komponentów
tekst1 = tkinter.Label(root, text='Ala ma kota', font='Arial')
tekst1.pack()
tekst2 = tkinter.Label(root, text='Ola ma psa', font='Times 40 italic', foreground='red')
tekst2.pack()
tekst3 = tkinter.Label(root, text='Trzeci napis')
tekst3.pack()
# własności (wygląd, tekst itp.) można ustawiać także później, już po utworzeniu obiektów, za pomocą configure:
tekst3.configure(font=('Arial', 36, 'bold'), foreground='#008844')
font1 = ('Arial', 30)
pole = tkinter.Entry(root, font=font1, background='white')
pole.pack()
# pole tekstowe (Entry) nie przyjmuje parametru text
# nie zadziała:
# pole = tkinter.Entry(root, text='halo halo', font=font1, background='white')
pole2 = tkinter.Entry(root, font=font1, bg='white', fg='red')
pole2.pack()
# początkowy tekst, który ma być wyświetlony w polu można ustawić takim poleceniem:
pole2.insert(tkinter.END, 'początkowy tekst')
def co_robic():
tkinter.messagebox.showinfo('Ping', 'Ojej, naciśnięto guzik')
# Aby po wciśnięciu guzika nastapiła reakcja (żeby progra mcoś zrobił),
# to guzikowi przypisujemy komendę : command=
# tą komendą powinna być funkcja, która nie przyjmuje żadnego parametru
guzik = tkinter.Button(root, text='OK', font=font1, command=co_robic)
guzik.pack()
combo = tkinter.ttk.Combobox(root, values=['Ala', 'Ola', 'Ela'], font='Arial 28')
combo.pack()
#myphoto = tkinter.PhotoImage(file='obrazek.png')
#img_label = tkinter.Label(master=root, image=myphoto)
guzikBlue = tkinter.Button(root, text='Niebieskie', fg='blue')
guzikBlue.pack()
guzikRed = tkinter.Button(root, text='Czerwone', fg='red')
guzikRed.pack()
# w akcji obsługi zdarzeń możemy odczytywać i modyfikować wartości w komponentach
# - o ile tylko mamy dostęp do nich jako do zmiennych (tu są to zmienne globalne: pole, tekst3)
def ustaw_niebieskie():
tekst3.configure(fg='blue', text=pole.get())
def ustaw_czerwone():
tekst3.configure(fg='red', text=pole2.get())
# akcje obługi zdarzeń można podpiąć do guzików także później, już po ich utworzeniu:
guzikBlue.configure(command=ustaw_niebieskie)
guzikRed.configure(command=ustaw_czerwone)
root.mainloop()
import tkinter
import tkinter.ttk
import tkinter.messagebox
# główne okno
root = tkinter.Tk()
root.title('Nasza pierwsza apka')
root.geometry('800x600')
# komponenty okna
# pierwszy parametr root oznacza, że komponent należy do tego okna
# poza nim można przekazywać wiele innych parametrów (technicznie: **kwargs),
# za pomocą których ustala się styl i zawartość komponentów
tekst1 = tkinter.Label(root, text='Ala ma kota', font='Arial')
tekst1.pack()
tekst2 = tkinter.Label(root, text='Ola ma psa', font='Times 40 italic', foreground='red')
tekst2.pack()
tekst3 = tkinter.Label(root, text='Trzeci napis')
tekst3.pack()
# własności (wygląd, tekst itp.) można ustawiać także później, już po utworzeniu obiektów, za pomocą configure:
tekst3.configure(font=('Arial', 36, 'bold'), foreground='#008844')
font1 = ('Arial', 30)
pole = tkinter.Entry(root, font=font1, background='white')
pole.pack()
# pole tekstowe (Entry) nie przyjmuje parametru text
# nie zadziała:
# pole = tkinter.Entry(root, text='halo halo', font=font1, background='white')
pole2 = tkinter.Entry(root, font=font1, bg='white', fg='red')
pole2.pack()
# początkowy tekst, który ma być wyświetlony w polu można ustawić takim poleceniem:
pole2.insert(tkinter.END, 'początkowy tekst')
def co_robic():
tkinter.messagebox.showinfo('Ping', 'Ojej, naciśnięto guzik')
# Aby po wciśnięciu guzika nastapiła reakcja (żeby progra mcoś zrobił),
# to guzikowi przypisujemy komendę : command=
# tą komendą powinna być funkcja, która nie przyjmuje żadnego parametru
guzik = tkinter.Button(root, text='OK', font=font1, command=co_robic)
guzik.pack()
combo = tkinter.ttk.Combobox(root, values=['Ala', 'Ola', 'Ela'], font='Arial 28')
combo.pack()
guzikBlue = tkinter.Button(root, text='Niebieskie', fg='blue')
guzikBlue.pack()
guzikRed = tkinter.Button(root, text='Czerwone', fg='red')
guzikRed.pack()
# w akcji obsługi zdarzeń możemy odczytywać i modyfikować wartości w komponentach
# - o ile tylko mamy dostęp do nich jako do zmiennych (tu są to zmienne globalne: pole, tekst3)
def ustaw_niebieskie():
tekst3.configure(fg='blue', text=pole.get())
def ustaw_czerwone():
tekst3.configure(fg='red', text=pole2.get())
# akcje obługi zdarzeń można podpiąć do guzików także później, już po ich utworzeniu:
guzikBlue.configure(command=ustaw_niebieskie)
guzikRed.configure(command=ustaw_czerwone)
root.mainloop()
autor = 'Patryk'
# Coś na kształ eksportu...
domyslna_funkcja = geometry.figures.square_area
def add_matrices_version_1(m1, m2):
result = []
for row_i in range(len(m1)):
row = []
for col_i in range(len(m1[row_i])):
element = m1[row_i][col_i] + m2[row_i][col_i]
row.append(element)
result.append(row)
return result
def add_matrices_version_2(m1, m2):
result = []
for row_m1, row_m2 in zip(m1, m2):
row = []
for ele_m1, ele_m2 in zip(row_m1, row_m2):
row.append(ele_m1 + ele_m2)
result.append(row)
return result
def add_matrices(m1, m2):
return [[ele_m1 + ele_m2 for ele_m1, ele_m2 in zip(row_m1, row_m2)] for row_m1, row_m2 in zip(m1, m2)]
from math import sqrt
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return f'({self.x}, {self.y})'
def dlugosc(self):
return sqrt(self.x ** 2 + self.y ** 2)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __lt__(self, other):
return self.dlugosc() < other.dlugosc()
def __le__(self, other):
return self.dlugosc() <= other.dlugosc()
def __gt__(self, other):
return self.dlugosc() > other.dlugosc()
def __ge__(self, other):
return self.dlugosc() >= other.dlugosc()
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
# to daje możliwość mnożenia wektor * liczba
def __mul__(self, other):
return Vector(self.x * other, self.y * other)
# to daje możliwość mnożenia liczba * wektor
def __rmul__(self, other):
return self.__mul__(other)
def main():
a = Vector(x=10, y=20)
b = Vector(15, 5)
zerowy = Vector()
pionowy = Vector(y=10)
print(f'a = {a}')
print(f'b = {b}')
print()
suma = a + b
print(f'suma = {suma}')
roznica = a - b
print(f'rozn = {roznica}')
iloczyn1 = a * 3
print(f'iloczyn1 = {iloczyn1}')
iloczyn2 = 5 * b
print(f'iloczyn2 = {iloczyn2}')
print()
if __name__ == '__main__':
main()
# Opcja 1: z pakietu zaimportuj moduł, podaję ścieżkę bezwzględną
# from mathematica.geometry import measures
# from mathematica.podstawy import pomnoz
# Opcja 2: z pakietu zaimportuj moduł, podaję ścieżkę względną
from . import measures
# from .. import podstawy
from ..podstawy import pomnoz
def square_area(a, b):
return pomnoz(a, b)
def triangle_area(a, h):
return a * h * 0.5
def circle_area(r):
from math import pi
return pi * r**2
def square_diagonal(a):
return measures.cartesian_distanse(a, a)
# Opcja 1: z modułu importuję funkcję, podaję ścieżkę bezwzględną
# from mathematica.geometry.measures import cartesian_distanse
# Opcja 2: z pakietu zaimportuj moduł, podaję ścieżkę względną
from .measures import cartesian_distanse
def square_area(a, b):
return a * b
def triangle_area(a, h):
return a * h * 0.5
def circle_area(r):
from math import pi
return pi * r**2
def square_diagonal(a):
return cartesian_distanse(a, a)
def cartesian_distanse(x, y):
return (x**2 + y**2)**0.5
def dodaj(x, y):
return x + y
def pomnoz(x, y):
return x * y
# Z pakietu mathematica.algebra (ścieżka bezwzględna) import modułu matrices
# tak jakby /mathematica/algebra/matrices.py
from mathematica.algebra import matrices
def test_add_matrices():
a = [
[1, 2, 3],
[4, 5, 6],
]
b = [
[7, 8, 9],
[10, 11, 12],
]
result = matrices.add_matrices(a, b)
assert result == [
[8, 10, 12],
[14, 16, 18],
]
def test_sub_matrices():
a = [
[12, 11, 10],
[9, 8, 7],
]
b = [
[1, 2, 3],
[4, 5, 6],
]
result = matrices.sub_matrices(a, b)
assert result == [
[11, 9, 7],
[5, 3, 1],
]
# Można importować podając ścieżkę bezwzględną
# from mathematica.geometry import figures
# Ale jeśli jesteśmy w tym pakiecie (mathematica.test),
# to możemy importować podając ścieżkę względną
# To odpowiada ścieżce do plików: ../geometry/figures.py
# Trzeba wejść poziom wyżej, bo jesteśmy w pakiecie tests
from ..geometry import figures
def test_square_area():
assert figures.square_area(a=2, b=3) == 6
def test_triangle_area():
assert figures.triangle_area(a=2, h=4) == 4
from .algebra.matrices import add_matrices
m1 = [[1,1],
[2,2],
[3,4]]
m2 = [[0,1],
[1,0],
[10,10]]
wynik = add_matrices(m1, m2)
print(wynik)
print()
\ No newline at end of file
# To jest przykład "modułu", czyli pliku, który może być imporotwany przez inne pliki (moduły, programy)
print('Początek modułu. Teraz __name__ == ', __name__)
MIASTO='Katowice'
def pole_kwadratu(a):
return a*a
def wypisz_tekst(tekst, ile_razy):
for i in range(ile_razy):
print(tekst)
class Klasa:
def metoda(self):
print('To jest metoda')
if __name__ == '__main__':
print(' O, teraz modul został uruchomiony jako program')
wypisz_tekst(' __name__ == __main__', 2)
else:
print(' Teraz moduł jest importowany')
print('Koniec modułu')
print('Początek programu, teraz __name__ == ', __name__)
print('Zaraz będzie import...')
import modul
# Przy taki sposobie importowania trzeba używać nazwy modułu przed nazwami funkcji
wynik = modul.pole_kwadratu(5)
modul.wypisz_tekst(f'Ala ma {wynik} kotów.', 3)
obiekt = modul.Klasa()
obiekt.metoda()
print(modul.MIASTO)
print('Próba drugiego importu')
# Moduł jest importowany tylko jeden raz. Kolejny import już nic nie robi.
print('Koniec programu')
import modul as m
#ERR wynik = modul.pole_kwadratu(5)
# Przy taki sposobie importowania trzeba używać aliasu przed nazwami funkcji
wynik = m.pole_kwadratu(5)
m.wypisz_tekst(f'Ala ma {wynik} kotów.', 3)
obiekt = m.Klasa()
obiekt.metoda()
print(m.MIASTO)
from modul import wypisz_tekst, Klasa, MIASTO
# Przy takim sposobie importowania w kodzie używamy samych nazw funkcji
# a nie nie możemy już uzywać nazwy moduły (i dostawać się do innych funkcji)
# wynik = modul.pole_kwadratu(5)
# modul.wypisz_tekst(f'Ala i jej kot', 3)
wypisz_tekst(f'Ala mieszka w {MIASTO}', 3)
obiekt = Klasa()
obiekt.metoda()
print(MIASTO)
from modul import *
# Przy takim sposobie importowania w kodzie używamy samych nazw funkcji,
# zaimportowane są wszystkie globalne definicje z tamtego pliku.
# wynik = modul.pole_kwadatu(5)
wynik = pole_kwadratu(5)
wypisz_tekst(f'Ala mieszka w {MIASTO}', 3)
obiekt = Klasa()
obiekt.metoda()
print(MIASTO)
def jakas_funkcja(x):
# "import lokalny"
from modul import pole_kwadratu
print(pole_kwadratu(x))
# nie można skorzystać poza funkcją
# pole_kwadratu(8)
# nawet gdy funckje wywołuję wielokrotnie, albo wiele takich funkcji, to moduł importuje się raz
print('AAA')
jakas_funkcja(7)
print('BBB')
jakas_funkcja(6)
print('CCC')
from setuptools import setup, find_packages
setup(
name='mathematica',
version='1.0.0',
description='Math utils.',
packages=find_packages(exclude=['mathematica.tests']),
)
# Aby zbudować paczkę w formie zipa używamy:
# python setup.py sdist --format=zip
# - to daje wersję ze źródłami, którą łatwiej zainstalować
# lub ewentualnie
# python setup.py bdist
# - co daje wersję "binarną"/"skompilowaną", którą trudniej zainstalować - może być to nieprzenośne między systemami
# Po zbudowaniu paczki za pomocą sdist w docelowej lokalizacji można wykonać polecenie
# pip install mathematica-1.0.0.zip
# i pakiet oraz jego moduły staną się dostępne
import mathematica.algebra.matrices
import mathematica.podstawy
# Sposób importowania pokazany tutaj: import PAKIET.MODUL
# Konsekwencja: podczas wywoływania funkcji lub klas trzeba wpisywać pełną ścieżkę
wynik = mathematica.podstawy.pomnoz(2, 3)
print(wynik)
m1 = [[1,1],
[2,2],
[3,4]]
m2 = [[0,1],
[1,0],
[10,10]]
wynik = mathematica.algebra.matrices.add_matrices(m1, m2)
print(wynik)
import mathematica
print(mathematica.autor)
print(mathematica.domyslna_funkcja(7, 5))
from mathematica.algebra.matrices import *
from mathematica.podstawy import pomnoz
# Sposób importowania pokazany tutaj: from PAKIET.MODUL import FUNKCJA
wynik = pomnoz(2, 3)
print(wynik)
m1 = [[1,1],
[2,2],
[3,4]]
m2 = [[0,1],
[1,0],
[10,10]]
wynik = add_matrices(m1, m2)
print(wynik)
print()
from mathematica import autor
print(autor)
from mathematica import podstawy
from mathematica.algebra import matrices as macierze
from mathematica.geometry import figures
# Sposób importowania pokazany tutaj: from PAKIET import MODUL
wynik = podstawy.pomnoz(2, 3)
print(wynik)
wynik = figures.square_area(5, 3)
print(wynik)
print()
m1 = [[1,1],
[2,2],
[3,4]]
m2 = [[0,1],
[1,0],
[10,10]]
wynik = macierze.add_matrices(m1, m2)
print(wynik)
print()
import mathematica
print(mathematica.autor)
import sys
# najbardziej oczywisty zapis w Pythonie - wersja z tworzeniem tablic int
def mnoz_zakres(n):
t1 = list(range(n))
t2 = list(range(n))
suma = 0
for e1 in t1:
for e2 in t2:
suma += e1 * e2
return suma
if __name__ == '__main__':
n = int(sys.argv[1])
wynik = mnoz_zakres(n)
print('Wynik:', wynik)
import sys
# wersja bez tworzenia tablic
def mnoz_zakres(n):
return sum(e1 * e2 for e1 in range(n) for e2 in range(n))
if __name__ == '__main__':
n = int(sys.argv[1])
wynik = mnoz_zakres(n)
print('Wynik:', wynik)
import sys
import numpy
# wersja z użyciem biblioteki numpy
# Gdy użyjemy tej biblioteki, będą używane "natywne" liczby, podobnie jak w C i Javie
def mnoz_zakres(n):
t1 = numpy.arange(n, dtype=numpy.int64).reshape(1, n)
t2 = numpy.arange(n, dtype=numpy.int64).reshape(n, 1)
return (t2 @ t1).sum()
if __name__ == '__main__':
n = int(sys.argv[1])
#n = 10000
wynik = mnoz_zakres(n)
print('Wynik:', wynik)
#include <stdio.h>
#include <stdlib.h>
long mnoz_zakres(int n) {
int *t1 = (int*) malloc (n * sizeof(int));
int *t2 = (int*) malloc (n * sizeof(int));
for(int i=0; i < n; i++) {
t1[i] = i;
t2[i] = i;
}
long suma = 0;
for(int i=0; i < n; i++) {
for(int j=0; j < n; j++) {
suma += t1[i] * t2[j];
}
}
free(t1);
free(t2);
return suma;
}
int main(int argc, char **argv) {
int n = atoi(argv[1]);
long wynik = mnoz_zakres(n);
printf("Wynik: %ld\n", wynik);
return 0;
}
// Najbardziej oczywista implementacja w Javie
// Wersja z tworzeniem tablic.
public class mnozenie4 {
private static long mnoz_zakres(int n) {
int[] t1 = new int[n];
int[] t2 = new int[n];
for(int i=0; i < n; i++) {
t1[i] = i;
t2[i] = i;
}
long suma = 0;
for(int x : t1) {
for(int y : t2) {
suma += x * y;
}
}
return suma;
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long wynik = mnoz_zakres(n);
System.out.printf("Wynik: %d\n", wynik);
}
}
// Najbardziej oczywista implementacja w Javie
// Wersja bez tworzenia tablic.
public class mnozenie4a {
private static long mnoz_zakres(int n) {
long suma = 0;
for(int x=0; x < n; x++) {
for(int y=0; y < n; y++) {
suma += x * y;
}
}
return suma;
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long wynik = mnoz_zakres(n);
System.out.printf("Wynik: %d\n", wynik);
}
}
import java.util.stream.LongStream;
// W tej wersji używam "lamb i stream-ów", czyli elementów programowania funkcyjnego, dostepnych od Javy 8
public class mnozenie5 {
private static long mnoz_zakres(int n) {
return LongStream.range(0, n)
.flatMap(i -> LongStream.range(0, n).map(j -> i * j))
.sum();
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long wynik = mnoz_zakres(n);
System.out.printf("Wynik: %d\n", wynik);
}
}
import java.util.stream.LongStream;
// W tej wersji używam "parallel stream", aby zrównoleglić obliczenia (wykorzystać wiele procesorów)
public class mnozenie5p {
private static long mnoz_zakres(int n) {
return LongStream.range(0, n)
.parallel()
.flatMap(i -> LongStream.range(0, n)
.parallel()
.map(j -> i * j))
.sum();
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long wynik = mnoz_zakres(n);
System.out.printf("Wynik: %d\n", wynik);
}
}
import java.math.BigInteger;
// W tej wersji do reprezentowania liczb używam klasy BigInteger, czyli liczb bez ograniczenia na wielkość; czegoś, co działa analogicznie do Pythonowego int.
public class mnozenie6 {
private static BigInteger mnoz_zakres(int n) {
BigInteger[] t1 = new BigInteger[n];
BigInteger[] t2 = new BigInteger[n];
for(int i=0; i < n; i++) {
t1[i] = BigInteger.valueOf(i);
t2[i] = BigInteger.valueOf(i);
}
BigInteger suma = BigInteger.ZERO;
for(BigInteger x : t1) {
for(BigInteger y : t2) {
suma = suma.add(x.multiply(y));
}
}
return suma;
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
BigInteger wynik = mnoz_zakres(n);
System.out.printf("Wynik: %d\n", wynik);
}
}
import System.Environment
-- Język Haskell. Wersja z tworzeniem tablic.
oblicz::Int -> Int
oblicz n =
let t1 = [0..n-1] in
let t2 = [0..n-1] in
sum([x*y | x <- t1, y <- t2])
main::IO()
main = do
[arg0] <- getArgs
let n = read arg0
let res = oblicz n
print res
Błąd! division by zero
2+2
2+3*4
2**(10*2)
123/0
12/2
18*9
from sys import stderr
while True:
linia = input()
if not linia:
break
try:
wynik = eval(linia)
print(wynik)
except Exception as e:
print(f'Błąd dla działania "{linia}":', e, file=stderr)
This source diff could not be displayed because it is too large. You can view the blob instead.
4
14
1048576
6.0
162
This source diff could not be displayed because it is too large. You can view the blob instead.
import subprocess
print('Początek Pythona')
# Program bez żadnych argumentów można uruchomić tak:
subprocess.run('ls')
#subprocess.run('kcalc')
#subprocess.run('calc.exe')
# W tej wersji program wypisuje swoje wyśjcie na standardowe wyjście tego procesu Pythona.
# (Python nie przechwytuje wyjścia tego procesu, tylko "wypuszcza je na zewnątrz").
print('Koniec Pythona')
import subprocess
print('Początek Pythona')
#ERR subprocess.run('ls -l')
# OK
# Gdy uruchamiany program ma otrzymać parametry, to do run przekazujemy listę
# gdzie na początku jest samo polecenie, a potem jego argumenty.
subprocess.run(['ls', '-l'])
print('--------')
result = subprocess.run(['python', r'/home/patryk/PycharmProjects/pythonProject/p01_podstawy/hello.py'])
print('Proces zakończony:', result)
print('Kod zakończenia:', result.returncode)
import subprocess
# W tej wersji włączymy opcję zbierania outputu - to pozwala odczytać output po zakończeniu procesu.
# Wyjście programu jest zapamiętywane w RAM, a potem można to odczytać.
result = subprocess.run(['find', '..', '-name', '*.py'], capture_output=True)
print('Proces zakończony kodem', result.returncode)
print('Output:')
print(result.stdout)
# decode ?
import subprocess
print('Zaraz zacznę')
# Tutaj efekt, który daje capture_output=True, uzyskujemy wpisując specjalną wartość PIPE
# do parametrów stdout i stderr
result = subprocess.run(['find', '..', '-name', '*.py'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = result.stdout
tekst = output.decode()
linie = tekst.splitlines(keepends=False)
for linia in linie:
print('*', linia)
print('Gotowe')
import subprocess
# W tej wersji wyjście jest zapisywane do pliku.
print('Zaczynamy')
with open('output5.txt', mode='w') as plik:
result = subprocess.run(['find', '..', '-name', '*.py'],
stdout=plik, stderr=subprocess.DEVNULL)
print('Gotowe')
import subprocess
# W tej wersji wejście, wyjście i błedy - wszystko jest w oddzielnych plikach
print('Zaczynamy')
with open('dzialania.txt', mode='r') as wejscie, \
open('output6.txt', mode='w') as wyjscie, \
open('bledy6.txt', mode='w') as bledy:
result = subprocess.run(['python', 'kalkulator.py'],
stdin=wejscie, stdout=wyjscie, stderr=bledy)
print('Gotowe. exitcode = ', result.returncode)
from subprocess import call
# W starszych wersjach Pythona zamiast run używało się call
print('Zaraz zacznę')
with open('stdout7.txt', mode='wb') as wyjscie, open('stderr7.txt', mode='wb') as bledy:
result = call(['find', '..', '-name', '*.py'], stdout=wyjscie, stderr=bledy)
print('result:', result)
print('Gotowe')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment