Usporedba osnovnih elemenata C-a i python-a

Pregled često korištenih tipova podataka

Sljedeća tablica prikazuje često korištene tipove podataka u pythonu i referencu na odjeljak gdje se navedeni tip detaljnije diskutira.

opis mutable immutable
jednostavni tipovi, brojevi   int, float, complex, bool, NoneType (vidi Osnovni tipovi podataka)
niz byteova bytearray bytes (vidi Binarne datoteke, Unicode)
niz unicode znakova (=string) nema, ali io.StringIO, array.array, bytearray, list mogu poslužiti str (Stringovi i polja (liste), Rad sa stringovima, detalji u Unicode)
niz objekata list tuple
niz objekata određenog tipa (“homogeno” polje) array.array  
niz objekata bez ponavljanja set frozenset
rječnik dict (vidi Rječnik (Dictionary))  

Mutable varijable se mogu mijenjati, immutable varijable se ne mogu mijenjati (konstante su). Treba primijetiti da su u C-u primitivni tipovi podataka int, float, ... mutable, a u pythonu su immutable. Razlika između mutable i immutable diskutira se u odjeljku Pridruživanje lista.

Osnovne primjere upotrebe možete naći u raznim tutorialima npr.:

Operatori

Operatori su slični kao u C-u. Postoje razlike, npr. postoji poseban operator // za cjelobrojno dijeljenje kao i za potenciranje **.

Python C
and &&
or ||
a**b pow(a,b)
a/b ((double)a)/b (dijeljenje s decimalama)
a//b a/b ako su oba cjelobrojni, inače floor(a/b)
not !
id(x) &x (adresa od x)

U pythonu postoji operator in koji pretražuje postoji li element u skupu. Npr. u sljedećem primjeru provjeravamo jesu li 1, '1', '' elementi liste a:

>>> a = [1, 2, 3, 'x', '']
>>> print( 1 in a, '1' in a, '' in a )
True False True

Direktan rad s memorijom u pythonu nije podržan što znači da ne postoji operator za očitavanje vrijednosti na adresi kao * u C-u. Ne postoji operator za očitavanje adrese objekta ali postoji funkcija id() koja očitava “identitet” objekta. U CPythonu se kao “identitet” objekta koristi adresa objekta.

Popis operatora s jednostavnim primjerima:

Korisne kratice

Umnožak stringa i broja slijepi više primjeraka tog stringa npr. 'xy'*3 daje 'xyxyxy'. Slično za liste i tupleove: [1,2]*3 daje [1,2,1,2,1,2].

Korisne kratice su i:

Python C
a<b<c a<b && b<c
a,b,c = 1,2,3 a=1; b=2; c=3;

Na sličan način funkcija može vratiti “dvije vrijednosti”:

def f(x):
  return x+2, x*2
a, b = f(10)
print( a, b )
12 20

Također, (generatorske) funkcije mogu vratiti više vrijednosti, ali jednu po jednu, što ima prednost da nisu sve odjednom u memoriji (vidi npr. Pridruživanje iteratora varijablama).

U C-u se to obično radi koristeći polja ili strukture što je manje elegantno.

Zadavanje vrijednosti tipa tuple, list, set

Povratnu vrijednost u gornjem primjeru mogli smo pridružiti i jednoj varijabli.

def f(x):
  return x+2, x*2
a = f(10)
print( a, type(a) )
(12, 20) <class 'tuple'>

Vidimo da je vrijednost te varijable (12, 20) a tip tuple.

Napomena

Nizovi vrijednosti tipa tuple zadaju se pomoću okruglih zagrada, nizovi tipa list pomoću uglatih, nizovi tipa set (kao i dict) pomoću vitičastih.

U slučaju tipa tuple zagrade se u nekim slučajevima mogu izostaviti. To smo vidjeli kod naredbe return (npr. return a,b,c je isto što i return (a, b, c)). Naredbe koje to dopuštaju su npr. yield, for i pridruživanje.

a = (1, 2, 3, 2, 3)
b = [2, 3, 4]
c = frozenset( a )
d = {2, 3, 4}
e = {}
f = set()
g = {'a':1, 'b':2, 'c':3}

print( a, type(a) )
print( b, type(b) )
print( c, type(c) )
print( d, type(d) )
print( e, type(e) )
print( f, type(d) )
print( g, type(g) )
print()

b.extend( a )
d.update( a )

print( b, type(b) )
print( d, type(d) )
(1, 2, 3, 2, 3) <class 'tuple'>
[2, 3, 4] <class 'list'>
frozenset({1, 2, 3}) <class 'frozenset'>
{2, 3, 4} <class 'set'>
{} <class 'dict'>
set() <class 'set'>
{'a': 1, 'b': 2, 'c': 3} <class 'dict'>

[2, 3, 4, 1, 2, 3, 2, 3] <class 'list'>
{1, 2, 3, 4} <class 'set'>

Osnovni tipovi podataka

Python Komentar C

bool

>>> a = True
>>> print(a, type(a))
True <class 'bool'>
Logički tip podataka True, False. U Pythonu None, razne nule (0, 0.0), prazne liste [], stringovi "", itd. kad se koriste kao logički uvjet znače False.

U starijem standardu C-a ne postoji, od C99 nadalje postoji i naziva se _Bool. I u starim i u novim verzijama C-a tip int se može svugdje koristiti umjesto _Bool (na računalima u F26 _Bool zauzima 4 bytea što možemo vidjeti pomoću sizeof(1==0) koji vrati broj 4).

Kad je potrebno držati u memoriji polje boolean vrijednosti, radi štednje memorije možemo koristiti npr. char umjesto int ili radi još veće uštede koristiti pojedinačne bitove unutar veće varijable kao ovdje ili ovdje.

int

>>> a = -1000
>>> print(a, type(a))
-1000 <class 'int'>
>>> a = 123456789012345678901234567890
>>> print(a, type(a))
123456789012345678901234567890 <class 'int'>
Pythonov int drži cijele brojeve proizvoljnog broja znamenaka. C nema ugrađen takav tip. Slični tipovi su int, long, samo oni ne drže proizvoljan broj znamenki.

float

>>> a = 1.0e-300
>>> print(a, type(a))
1e-300 <class 'float'>
Python-ov float je implementiran pomoću C-ovog double-a double

complex

>>> a = 1 + 1.0e-300j
>>> print(a, type(a))
(1+1e-300j) <class 'complex'>
Noviji C prevoditelji podržavaju kompleksne brojeve. Primjeri na: http://stackoverflow.com/questions/6418807/how-to-work-with-complex-numbers-in-c. double complex

NoneType

>>> a = None
>>> print(a, type(a))
None <class 'NoneType'>

Varijabla se postavi na ovaj tip kad je definirana ali nije inicijalizirana. Primjer je funkcija koja zaboravi vratiti vrijednost:

def fun():
  print("funkcija samo ispisuje")
a = fun()
print(a, type(a))
funkcija samo ispisuje
None <class 'NoneType'>
Podsjeća na void u C-u, samo u C-u nisu postojale vrijednosti tipa void, postojao je samo tip void. U pythonu postoji samo jedna moguća vrijednost tipa NoneType a to je None.

Literatura

Grananje i petlje

Neke očite sličnosti i razlike C-a i python-a vidimo u sljedećoj tablici.

Python C
break break;
continue continue;
if uvjet:
  radnja
if(uvjet){
  radnja;
}
if uvjet:
  radnja1
else:
  radnja2
if(uvjet){
  radnja1;
}
else{
  radnja2;
}
while uvjet:
  radnja1
while(uvjet){
  radnja1;
}

Osnovni elementi programa

Python C

Indentacija

Napomena

U pythonu nema vitičastih zagrada, a blok naredbi je definiran time što je uvučen u desno, relativno na prethodni red, pomoću razmaka ili tabova. Kako broj razmaka koje tab predstavlja nije fiksan (tj. može se namjestiti u editoru po želji) bitno je to indentiranje raditi uniformno. Preporuča se koristiti isključivo razmake za uvlačenje (npr. 2 ili 4). Da bi se olakšalo upisivanje obično je moguće namjestiti u editoru da pritisak na tab generira npr. 4 razmaka ' ' (a ne tab '\t').

Napomena

U C-u se lako moglo definirati prazan blok pomoću ; ili {}. Za tu svrhu u pythonu postoji naredba pass koja isto tako ne radi ništa.

Vitičaste zagrade
Svaka naredba u svom redu ili ; ;

'xx' ili "xx" ili """xx""" (trostruki navodnici mogu uključivati više redaka teksta)

Kod unosa stringova u pythonu postoje još neke mogućnosti koje postignu dodavanjem slova (tzv. prefiksa) ispred prvih navodnika.

Prefiks r omogućuje upis znaka \ bez potrebe da se piše \\, tj. dovoljno je samo r"\". Naravno u takvom zapisu ne možemo upisati znak za novi red \n jer je r"\n" isto što i "\\n". Ovakav zapis je koristan kad je potrebno upisivati stringove koji sadrže veliki broj znakova \.

Prefiks f omogućuje lagano ubacivanje vrijednosti varijabli u string, te formatiranje. (Više na https://realpython.com/python-f-strings/)

a = 1
print(f"{a}+{a}={a+a}")
print(f"{a:5}+{a:5}={a+a:5}")
1+1=2
    1+    1=    2

Prefiks u se koristio u pythonu 2. U pythonu 3 se podrazumijeva da su stringovi nizovi unicode znakova.

"xx"
Nema tip podataka znak (char). Umjesto toga koristi string duljine 1: "x" (ili niz byteova duljine 1: b"x"). 'x'
Python izvršava kôd naredbu po naredbu. Ne pregledava točnost unaprijed kao C nego tek u trenutku izvršavanja. To znači da ako se program u pythonu uspije pokrenuti, ne znači da u njemu nema tipfelera. C sve provjerava unaprijed.
Case sensitive (tj. razlikuje velika i mala slova) Također case sensitive

Heksadecimalni brojevi unose se koristeći prefiks 0x.

Dodatno, radi preglednosti, grupe znamenki se mogu razdvajati znakom _. Npr.:

a = 12_345.6
print(f"{a:,} + {a:,} = {a+a:,}")
print(f"{a:_} + {a:_} = {a+a:_}")
12,345.6 + 12,345.6 = 24,691.2
12_345.6 + 12_345.6 = 24_691.2
Također 0x.

for petlja

Python C
for i in range(pocetak,kraj,korak):
  radnja

range() je oznaka za interval sa zadanim granicama i iznosom koraka. U pythonu 2 rezultat poziva range(...) je lista brojeva, u pythonu 3 rezultat je objekt tipa range.

a = range(1,26,5)
print( a, type(a) )
range(1, 26, 5) <class 'range'>

Tip range predstavlja niz podataka (tj. sequence type) kao tuple i list. Može se lako pretvoriti u listu:

a = range(1,26,5)
print( a[0], a[1] )
print( list(a) )
1 6
[1, 6, 11, 16, 21]

Za potrebe for petlje možemo koristiti bilo koji tip koji je niz ili koji se može iterirati. Ne mora nužno biti range. O generatorima/iteratorima vidi napomenu u Generatori/iteratori.

for i in ['a', 1, 100]:
  print(i)
a
1
100

Pozor

Bitno je uočiti da su elementi liste uvijek manji od granice kraj. (npr. u gornjem primjeru broj 26 nije u listi)

for(i=pocetak; i<kraj; i+=korak){
  radnja;
}

Formatiranje (formatirani ispis)

Formatiranje stringova i brojeva.

Savjet

Korisna mogućnost pythona je operator % koji radi više manje isto što i sprintf iz C-a

Savjet

U pythonu nije moguće direktno zbrojiti string i broj nego broj treba pretvoriti u string: "broj = " + str(6)

a = 6
b = "broj = %d" % a
d = "x=%f,y=%f" % (1.0,2.2)
print(b)
print(d)
broj = 6
x=1.000000,y=2.200000
int a=6;
char b[32];
char d[32];
sprintf(b,"broj = %d",a);
sprintf(d,"x=%f,y=%f", 1.0, 2.2);
printf("%s\n",b);
printf("%s\n",d);
broj = 6
x=1.000000,y=2.200000

Python podržava i druge načine formatiranja. Pogledati primjere na:

Stringovi i polja (liste)

Duljina stringa
len(a)
strlen(a)
Duljina polja
L=[1,2,3]
print(len(L))
3
int L[]={1,2,3};
//u nekim situacijama može se 
//očitati duljina polja pomoću
printf("%lu\n",sizeof(L)/sizeof(L[0]));
3
Ispis elemenata polja
L=[1,2,30,40]
for i in range(len(L)):
  print(L[i])
1
2
30
40
int L[]={1,2,30,40};
int i;
for(i=0; i<4; i++)
  printf("%d\n",L[i]);
1
2
30
40

Savjet

Ispis elemenata polja na način tipičan za python

L=[1,2,30,40]
for a in L:
  print(a)
1
2
30
40
 

Zbrajanje i nadodavanje

Zbrajanje stringova = nadodavanje stringa na string
a="str"
b="ing"
c=a+b
print(c)
string
char a[32], b[32], c[32];
strcpy(a,"str");
strcpy(b,"ing");
strcpy(c,a);
strcat(c,b);
printf("%s\n",c);
string
Zbrajanje lista = nadodavanje liste na listu
a=[1,2,3]
b=[21,1]
c=a+b
print(c)
[1, 2, 3, 21, 1]
int a[16],b[16],c[16];
a[0]=1; a[1]=2; a[2]=3;
b[0]=21; b[1]=1;
memcpy(c,a,3*sizeof(int)); //kopirati a u c
memcpy(c+3,b,2*sizeof(int)); //kopirati b na c+3
int i;
for(i=0;i<5;i++)printf("%d ",c[i]);
printf("\n");
1 2 3 21 1 
Nadodavanje elemenata na listu
a = [10,20]
a.append(30)
a.append(40)
print(a)
[10, 20, 30, 40]
int a[16] = {10,20};
int na = 2; // programer mora voditi evidenciju
            // o tome gdje je kraj liste
a[na++] = 30;
a[na++] = 40;

int i;
for(i=0;i<na;i++)printf("%d ",a[i]);
printf("\n");
10 20 30 40 
Zbrajanje lista moguće i za liste s elementima raznih tipova
a = [1,2,"a"]
b = ["w",[4,1]]
c = a+b
print(c)
[1, 2, 'a', 'w', [4, 1]]
U C-u je ovo komplicirano. Trebalo bi raditi s listom struktura koji sadrže: informacije o tipu podataka + pointer na same podatke i takve strukture nadodavati s jedne liste na drugu.

Napomena

Python omogućuje i razne druge operacije nad listama - pogledati https://docs.python.org/3/tutorial/datastructures.html

Rad sa stringovima

mijenjanje stringova

u pythonu nije dopušteno mijenjati stringove, iako to ne dolazi do izražaja jer je dopušteno:

a=a+"3"

gornja naredba kreira novi string a zaboravi stari. nakon izvršavanja gornje naredbe a pokazuje na novi string. memoriju zauzetu starim stringom oslobodi u nekom trenutku python-ov garbage collector, ako više nije potrebna.

u žargonu se kaže da su u pythonu stringovi immutable. (a liste su mutable)

Napomena

pogledati Pridruživanje lista

u C-u je promjena dopuštena.

strcat(a,"3")

gornja naredba je promijenila sadržaj na koji a pokazuje, ali sam pointer a je ostao isti.

za razliku od pythona programer mora paziti da se ne prekorači rezervirana duljina od a.

mala u velika slova
a="string"
print(a.upper())
STRING

treba primijetiti da je sam a ostao isti tj. "string"

#include <stdio.h>
#include <string.h>
#include <ctype.h>

void upper( char* s ){
  while( (*s++ = toupper(*s)) );
}

int main(){
  char a[32];
  strcpy(a, "string");
  upper(a);
  printf("%s\n",a);
}
STRING

u C-u je lakše napraviti tako da se sadržaj od a promijeni (u žargonu: in-place operacija)

traženje podstringa u stringu
a="string"

pos = a.find("tri")
if pos >= 0:
  print(pos)
else:
  print("nije pronađen")

pos = a.find("dva")
if pos >= 0:
  print(pos)
else:
  print("nije pronađen")
1
nije pronađen
char a[32];
char* pos;
strcpy(a, "string");

pos = strstr(a,"tri");
if(pos)
  printf("%ld\n",pos-a);
else
  printf("nije pronađen");

pos = strstr(a,"dva");
if(pos)
  printf("%ld\n",pos-a);
else
  printf("nije pronađen");
1
nije pronađen
pristup pojedinim znakovima u stringu
a[1]
a[1]
pristup podstringovima
a="string"
b=a[1:4]
print(b)
tri
char a[]="string";
char b[32];
strncpy(b,a+1,3);
b[3]='\0';
printf("%s\n",b);
tri

Napomena

Popis funkcija (preciznije, metoda) za rad sa stringovima na https://docs.python.org/3/library/stdtypes.html#string-methods

Dijelovi stringa/liste

radnja kôd
sve osim prvog
>>> a="string"
>>> a[1:]
tring
prva 3 znaka/elementa
>>> a = "string"
>>> a[:3]
str
zadnja 3 znaka/elementa
>>> a = "string"
>>> a[-3:]
ing
odbaciti prvi i zadnji
>>> a = ["string",2,3,5j,"4"]
>>> a[1:-1]
[2, 3, 5j]