♻️ Temel Tür Dönüşümleri

12-1.18.24

Tür dönüştürme, type conversion ya da type cast olarak geçmektedir.

Python’da tüm atama işlemlerinin adres ataması olduğunu konuşmuştuk.

a = 3.14 dediğimiz zaman aslında değeri 3.14 olan bir float nesnesi oluşuyor ve adresi a değişkenine atanıyordu.

Bazen şunu da isteyebiliriz: a nın gösterdiği yerdeki nesnenin türü float ama biz onu int olarak ele almak isteyebiliriz. İşte bu işlem tür dönüştürmedir.

Tür dönüştürme, bir nesnenin içerisindeki değeri değiştirerek başka bir türden bir nesne biçiminde elde edilmesi olarak tanımlanabilir.


Python’da gördüğümüz int, float, bool gibi türler aslında birer sınıftır ve biz bu sınıflardan birer nesne (OOP’deki O anlamında nesne) yaratmış oluyoruz.

Tür dönüştürme

<dönüştürülecek hedef tür>(<ifade>)

şeklinde yapılmaktadır.

Örneğin

a = 3.14
b = int(a)

şeklinde yapmaktayız. Bunu bir fonksiyon çağrısı olarak ele alabiliriz.


Tür dönüştürme işlemiyle yeni bir nesne yaratılmaktadır. Her tür dönüştürme işlemi, yeni bir nesne yaratır. Yani var olan nesnenin türü değiştirilerek yapılmamaktadır, nesnenin immutable ya da mutable olması konusu değil. Var olan nesnenin değerinden yeni bir nesnenin yaratılmasını sağlamaktadır.

>>> x = 10
>>> y = float(x)

>>> print(id(x), id(y))
1754405759568 1754415633136

>>> print(type(x), type(y))
<class 'int'> <class 'float'>

Görüldüğü gibi ikisi de farklı nesnedir.


T bir tür belirtmek üzere T türünden bir nesnenin yaratılması T(...) biçiminde bir ifadeyle yapılmaktadır. Bu ileride göreceğimiz bir konudur.


Eğer bir ifade aynı türe dönüştürülüyorsa ve o tür değiştirilemez bir tür ise, temel türler gibi, Python implementasyonu yeni bir nesne yaratmayabilir. Bu, ilgili implementasyonun kendi içerisinde yaptığı optimizasyon ile ilgilidir.

>>> x = 4
>>> y = int(4)
>>> x is y
True

Örneğin yukarıda görebileceğimiz gibi CPython benim sistemimde yeni bir nesne yaratmadı, yaratabilirdi ama.


Python’daki temel türler, yani şimdiye kadar gördüklerimiz, T(...) biçiminde birbirlerine dönüştürülebilmektedir. Elbette programcının bu dönüşümün sonucunda nelerin olacağını bilmesi gerekir. Hadi gelin, durumlara bir bakalım.

Nereden ↓ / Nereye →

int

float

bool

str

complex

NoneType

int

🟢

🚫

float

🟢

🚫

bool

🟢

🚫

str

🟢

🚫

complex

🚫

🚫

🟢

🚫

NoneType

🚫

🚫

🚫

🚫

  • ✅ ile işaretlenen dönüşümler bu yazıda anlatılmaktadır ve legaldir.

  • 🚫 ile işaretlenen dönüşümler bu yazıda anlatılmakta fakat illegaldir.

  • 🟢 NoneType hariç diğer türler kendi içinde dönüştürülebilmektedir. Hoş, pek anlamlı değildir.


floatint

Bu dönüşümde nokta, ., dan sonraki kısım atılır. Bu, truncation toward zero yaklaşımıdır. Herhangi bir tarafa yuvarlama, floor ya da ceil, yapılmaz. Sayının negatif ya da pozitif olması sonucu değiştirmez.

>>> int(3.89)
3

>>> int(-3.89)
-3

Burada C gibi dillerden farklı olarak lehimize bir durum vardır. C gibi dillerde bir int nesne, float bir sayının tam sayı kısmını tutamayabilir, aralığı yeterli olmayabilir, tanımsız davranış oluşabilir. Python’da ise int nesnelerin tutabileceği değerlerin bir sınırı olmadığı için böyle bir derdimiz yoktur.

boolint

12-1.37.10

bool bir nesne iki farklı değer tutabilir, True ve False. Eğer inte dönüşüm yapılırsa, True değer 1, False ise 0 olarak dönüştürülür.

>>> print(int(True))
1

>>> print(int(False))
0

strint

12-1.38.35

Eğer bir string içerisinde, tam sayıya dönüşüm için anlamlı olacak karakterler varsa yeni bir int nesne yaratılır ve yazı aslında sayıya dönüştürülmüş olur. Fakat sayıya dönüştürülemeyecek karakterler içeriyorsa bu durumda bir exception, ValueError, oluşur. Exception konusunda biraz konuşmuştuk. Programcı bunu ele almazsa bu durumda program sonlanmaktadır.

Bir yazının başındaki boşluk karakterlere leading space, yazının sonundaki karakterler ise trailing space denmektedir. Bu dönüşüm sırasında ilgili boşluklar, white space, dikkate alınmaz, problem oluşturmaz.

>>> print(int('120'))
120

>>> print(int(' 1234     '))
1234

>>> print(int('-42'))
-42

>>> print(int('120.55'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '120.55'

>>> print(int('alper'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'alper'

Burada yazının onluk sayı sisteminde olması şart değildir. İstersek int() fonksiyonunu çağırırken ikinci parametre olarak dönüşümün hangi tabanda olacağını belirtebiliriz.

>>> print(int('0f'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '0f'

>>> print(int('0f', 16))
15

>>> print(int('0x0f', 16))
15

Hatta print(int('g', 17)) gibi gariplikler de yapabiliriz. 😬

complexint 🚫

complex tür, int türüne dönüştürülememektedir.

>>> print(int(3+4j))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert complex to int

NoneTypeint 🚫

NoneType türünde olan tek değer olan None, int e dönüştürülememektedir.

>>> print(int(None))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

int bir ifadenin int türüne dönüştürülmesi geçeli fakat anlamsızdır, aynı değer elde edilir.


intfloat

12-2.02.30

int bir değer float türüne dönüştürülürken eğer sayı IEEE 754 double-precision format ile “kayıpsız” ifade edilebiliyorsa sayının sonuna .0 gelmiş gibi dönüştürülür. Fakat Python’da int sayıların aslında bir sınırının olmadığnı söylemiştik, diğer programlama dillerinina aksine. İşte bu durumda bir int değer float değerin tutamayacağı kadar büyük bir değeri tutuyor olabilir. Bu durumda ise OverflowError exception oluşmaktadır. Mesela C’deki long long türünü ele alalım, tipik olarak 8 byte olmaktadır. Bu byte adedinin tutabileceği tüm sayılar zaten kayar noktalı formatta ifade edilebilmektedir.

Bundan bağımsız olarak bu dönüşümde bir durum daha vardır kayar noktalı sayıların formatı ile ilgilidir ve dilden bağımsızdır. Daha önceden de konuştuğumuz gibi kayar noktalı sayılar tüm sayıları kusursuzca ifade edememektedir. Bu durumda int bir sayı float olarak ifade edilemese bile mantis, fraction, yani hiç noktalı kısımlar olmasaydı sayı nasıl olurdu kısmı, kaybıyla en yakın float sayı ile ifade edilir. Bu durumda bir exception oluşmaz.

Örneğin

>>> x = 12345678901234567890
>>> y = float(x)
>>> int(y)
12345678901234567168
>>> x - int(y)
722

Bu örnekte x e atadığımız değer önce float bir değere çevrilmiş daha sonra bu değerden tekrar int değere dönünce ilk orijinal değere ulaşılamamıştır. Nedeni, ilk int float dönüşüm sıraında kayıp yaşanmasıdır. Ama bu durum bir exception oluşturmaz.

Özetle int float dönüşümünde:

1️⃣ Sayı float formatı ile kayıpsız ifade edilebiliyorsa sonuna .0 konmuş olur.

2️⃣ Kayıplı ifade edilebilir, en yakın değere dönüştürülür ama exception oluşmaz. “En yakın değer”, dönüştürülen sayıdan büyük ya da küçük olabilir, bunun detayları ayrıca ele alınmalıdır.

3️⃣ Değer sınırı aşıyorsa OverflowError Exception oluşur.

boolfloat

bool bir nesne iki farklı değer tutabilir, True ve False. Eğer floata dönüşüm yapılırsa, True değer 1.0, False ise 0.0 olarak dönüştürülür.

>>> print(float(True))
1.0

>>> print(float(False))
0.0

strfloat

strint dönüşümü gibi bu dönüşüm de benzer bir şekilde yapılır. Eğer stringin içerisindeki karakterler yani tutulan yazı float türden ifade edilen bir sayı biçimindeyse dönüşüm yapılır. Eğer karakterler anlamsız ise ValueError exception oluşur.

Dönüşüm yaptığımız float() fonksiyonu tek parametrelidir, int() fonksiyonunun aksine ikinci argüman ile taban bilgisi geçilmez.

Bu dönüşüm sırasında float türü ile ifade edilemeyecek çok büyük ya da çok küçük sayıların yazısal karşılıklarının nasıl dönüştürüleceği Python Standard Library Reference içerisinde açıkça belirtilmemiştir. CPython implementasyonunun bu gibi durumlarda +inf ya da -inf değerlerini ürettiğini söyleyebiliriz. Yine inte dönüşümde olduğu gibi yazı içerisindeki leading space ya da trailing space göz ardı edilir.

Örneğin:

>>> x = ' 123.567  '
>>> y = float(x)
>>> y
123.567

>>> x = '123.a'
>>> float(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: '123.a'

>>> x = '0x10'
>>> float(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: '0x10'

complexfloat 🚫

complex tür, float türüne dönüştürülememektedir.

>>> print(float(3+4j))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: float() argument must be a string or a real number, not 'complex'

NoneTypefloat 🚫

NoneType türünde olan tek değer olan None, float e dönüştürülememektedir.

>>> print(float(None))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: float() argument must be a string or a real number, not 'NoneType'

Şimdi bool türüne olan dönüşümlere bakalım.


intbool

13-0.00.00

Eğer int değer 0 dışı bir değerse, pozitif ya da negatif fark etmez, True eğer 0 ise False olarak dönüştürülür.

>>> print(bool(3))
True

>>> print(bool(-3))
True

>>> print(bool(0))
False

>>> print(bool(-0))
False

floatbool

int dönüşümü ile benzerdir. Sayı 0.0 değilse True, 0.0 ise False olur.

>>> print(bool(3.5))
True

>>> print(bool(-3.0))
True

>>> print(bool(0.0))
False

>>> print(bool(-0.0))
False

strbool

Eğer string boş ise dönüşüm False, dolu ise True olarak yapılır. Burada string içerisindeki yazıya bakılmaz. Yani 'False' yazısı dolu bir yazı olduğu için True olarak dönüştürülür.

>>> print(bool('False'))
True

>>> print(bool(''))
False

>>> print(bool(' '))
True

complexbool

Eğer hem gerçek hem de sanal kısmı 0 değilse dönüşüm True, her iki kısım da 0 ise False olarak yapılır.

>>> print(bool(3 + 4j))
True

>>> print(bool(3 + 0j))
True

>>> print(bool(0 + 4j))
True

>>> print(bool(0 + 0j))
False

NoneTypebool

NoneType türünde olan tek değer olan None, bool türüne False olarak dönüştürülür.

>>> print(bool(None))
False

Diğer Veri Türleri → bool

Henüz görmedik ama yakında göreceğimiz liste, demet, sözlük, küme gibi veri yapıları eğer boş ise False, dolu ise True olarak bool türüne dönüştürülür.

>>> x = (10, 20)

>>> type(x)
<class 'tuple'>

>>> print(bool(x))
True

intcomplex

13-0.19.38

Bu dönüşüm yapılabilir, sanal kısmı 0 olan bir complex sayı elde edilir.

>>> print(complex(3))
(3+0j)

floatcomplex

Bu dönüşüm yapılabilir, sanal kısmı 0 olan bir complex sayı elde edilir.

>>> print(complex(3.0))
(3+0j)

boolcomplex

Bu dönüşüm yapılabilir, sanal kısmı 0 olan bir complex sayı elde edilir. Eğer bool türünün değeri True ise gerçek kısım 1, False ise 0 olmaktadır.

>>> print(complex(True))
(1+0j)

>>> print(complex(False))
0j

Dikkat

complex türündeki sayıların gerçek ve sanal kısımları aslında ayrı ayrı birer float sayı olarak düşünülebilir. Fakat yazdırılırken düzgün gözüksün diye eğer sayıda nokta yoksa . kullanılmamaktadır. Ama her durumda arka planda iki adet float sayıdan oluştuğunu düşünebiliriz. Dönüşüm ile elde ediyorsak kaynak tür ne olursa olsun bu böyledir.

strcomplex

Bu dönüşümün olması için yazının a±bj formatında olması gerekmektedir. Yine diğer dönüşümlerde olduğu gibi leading ve trailing space karakterleri dikkate alınmaz ama yazının ortasında boşluk olmamamlıdır.

>>> print(complex('3+4j'))
(3+4j)

>>> print(complex('  3+4j '))
(3+4j)

>>> print(complex('3-4j'))
(3-4j)

>>> print(complex('3- 4j'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string

>>> print(complex('4j+3'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string

>>> print(complex('4j-3'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string

NoneTypecomplex 🚫

NoneType türünde olan tek değer olan None, complex e dönüştürülememektedir.

>>> print(complex(None))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: complex() first argument must be a string or a number, not 'NoneType'

intstr

Sayının yazı formu elde edilir.

>>> x = str(5)
>>> x
'5'

floatstr

Sayının yazı formu elde edilir.

>>> x = str(5.5)
>>> x
'5.5'

boolstr

True değer 'True', False değer ise 'False' olarak çevirilir.

>>> x = str(True)
>>> x
'True'

>>> x = str(False)
>>> x
'False'

complexstr

Sayının yazı formu elde edilir.

>>> x = str(4j + 3)
>>> x
'(3+4j)'

complex sayıların bj + a formunda da ifade edilebildiğine fakat dönüşümün a+bj formatında yapıldığında dikkat ediniz.

NoneTypestr

NoneType türünde olan tek değer olan None, stringe 'None' olarak dönüştürülür.

>>> x = str(None)
>>> x
'None'

NoneType Türüne Dönüşüm 🚫

NoneType türünden tek değer olan None dahil olmak üzere hiçbir tür NoneType türüne dönüştürülemez.

>>> print(NoneType(None))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'NoneType' is not defined

>>> print(NoneType(4))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'NoneType' is not defined

13-0.39.50

Argümansız Tür Dönüşüm Fonksiyonları

Tür dönüşümü için gördüğümüz int(), float() gibi fonksiyonları argümansız çağırdığımız zaman bize sabit değerli nesneler verirler.

Fonksiyon

Değer

int()

0

float()

0.0

str()

''

complex()

0j

bool()

False

>>> print(int())
0
>>> print(float())
0.0
>>> print(str())

>>> print(complex())
0j
>>> print(bool())
False

gibi.