Veri Türleri ve Değişkenler

Giriş

Containers

C, C++ veya benzer programlama dillerini kullandınız mı? Eğer böyleyse, veri türleri ve değişkenler hakkında yeterli bilgiye sahip olduğunuzu düşünebilirsiniz. Birçok şey biliyorsunuz, bu doğru, ancak Python için bu yeterli değil. Bu yüzden Python’da veri türleri ve değişkenler hakkındaki bu bölüm okunmaya değer. Python ve C’nin arasında bu konuda konusunda çok önemli fark vardır. Tamsayılar, kayan noktalı sayılar, karakter dizileri ve pek çok diğer veri türü iki tarafta da mevcuttur, ancak tam olarak C veya C++’daki gibi de değillerdir.

C gibi dillerde listeler veya ilişkili diziler kullanmak istediğinizde, veri türü listesini veya ilişkili dizileri sıfırdan oluşturmanız gerekir, yani hafıza yapısını ve yerleşim yönetimlerini tasarlamalısınız.Gerekli arama ve erişim yollarını da ayarlamalısınız. Listeler ve ilişkili diziler (Python’da dict – sözlük olarak bilinir), dilin orijinal kısmı olarak kullanımınıza sunulmuştur. Sözün kısası, bu bölüm hem yeni başlayanlar ve hem de diğer programlama dillerinde ileri düzeye gelmiş programcılar için okunmaya değer.

Değişkenler

Genel Değişken Fikri

Bu alt bölüm daha çok C, C++ ve Java programcılarına hitap ediyor, çünkü bu programlama dillerinin temel veri türlerini ele alış şekli Python’unkinden farklıdır. Python’u ilk programlama dili olarak öğrenmeye başlayanlar sonraki alt bölüme geçebilir.

Pekâla, değişken nedir? İsminden anlayacağımız üzere, bir değişken, değişebilen bir şeydir. Değişken, bir bilgisayar programı tarafından kullanılan bir hafıza konumuna işaret etme yöntemidir. Pek çok programlama dilinde bir değişken, bu fiziksel konumun sembolik ismidir.

Bu hafıza konumu sayılar, metin ve/ veya daha karmaşık veri türleri gibi değerler içerir. Bu değişkeni bilgisayara bir veriyi bu konumda saklamasını veya bu konumdan bir miktar bilgi almasını söylemek için kullanabiliriz.

Box X and Y

Bir değişken olarak bazı değerleri saklamak için bir kap olarak görülebilir. Program çalışırken, değişkenlere erişim sağlanır ve bazen değiştirilir, yani bir değişkene yeni bir değer atanır.

Değişkenler hakkında şu ana kadar söylediğimiz şeyler en çok değişkenlerin C, C++ veya Java dillerindeki kullanım biçimine uyar. Bu dillerde değişken isimleri, kullanılmadan önce belirtilmek zorundadır.

int x;
int y; 

Bu belirtmeler programın x ve y isimli iki değişken için hafıza ayırmasını sağlar. Değişken isimleri hafıza konumu yerine geçer. Yukarıda görüldüğü gibi, iki boş ayakkabı kutusu gibidir. Bu ayakkabı kutuları x ve y olarak etiketlenmiştir. Yukarıdaki iki ayakkabı kutusu gibi, hafıza da boştur.

Değişkenlere değer vermek atama işlemleri ile gerçekleştirilebilir. Değişkenlere değer verme yolu bütün programlama dillerinde neredeyse aynıdır. Çoğu durumda eşittir (=) işareti kullanılır. Sağ taraftaki değer, sol taraftaki değişken ismine atanır. Her iki değişkene 42 değerini atıyoruz ve aşağıdaki resimde bulunan iki ayakkabı kutusuna karşılık gelen hafızada iki sayının fiziksel olarak saklandığını görüyoruz.

Box X and Y

X = 42;
y = 42; 

Burada ne olduğunu anlamanın kolay olduğunu düşünüyoruz. Eğer y değişkenine, diyelim ki 78 değerini atarsak:

y = 78;

Assigning a value to a variable in C or Java

değişken y’nin hafıza konumunun içeriğini değiştirmiş oluruz.

C, C++ veya Java gibi dillerde her değişkenin benzersiz bir veri türü vardır ve olmalıdır, yani bir değişkenin türü tamsayı ise, programın çalıştırıldığı süre boyunca yalnızca bu değişken türünde değerler (tamsayılar) kaydedilebilir. Bu programlama dillerinde her değişken kullanılmadan önce belirtilmelidir. Bir değişkenin belirtilmesi (beyan edilmesi), onun bir veri türüne bağlanması anlamına gelir.

Python’da Değişkenler

Python’da işler çok daha kolaydır. Python’da değişkenlerin beyan edilmesi işlemi yoktur. Bu mümkün bile değildir. Bir değişkene ihtiyaç varsa, bir isim düşünürsünüz ve bunu kullanmaya başlarsınız.

Python’un bir başka dikkat çekici özelliği de şudur: Programın çalışması sırasında değişkenin yalnızca değeri değil, aynı zamanda türü de değişebilir. Değişkene tamsayı değeri atanabilir, bir süre ondalık sayı olarak kullanılabilir ve daha sonra da aynı değişkene karakter dizisi atanabilir. Aşağıdaki kod satırında bir değişkene 42 değerini atayacağız:

In [1]:
i = 42

Buradaki eşittir “=” işareti aslında “eşittir” anlamına gelmez ve böyle görülmemelidir. “i değişkeni 42 değerine ayarlandı” örneğinde olduğu gibi, bu işaret “ayarlanmak” olarak yorumlanmalı veya böyle “okunmalıdır”. Şimdi bu değişkenin değerini arttıralım:

In [2]:
i = i + 1
print(i)
43

Yukarıda söylediğimiz gibi, betiğin yürütülmesi sırasında bir değişkenin türü değişebilir. Daha kesin konuşmak gerekirse, herhangi bir türden olabilecek yeni bir nesne bu değişkene atanır. Bu özelliği aşağıdaki örneğimizde görelim:

  • i = 42 # veri türü kesin olarak bir tamsayıya ayarlanmış
  • i = 42 + 0.11 # veri türü kayan noktalı sayı olarak değişmiş
  • i = "forty" # şimdi de bir karakter dizisi olacak

Python “i = 42” gibi bir komutu yürüttüğünde, komutun sağ tarafını değerlendirir ve bir tamsayı olan 42’ye karşılık geldiğini tanır. Bu veriyi saklamak için tamsayı sınıfından bir nesne oluşturur. Nesneler ve sınıflar hakkında daha çok bilgi edinmek isterseniz, Nesne Yönelimli Programlama (Object Oriented Programming) bölümünü okuyabilirsiniz, ancak buna mecbur hissetmeyin. Diğer bir deyişle, Python farklı veri türlerinin fiziksel gösterimlerini otomatik olarak halleder.

Nesne Göndermeleri

Şimdi değişkenler konusuna daha yakından bakacağız. Python değişkenleri nesnelere yapılan göndermelerdir, ancak gerçek veriler nesnelerde saklanır:

Python Variable

Resim çevirisi: “Ben bir Python değişkeniyim. Adım x ve herhangi bir nesneyi gösterebilirim. Burada bir int nesnesini gösteriyorum.”

Değişkenler nesnelere yönlendirildiği için ve nesneler de herhangi bir veri türü alabileceği için, değişkenlerin kendileri ile ilişkilendirilen veri türleri olamaz. Bu C, C++ veya Java’dan çok farklıdır, bu dillerde bir değişken sabit bir veri türü ile ilişkilendirilir. Bu ilişkilendirme, program çalıştırıldığı sürece değiştirilemez.

Bu yüzden, Python’da aşağıdaki kodu yazmak mümkündür:

In [3]:
x = 42
print(x)
42
In [4]:
x = "Şimdi x bir karakter dizisine gönderme yapıyor"
print(x)
Şimdi x bir karakter dizisine gönderme yapıyor

Şimdi x bir karakter dizisine gönderme yapıyor Şimdi farklı birşey göstereceğiz. Aşağıdaki koda bakalım:

In [5]:
x = 42
y = x

42 değerine sahip bir tamsayı nesnesi oluşturduk ve x değişkenine atadık. Bundan sonra da x değişkenini y değişkenine atadık.

Bu her iki değişkenin de aynı nesneye gönderme yaptığı anlamına geliyor. Aşağıdaki görsel bu durumu anlatmaktadır:

Two Python Variables referencing the same object

Resim çevirisi: Sol taraf: Ben bir Python değişkeniyim. Adım x ve herhangi bir nesneyi gösterebilirim. Burada bir int nesnesini gösteriyorum. Sağ taraf: Adım Y ve X değişkeni ile aynı nesneye gönderme yapıyorum”

Aşağıdaki kodu çalıştırdığımız zaman ne olur?

y = 78

Python '78' içeriğine sahip yeni bir tamsayı nesnesi oluşturacak ve y değişkeni aşağıdaki görselden anlayacağınız gibi bu yeni oluşturulmuş nesneye gönderme yapacak:

Assigning a new object to an existing Python Variable

Resim çevirisi: Sol taraf: “Ben hâlâ 42 tamsayı nesnesine gönderme yapıyorum”. Sağ taraf: “Şimdi yeni oluşturulmuş tamsayı nesnesi olan 78’e gönderme yapıyorum”.

Büyük ihtimalle, programımızın akışı esnasında değişkenlerimizin değerlerinde başka değişiklikler de göreceğiz. Örneğin x değişkenine bir kelime dizisi ataması yapabiliriz. Bu atamanın ardından daha önce tamsayı nesnesi olan “42” öksüz kalacaktır. Bu değer Python tarafından silinecektir, çünkü ona gönderme yapan başka bir değişken kalmamıştır.

Python Variable referencing string object

Resim çevirisi: Sol taraf: “Şimdi bir kelime dizisine gönderme yapıyorum!”. Sağ taraf: “Ben hâlâ tamsayı nesnesi olan 78’e gönderme yapıyorum”.

Şimdi kendinize sorabilirsiniz, önceki örneğimizde y = x atamasından sonra x ve y gerçekten de aynı nesneye gönderme yapıp yapmadığını nasıl görebiliriz veya ispatlayabiliriz?

Bu amaçla tanım fonksiyonu id() kullanılabilir. Her olay (nesne veya değişken) bir kimlik numarasına sahiptir; yani bir tamsayının betik içinde benzersiz bir yeri vardır, bir başka deyişle, diğer nesneler farklı numaralara sahiptir. Dolayısıyla önceki örneğimize bakalım ve kimlik numaralarının nasıl değiştiğini görelim:

In [6]:
x = 42
id(x)
Out[6]:
140715239450288
In [7]:
y = x
id(x), id(y)
Out[7]:
(140715239450288, 140715239450288)
In [8]:
y = 78
id(x), id(y)
Out[8]:
(140715239450288, 140715239451440)

Geçerli Değişken İsimleri

Değişkenlerin isimlendirilmesi konusu tanımlayıcı kavramı ile ilgilidir. Bir Python tanımlayıcısı bir değişkeni, fonksiyonu, sınıfı, modülü veya başka bir nesneyi tanımlamak için kullanılan bir isimdir. Bir değişken ismi ve tanımlayıcısı A-Z arası büyük harfler, a-z arası küçük harfler, alt çizgi _ ve ilk karakter hariç olmak üzere 0-9 arası sayılar içerebilir. Python 3.x Unicode esaslı bir dildir. Yani, değişken ve tanımlayıcı isimleri bunlara ilave olarak Unicode karakterleri de içerebilir.

Tanımlayıcıların karakter sınırı yoktur. Büyük-küçük harf önemlidir. Tanımlayıcı isimlerinin büyük-küçük harfe duyarlı olması bazı Windows kullanıcılarına sorun yaşatabilir, çünkü dosya isimleri büyük-küçük harflere karşı duyarlı değildir.

Yukarıdaki kurallar göz önüne alındığında özel Python anahtar kelimelerinin istisna oluşturduğunu görüyoruz ve bunlar daha sonraki paragraflarda görülebilir.

Aşağıdaki değişken tanımlamalarının tamamı geçerlidir:

 
height = 10
maximum_height = 100

υψος = 10
μεγιστη_υψος = 100

MinimumHeight = 1

Python Anahtar Kelimeleri

Yukarıda bahsettiğimiz isimlendirme kurallarına uysalar da tanımlayıcılar şu Python anahtar kelimeleri ile aynı olamaz:

and, as, assert, break, class, continue, def, del, elif, else,
except, False, finally, for, from, global, if, import, in, is, 
lambda, None, nonlocal, not, or, pass, raise, return, True, try, 
while, with, yield
Bunları ezbere bilmek zorunda değilsiniz. Python anahtar kelimelerine etkileşimli kabuktan help komutu ile ulaşabilirsiniz. Komut, parantezler dâhil olmak üzere, help() şeklindedir:

In [ ]:
help()
Welcome to Python 3.7's help utility!

If this is your first time using Python, you should definitely check out
the tutorial on the Internet at https://docs.python.org/3.7/tutorial/.

Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules.  To quit this help utility and
return to the interpreter, just type "quit".

To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics".  Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".

help> and
Boolean operations
******************

   or_test  ::= and_test | or_test "or" and_test
   and_test ::= not_test | and_test "and" not_test
   not_test ::= comparison | "not" not_test

In the context of Boolean operations, and also when expressions are
used by control flow statements, the following values are interpreted
as false: "False", "None", numeric zero of all types, and empty
strings and containers (including strings, tuples, lists,
dictionaries, sets and frozensets).  All other values are interpreted
as true.  User-defined objects can customize their truth value by
providing a "__bool__()" method.

The operator "not" yields "True" if its argument is false, "False"
otherwise.

The expression "x and y" first evaluates *x*; if *x* is false, its
value is returned; otherwise, *y* is evaluated and the resulting value
is returned.

The expression "x or y" first evaluates *x*; if *x* is true, its value
is returned; otherwise, *y* is evaluated and the resulting value is
returned.

Note that neither "and" nor "or" restrict the value and type they
return to "False" and "True", but rather return the last evaluated
argument.  This is sometimes useful, e.g., if "s" is a string that
should be replaced by a default value if it is empty, the expression
"s or 'foo'" yields the desired value.  Because "not" has to create a
new value, it returns a boolean value regardless of the type of its
argument (for example, "not 'foo'" produces "False" rather than "''".)

Related help topics: EXPRESSIONS, TRUTHVALUE

Yardım komut istemini gördüğünüze göre özellikle anahtar kelimeler (“keywords”) hakkinda help> keywords yazarak çokça yardım alabilirsiniz:

False               def                 if                  raise
None                del                 import              return
True                elif                in                  try
and                 else                is                  while
as                  except              lambda              with
assert              finally             nonlocal            yield
break               for                 not                 
class               from                or                  
continue            global              pass                

İsimlendirme Kuralları

“Geçerli Değişken İsimleri” konusunda gördüğümüz gibi bazen birden fazla kelime içeren isimlere ihtiyacımız olabilir. Örneğin “maximum_height” ismini kullandık. Alt çizgi kelimeleri birbirinden ayırıyor, çünkü boşluk karakteri değişken isimlerinde kabul edilmiyor. Bazı kimseler değişken isimlerini “CamelCase” dediğimiz, her kelimenin ilk harfi büyük ve kelimeler birbirine eklenmiş durumda olan yöntemle yazmayı tercih ediyor. Bu isimlendirme stilinde MinimumHeight değişkenini tanımladık.

CamelCase yolunu sevenler ile alt çizgi sevenler arasında süregelmiş bir “savaş” var. Kişisel olarak, isimlendirmenin _doğal_yolu biçimini İsimlendirmeninDoğalYolu biçimine tercih ediyoum. Sanıyorum ki ilk örnek daha kolay okunabilir ve doğal dile daha yakındır.

Başka bir deyişle, CamelCase kelimelerinin okunması, alt çizgiler ile ayrılmış olanlara göre daha zordur, ÖzellikleBunlarÇokUzunsa...

Bunlar pek çok programcı tarafından paylaşılan, ancak kesinlikle herkes tarafından takip edilmeyen kişisel görüşlerimdir. Python Kodu için Stil Rehberi değişken isimleri ve fonksiyon isimleri için alt çizgi notasyonunu tavsiye etmektedir.

Değişken isimleri olarak bazı isimlerden kesinlikle kaçınmak gerekir. Asla, küçük L olan “l” karakterini, Ontario’nun ilk harfi olan “O” karakterini veya Indiana’nın ilk karakteri olan “I” karakterini tek karakterli değişken ismi olarak kullanmayınız. Bunlardan kaçınmamızı tavsiye etmemizin sebebi bu karakterlerin bazı yazı tiplerinde bir ve sıfır karakterlerinden ayrılmasının çok zor olmasıdır. “l” kullanmak isterseniz, ve daha iyi bir isim aklınıza gelmiyorsa, bunun yerine “L” kullanın.

Stil Rehberi standart modüllerde tanımlayıcıların isimlendirilmesi konusunda aşağıdaki açıklamayı yapmıştır:

Python standart kütüphanesinde bulunan bütün tanımlayıcılar mümkün olan her yerde yalnızca ASCII tanımlayıcılarını KULLANMALIDIR (pek çok durumda, İngilizce olmayan kısaltmalar ve teknik terimler kullanılmaktadır). Buna ek olarak, harflerden oluşan diziler de ASCII koduyla oluşturulmalıdır. Bunlara istisna olarak (a) ASCII olmayan özellikleri test eden durumlar ve (b) yazarların isimleri gelmektedir. Latin alfabesi ile yazılmayan isimlere sahip yazarlar, isimlerinin Latin alfabesi ile yazılmış halini de SUNMALIDIRLAR.” Uluslararası kitleye yönelik çalışma yapan şirketler, enstitüler, organizasyonlar veya açık kaynak projeleri benzer bir isimlendirme çalışması yapmalıdır!

Veri Türleri ve Saklama Yerlerinin Değiştirilmesi

Programlama veri işleme demektir. Bir Python programında veriler nesneler ile temsil edilir. Bu nesneler şunlar olabilir: • gömülü, yani Python tarafından sunulan nesneler, • açılım kütüphanelerince sağlanan nesneler • programcının uygulamasında ürettiği nesneler Dolayısıyla farklı veri türleri için farklı “türden” nesnelerimiz vardır. Python’da farklı veri türlerine göz atacağız.

Sayılar

Python’un çekirdeğindeki veri türleri bazen nesne türleri olarak da adlandırılır. Bunlar, sayılar için, dört hazır veri türüne işaret eder:

  • Tamsayı
∙Normal tamsayılar

Örnek: 4321

∙Sekiz tabanlı karakterler (8’li sayı sistemine göre)

Bir adet sıfır “0” ve ardından gelen küçük “o” veya büyük “O” harfi (octal kelimesinden ötürü) sekizli sayı sistemi olarak algılanacaktır.

Örnek:

In [1]:
a = 0o10
print(a)
8
∙Onaltılık karakterler (16’lı sayı sistemine göre)

Onaltılık karakterler “0x” veya “0X” ile başlamalıdır.

Örnek:

In [2]:
hex_number = 0xA0F
print(hex_number)
2575
∙İkili karakterler (2’li sayı sistemine göre)

İkili karakterler de yukarıdaki gibi kolaylıkla yazılabilir. Bunlar da başlarına bir “0” ve “b” ya da “B” alır:

In [3]:
x = 0b101010
x
Out[3]:
42

Bir tamsayıya karşılık gelen ikili, sekizli veya on altılı sistemdeki sayıya çevirmek için bin, oct veya hex fonksiyonları kullanılabilir:

In [4]:
x = hex(19)
x
Out[4]:
'0x13'
In [5]:
type(x)
Out[5]:
str
In [6]:
x = bin(65)
x
Out[6]:
'0b1000001'
In [7]:
x = oct(65)
x
Out[7]:
'0o101'
In [8]:
oct(0b101101)  
Out[8]:
'0o55'

Python3’teki tamsayılar sınırsız boyuta sahip olabilir:

In [9]:
x = 787366098712738903245678234782358292837498729182728
print(x)
787366098712738903245678234782358292837498729182728
In [10]:
x * x * x
Out[10]:
488123970070638215986770162105731315538827586091948617997871122950228891123960901918308618286311523282239313708275589787123005317148968569797875581092352
∙Uzun tamsayılar

Python 2’de int ve long olmak üzere iki tamsayı türü vardır. Artık Python3’de “long int” yok. Python2’den “int” ve “long” içeren sadece bir “int” türü var. Yani aşağıdaki kod Python3’de çalışmayacaktır:

In [11]:
1L
  File "<ipython-input-11-c0812a2707a8>", line 1
    1L
     ^
SyntaxError: invalid syntax
In [12]:
x = 43
long(x)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-12-bad7871d6042> in <module>
      1 x = 43
----> 2 long(x)

NameError: name 'long' is not defined
∙Kayan noktalı sayılar

Örnek: 42.11, 3.1415e-10

∙Karmaşık sayılar

Karmaşık sayılar <gerçek kısım> + <sanal kısım> şeklinde yazılır.

Örnekler:

In [2]:
x = 3 + 4j
y = 2 - 3j
z = x + y
print(z)
(5+1j)

Tamsayı Bölümleri

İki tür tamsayı bölüm işlemi vardır:

• "gerçek bölüm," "/" ile yapılır.
• "taban bölümü", "//" ile yapılır.

Gerçek Bölüm

Gerçek bölümde taksim(/) işlemci işareti olarak kullanılır. Büyük ihtimalle, “bölüm”den beklediğiniz herşeyi karşılayacaktır. Umarız ki aşağıdaki örnekler kendilerini açıklıyordur:

In [14]:
10 / 3
Out[14]:
3.3333333333333335
In [15]:
10.0 / 3.0
Out[15]:
3.3333333333333335
In [16]:
10.5 / 3.5
Out[16]:
3.0

Taban Bölümü

“//” taban bölümü yapar, yani bölünen sayı bölen sayı tarafından bölünür – gerçek bölüm işleminde de bu yapılır, tek fark, sadece taban değerinin döndürülmesidir. Taban değeri, gerçek bölüm işleminin sonucundan daha küçük olan, en büyük tamsayıdır. Bu sayı, bölen veya bölünen, ya da her ikisi kayan noktalı bir sayı ise kayan noktalı olacaktır. Her ikisi de tamsayı ise, sonuç da tamsayı olacaktır. Başka bir deyişle, “//” her zaman eksi sonsuza kısaltılır.

Taban fonksiyonu ile bağlantısı: Matematik ve bilgisayar biliminde, taban fonksiyonu gerçek bir x sayısını alır ve en büyük tamsayı olan ( x ) = ⌊ x ⌋ değerini döndürür, bu sayı x değerinden küçük veya ona eşittir.

Bu matematiksel ve teorik tanımdan dolayı kafanız karıştıysa, aşağıdaki örnekler umarız ki yardımcı olur:

In [17]:
9 // 3
Out[17]:
3
In [18]:
10 // 3
Out[18]:
3
In [19]:
11 // 3
Out[19]:
3
In [20]:
12 // 3
Out[20]:
4
In [21]:
10.0 // 3
Out[21]:
3.0
In [22]:
-7 // 3
Out[22]:
-3
In [23]:
-7.0 // 3
Out[23]:
-3.0

Karakter Dizileri

Strings in Action

Kırklı ve ellili yıllarda ilk nesil bilgisayarlar teknik sınırlamalar nedeniyle sayı işleme üzerine odaklanmıştı. Metin işlemek o zamanlarda sadece bir hayaldi. Günümüzde, bilgisayarların temel görevlerinden birisi bütün çeşitlerdeki metinleri işlemektir; Google gibi arama motorları en önde gelen uygulamalardır. Metin işlemeyi başlatmak için programlama dilleri uygun veri tiplerine ihtiyaç duyar. Karakter dizileri, metin bilgilerini saklamak ve işlemek için bütün modern programlama dilleri tarafından kullanılır. Mantıksal olarak, bir karakter dizisi, herhangi bir metin gibi – bir seri karakterden oluşur. Soru, bir karakterin ne içerdiği konusudur. Bir kitapta veya şu anda okuduğunuz metinde, karakterler grafik şekiller (graphemes), çizgiler, eğriler ve kesişmelerin belli açılar veya konumlarda gerçekleşmesi vs. ile oluşmaktadır. Eski Yunanlar bu kelimeyi sikkeler veya damgalar üzerine vurarken kullanmıştır.

Bilgisayar biliminde veya bilgisayar teknolojisinde, bir karakter bir bilgi birimidir. Bu karakterler yazıbirimlere karşılık gelir, bunlar yazılı veya basılı dillerin birimleridir. Unicode kullanılmaya başlanmadan önce, baytlar ile karakterler arasında birebir ilişki vardı.Böyle bir karakter baytı bu karakterin mantıksal kavramını ve bu karakterin yazıbirim sınıfını gösterir.

Sağ taraftaki görselde, “A” harfinin çeşitli şekillerini gösteriyoruz.

The Letter A

Dolayısıyla A harfinin soyut kavramının farklı “kodlanması” veya farklı grafik temsilleri vardır. (Bu arada, “A” harfi ters bir öküzün çizimini içeren Mısır hiyeroglifi olarak düşünülebilir). Bütün bu grafik temsillerin ortak yanları vardır. Yani, bir karakterin anlamı ya da yazılan veya basılan bir metin, kullanılan yazıtipine veya yazım şekline bağlı değildir. Bir bilgisayarda büyük A harfi ikili sistemde kodlanır. ASCII kullanırsak, diğer bütün karakterler gibi, bu karakter de 65 baytı ile kodlanır.

ASCII 128 karakterle sınırlıdır ve “Geliştirilmiş ASCII” hâlâ 256 bayt veya karaktere sahiptir. Bu İngilizce, Almanca ve Fransızca gibi diller için yeterlidir, ancak Çince, Japonca ve Korece gibi diller için kesinlikle yetersizdir. İşte burada Unicode devreye giriyor. Unicode, her dilden her karakteri temsil etmek için tasarlanan bir standarttır, yani dünyadaki yazım sistemlerinden herhangi birini işleyebilir. Bu yazım sistemleri de aynı anda kullanılabilir, örneğin Roman alfabesi Kiril ve hattâ Çin karakterleri ile beraber yazılabilir. Unicode için bu durum farklıdır. Bir karakter bir kod noktasını eşler. Mesela, “A” karakteri U+0041 kod noktasına eşlenmiştir. U+ “Unicode” anlamına gelir, “0041” ise bir onaltısal sayıdır, ondalık sistemde 65’e karşılık gelir.

Python’da bunu şöyle dönüştürebilirsiniz:

In [24]:
hex(65)
Out[24]:
'0x41'
In [25]:
int(0x41)
Out[25]:
65

Unicode’de her bir karakter için dört bayta kadar kullanım mümkündür. Teorik olarak, bu 4.294.967.296 olası karakterdir. UTF-16 kodlamasından gelen kısıtlamalardan ötürü, olası karakter sayısı “yalnızca” 1.112.064’tür. Unicode 8.0 sürümü 120.737 karakter atamıştır. Bütün olası karakter sayısının %10’undan biraz fazlası girilmiş durumdadır. Yani Unicode’a hâlâ neredeyse bir milyon karakter ekleyebiliriz.

Unicode Kodlamaları

Ad Açıklama
UTF-32 Bu birebir kodlamadır, yani her Unicode karakterini alır (4 baytlık bir sayı) ve 4 bayt olarak saklar. Bu kodlama yönteminin bir avantajı n’inci karakteri bir dizinin içinde doğrusal zamanda bulabilmenizdir, çünkü n’inci karakter 4xn’inci baytta başlar. Bu yaklaşımın ciddi bir dezavantajı ise her bir karakter için dört bayta ihtiyaç duymasıdır.
UTF-16 UTF-16 (16 Bit Unicode Dönüşüm Biçimi) Unicode’un bütün 1.112.064 geçerli kod noktasının kodlanmasını sağlayabilecek bir sistemdir. Kodlama değişken uzunluğuna göre çalışır, çünkü kod noktaları bir veya iki 16-bitlik kod birimleri ile kodlanmıştır.
UTF-8 UTF8 Unicode’un değişken uzunluklu kodlama sistemidir, yani farklı karakterler farklı bayt sayısına sahiptir. ASCII karakterleri tam olarak bir karaktere bir bayt kullanır. Bu, UTF8’in ilk 128 karakterinin ASCII tarafından farklılaştırılamaması anlamına gelir. “Geliştirilmiş Latince” olarak bildiğimiz karakterler, örneğin çift noktalı a (ä), ö ve diğerleri iki bayt almaktadır. Çince karakterler üç bayta ihtiyaç duyar. Son olarak çok nadiren kullanılan karakterler UTF-N’de dört bayt ile kodlanır. [W3Techs](https://w3techs.com/technologies/overview/character_encoding)'e (Web Teknoloji Anketleri) göre, “Karakter kodlamasını bildiğimiz bütün websitelerinin %94,3’ü tarafından UTF-8 kullanmaktadır” .

Karakter dizisi, Unicode ve Python

Bu uzun ancak gerekli girişten sonra, Python’a geliyoruz ve onun karakter dizileri ile nasıl uğraştığını öğreneceğiz. Python3’de bütün karakter dizileri “saf” Unicode karakterlerinin birleşiminden oluşur, UTF-8 gibi özgün kodlama yöntemleri kullanılmaz. Python’da karakter dizilerinin tanımlanmasında farklı yöntemler vardır:

In [26]:
s = 'Ben tek tırnaklar arasındaki bir karakter dizisiyim'
s2 = "Ben de başka bir karakter dizisiyim, ancak çift tırnaklar arasındayım"

Hem s, hem de s2 karakter dizisi nesnelerine gönderme yapan değişkenlerdir. Harflerden oluşan dizilerin tek (‘) veya çift (“) tırnak işaretleri arasına alınabeleceğini öğrendik. Karakter dizisi tek tırnaklar arasında belirtilmiş ise ve içeride başka bir tek tırnak kullanılıyorsa ters bölü \ işareti kullanılmalıdır:

In [27]:
s3 = 'It doesn\'t matter!'

Karakter grubu çift tırnaklar arasına alınmış ise buna gerek yoktur:

In [28]:
s3 = "It doesn't matter!"

Benzer şekilde, çift tırnaklar arasına alınmış bir karakter dizisi içinde çift tırnak kullanımında ters bölü işareti kullanılmalıdır:

In [29]:
txt = "He said: \"It doesn't matter, if you enclose a string in single or double quotes!\""
print(txt)
He said: "It doesn't matter, if you enclose a string in single or double quotes!"

Ayrıca üçlü tek veya üçlü çift tırnak işaretleri de kullanılabilir. Bu durumda üçlü tırnak içeren karakter dizileri elde edilmiş oluyor. Ters bölü \ karakteri, yeni satır, ters bölü veya tırnak karakteri gibi başka zaman özel bir anlama gelecek karakterlerden kaçış sağlamak için kullanılır.

 
txt = '''Üç tırnak içindeki bir karakter dizisi
bunun gibi çok satıra yayılabilir ve 
'tek' and "çift" tırnaklar içerebilir.'''
Üç tırnaklı (‘ veya “) karakter dizilerinde, kaçış yapılmamış yeni satırlar ve tırnaklara izin verilir (ve bunlar saklanır), ancak yan yana üç kere tırnak işareti kullanılırsa karakter dizisi sona erer.

Positive and negative indices of strings

Bir karakter dizisi Python’da harf, rakam ve özel karakterleri içerebilir. Karakter dizileri indislenebilir ve indekslenebilir. C’ye benzer olarak, bir karakter dizisinin ilk karakteri 0 indeksine sahiptir.

In [30]:
s = "Merhaba Dünya"
s[0]
Out[30]:
'M'
In [31]:
s[7]
Out[31]:
' '

Bir karakter dizisinin son karakterine şu şekilde erişilebilir:

In [32]:
s[len(s)-1]
Out[32]:
'a'

ancak Python’da daha kolay bir yol vardır. Son karaktere -1 ile erişilebilir, sondan bir öncekine -2 ile erişilebilir ve böyle devam eder:

In [33]:
s[-1]
Out[33]:
'a'
In [34]:
s[-2]
Out[34]:
'y'

Bazı okuyucular, “altindisleme” (subscripting) terimini “indeksleme” ile eşanlamlı olarak kullanmamızı kafa karıştırıcı bulabilir. Genel olarak, altindis bir sayı, şekil, sembol veya indikatörün boyutunun yazıtipinden daha küçük olduğu ve yukarıda ya da aşağıda konumlandığı duruma verilen addır. s[0] veya s[3] yazdığımızda (önceki örneklere bakınız), s0 veya s3 yazmanın alternatif bir yolu olarak görülebilir. Bu yüzden s3 ve s[3] dördüncü karakteri gösterir. Bu arada, Python’da karakter türü yoktur. Bir karakter, bir boyutlu karakter dizisinin üyesidir.

String Indexing or subscripting

Daha önce bahsettiğimiz gibi indisleri sağdan başlayarak sayabilirsiniz. Bu durumda negatif sayılar kullanılır ve en sağdaki karakter için -1 verilir.

Negative String indices from the right

Karakter dizileri için bazı operatörler ve fonksiyonlar

  • Birleştirme
    “+” operatörü ile karakter dizileri birbiriyle birleştirilebilir: "Merhaba" + "Dünya" birleştirilince "MerhabaDünya” olur.
  • Tekrarlama
    Karakter dizisi “” (asterisk) operatörü ile tekrarlanabilir veya tekrarlanarak birleştirilebilir: "-" 3 şu sonucu verir: "---"
  • İndeksleme
    "Python"[0] "P" sonucunu verir.
  • Dilimleme
    Dilim veya dilimleme işlemi ile alt karakter dizileri oluşturulabilir. Yani birbirinden iki nokta üst üste (:) işareti ile ayrılmış iki indeks ile dilimleme yapılabilir: "Python"[2:4] ile "th" elde edilir.
    String Slicing
  • Boyut
    len("Python") 6 sonucunu verir.

Karakter Dizilerinin Değişmezliği

Java’daki karakter dizileri gibi, ancak C ile C++’dan farklı olarak, Python dizileri değiştirilemez. Bir indeks konumunda değişiklik yapılmaya çalışıldığında hata mesajı alınır:

In [35]:
s = "Bazı şeyler değişmez!"
s[-1] = "."
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-35-34c1e73a7d0a> in <module>
      1 s = "Bazı şeyler değişmez!"
----> 2 s[-1] = "."

TypeError: 'str' object does not support item assignment

Python’a yeni başlayanlar sıklıkla aşağıdaki kodu görünce şaşırır:

In [37]:
txt = "O Berlin’de yaşıyor!"
txt = "O Hamburg’da yaşıyor!"

“txt” değişkeni bir karakter dizisine gönderme yapar. İkinci komutta ise tamamen yeni bir karakter dizisi nesnesi tanımlıyoruz. Bu sebeple değişken ismiyle gönderme yapılan nesneyi karıştırmamalısınız!

Bir Karakter Dizisi Garipliği

Karakter dizilerinın ilginç bir özelliği vardır, bunu aşağıdaki örnekte göreceğiz. İhtiyaç duyacağımız şey “is” operatörüdür. Eğer a ve b karakter dizisi ise, “a is b” aynı türden mi diye kontrol edilir, yani aynı hafıza konumunu paylaşıyor mu diye bakılır. Eğer “a is b” True (Doğru) ise, önemsiz bir şekilde “a == b” önermesinin de True olması beklenir. Ancak “a == b” önermesinin Doğru olması, “a is b” önermesinin Doğru olmasını gerektirmez! Gelin Python’da karakter dizilerinin nasıl saklandığına bakalım:

In [38]:
a = "Linux"
b = "Linux"
a is b
Out[38]:
True

Peki, karakter dizileri daha uzun olursa ne yaparız? Aşağıdaki örnekte dünyadaki en uzun köy ismini kullanacağız. Burası Galler’in kuzeybatısında, Anglesey adasının güneyinde, 3000 nüfuslu küçük bir köydür:

In [39]:
a = "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"
b = "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"
a is b
Out[39]:
True

“Linux” örneğimizle karşılaştırırsak hiçbir şey değişmedi. Ancak Galler için işe yarayan şey Almanya’daki Baden-Württemberg için yaramıyor:

In [40]:
a = "Baden-Württemberg"
b = "Baden-Württemberg"
a is b
Out[40]:
False
In [41]:
a == b
Out[41]:
True

Haklısınız, bunun coğrafi yerler ile hiçbir ilgisi yok. Özel karakter(ler) örneğin tire işareti burada “suçlu” olan şey.

In [42]:
a = "Baden!"
b = "Baden!"
a is b
Out[42]:
False
In [43]:
a = "Baden1"
b = "Baden1"
a is b
Out[43]:
True

Karakter Katarlarında Kaçış Dizileri

Bu bölümde karakter katarları konusunu bitirirken, bazı kaçış karakterleri ve dizilerine bakacağız. Ters bölü (\) karakteri, karakterlerden kaçmak için kullanılır, yani başka türlü bu karakterin sahip olabileceği özel anlamlardan “kaçmaya” yarar. Bunun için örnek olarak yeni satır karakteri, ters bölü karakterinin kendisi veya tırnak işareti verilebilir. Harf dizileri isteğe bağlı olarak ‘r’ veya ‘R’ alabilir; bu karakter katarlarına ham karakter katarı denir. Ham karakter katarları ters bölü kaçış dizileri için farklı kurallar kullanır.

Kaçış Dizisi Anlam
\newline Gözardı edilir
\\ Ters bölü (\)
\' Tek tırnak (')
\" Çift tırnak (")
\a ASCII Düdük(BEL)
\b ASCII Geri silme(BS)
\f ASCII Sayfa Besleme (FF)
\n ASCII Satır Besleme (LF)
\N{name} Unicode veritabanında isimlendirilen karakter (yalnızca Unicode)
\r ASCII Satır Başı (CR)
\t ASCII Yatay Sekme (TAB)
\uxxxx 16-bit onaltılık değere karşılık gelen karakter (Yalnızca Unicode)
\Uxxxxxxxx 32-bit onaltılık değere karşılık gelen karakter (Yalnızca Unicode)
\v ASCII Dikey Sekme (VT)
\ooo Sekizli sayı düzeninde ooo değerinin karşılık geldiği karakter
\xhh Onaltılık düzende hh değerinin karşılık geldiği karakter

Bayt Karakter Dizileri

Python 3.0 Unicode ve 8-bit karakter dizileri yerine metin ve (ikili) verileri kullanır. Python3’te her karakter dizisi veya metin Unicode’dur, ancak kodlanmış Unicode ikili düzende veri olarak temsil edilir. Metin tutmak için kullanılan tür str’dir, verileri tutmak için kullanılan tür ise bayttır. Python3’te metin ve veriyi birleştirmek mümkün değildir; bu durumda TypeError hatası oluşur. Bir karakter dizisi nesnesi Unicode olarak bir seri karakter tutarken, bir bayt nesnesi bir seri baytı tutar, aralık 0 .. 255’tir ve ASCII değerlerine karşılık gelir.

Bayt nesnelerini tanımlayalım ve karakter dizilerine dönüştürelim:

In [12]:
x = "Hallo"
t = str(x)
u = t.encode("UTF-8")
print(u)
b'Hallo'
In [46]:
xx=20
print(xx)
20