4. Daha Fazla Kontrol Akışı Aracı¶
Az önce tanıtılan while
deyiminin yanı sıra Python, bazı değişikliklerle birlikte diğer dillerden bilinen olağan akış kontrol deyimlerini kullanır.
4.1. if
İfadeleri¶
Belki de en iyi bilinen deyim türü if
deyimidir. Örneğin:
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
... x = 0
... print('Negative changed to zero')
... elif x == 0:
... print('Zero')
... elif x == 1:
... print('Single')
... else:
... print('More')
...
More
Sıfır veya daha fazla elif
bölümü olabilir ve else
bölümü isteğe bağlıdır. ‘elif
’ anahtar sözcüğü ‘else if’ ifadesinin kısaltmasıdır ve aşırı girintiden kaçınmak için kullanışlıdır. Bir if
… elif
… elif
… dizisi, diğer dillerde bulunan switch
veya case
deyimlerinin yerine geçer.
4.2. for
İfadeleri¶
Python’daki for
deyimi, C veya Pascal’da alışkın olduğunuzdan biraz farklıdır. Her zaman sayıların aritmetik ilerlemesi üzerinde yineleme yapmak (Pascal’daki gibi) veya kullanıcıya hem yineleme adımını hem de durma koşulunu tanımlama yeteneği vermek (C gibi) yerine, Python’un for
deyimi, herhangi bir dizinin (bir liste veya bir dize) öğeleri üzerinde, dizide göründükleri sırayla yineler. Örneğin (kelime oyunu yapmak istemedim):
>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
... print(w, len(w))
...
cat 3
window 6
defenestrate 12
Aynı koleksiyon üzerinde yineleme yaparken bir koleksiyonu değiştiren kodun doğru yazılması zor olabilir. Bunun yerine, koleksiyonun bir kopyası üzerinde döngü yapmak veya yeni bir koleksiyon oluşturmak genellikle daha kolaydır:
# Strategy: Iterate over a copy
for user, status in users.copy().items():
if status == 'inactive':
del users[user]
# Strategy: Create a new collection
active_users = {}
for user, status in users.items():
if status == 'active':
active_users[user] = status
4.3. range()
Fonksiyonu¶
Bir sayı dizisi üzerinde yineleme yapmanız gerekiyorsa, yerleşik range()
fonksiyonu kullanışlı olur. Aritmetik ilerlemeler üretir:
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
Verilen bitiş noktası asla oluşturulan dizinin bir parçası değildir; range(10)
10 değer üretir, 10 uzunluğundaki bir dizinin öğeleri için yasal indisler. Aralığın başka bir sayıdan başlamasına izin vermek veya farklı bir artış (negatif bile olsa; bazen buna ‘adım’ denir) belirtmek mümkündür:
>>> list(range(5, 10))
[5, 6, 7, 8, 9]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(-10, -100, -30))
[-10, -40, -70]
Bir dizinin indisleri üzerinde yineleme yapmak için range()
ve len()
öğelerini aşağıdaki gibi birleştirebilirsiniz:
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
... print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb
Ancak bu tür durumların çoğunda enumerate()
fonksiyonunu kullanmak uygundur, bkz Döngü Teknikleri.
Sadece bir aralık yazdırırsanız garip bir şey olur:
>>> range(10)
range(0, 10)
Birçok yönden range()
tarafından döndürülen nesne bir listeymiş gibi davranır, ancak aslında öyle değildir. Üzerinde yineleme yaptığınızda istenen dizinin ardışık öğelerini döndüren bir nesnedir, ancak listeyi gerçekten oluşturmaz, böylece yerden tasarruf sağlar.
Böyle bir nesnenin iterable olduğunu, yani arz tükenene kadar ardışık öğeler elde edebilecekleri bir şey bekleyen fonksiyonlar ve yapılar için bir hedef olarak uygun olduğunu söylüyoruz. Daha önce for
deyiminin böyle bir yapı olduğunu görmüştük, bir yinelenebilir alan bir fonksiyon örneği ise sum()
:
>>> sum(range(4)) # 0 + 1 + 2 + 3
6
Daha sonra yinelenebilirleri döndüren ve argüman olarak yinelenebilirleri alan daha fazla fonksiyon göreceğiz. Veri Yapıları bölümünde, list()
hakkında daha ayrıntılı olarak tartışacağız.
4.4. break
ve continue
İfadeleri ve else
Döngülerdeki Cümleler¶
C’de olduğu gibi break
deyimi, en içteki for
veya while
döngüsünü keser.
Döngü deyimleri bir else
cümlesine sahip olabilir; bu cümle döngü yinelenebilirin tükenmesiyle sonlandığında (for
ile) veya koşul yanlış olduğunda (while
ile) çalıştırılır, ancak döngü bir break
deyimiyle sonlandırıldığında çalıştırılmaz. Bu, asal sayıları arayan aşağıdaki döngü ile örneklendirilmiştir:
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print(n, 'equals', x, '*', n//x)
... break
... else:
... # loop fell through without finding a factor
... print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
(Evet, bu doğru koddur. Yakından bakın: else
cümlesi for
döngüsüne aittir, değil if
deyimine)
Bir döngü ile kullanıldığında, else
ifadesinin try
deyiminin else
cümlesiyle, if
deyimlerininkinden daha fazla ortak noktası vardır: try
deyiminin else
cümlesi herhangi bir istisna oluşmadığında çalışır ve bir döngünün else
cümlesi herhangi bir break
oluşmadığında çalışır. try
deyimi ve istisnalar hakkında daha fazla bilgi için Özel Durumları İşleme bölümüne bakınız.
Yine C’den ödünç alınan continue
deyimi, döngünün bir sonraki yinelemesiyle devam eder:
>>> for num in range(2, 10):
... if num % 2 == 0:
... print("Found an even number", num)
... continue
... print("Found an odd number", num)
...
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9
4.5. pass
İfadeleri¶
pass
deyimi hiçbir şey yapmaz. Sözdizimsel olarak bir deyim gerektiğinde ancak program hiçbir eylem gerektirmediğinde kullanılabilir. Örneğin:
>>> while True:
... pass # Busy-wait for keyboard interrupt (Ctrl+C)
...
Bu genellikle minimal sınıflar oluşturmak için kullanılır:
>>> class MyEmptyClass:
... pass
...
pass
‘in kullanılabileceği bir başka yer de, yeni kod üzerinde çalışırken bir fonksiyon veya koşul gövdesi için bir yer tutucu olarak daha soyut bir düzeyde düşünmeye devam etmenizi sağlamaktır. pass
sessizce göz ardı edilir:
>>> def initlog(*args):
... pass # Remember to implement this!
...
4.6. Fonksiyonların Tanımlanması¶
Fibonacci serisini rastgele bir sınıra kadar yazan bir fonksiyon oluşturabiliriz:
>>> def fib(n): # write Fibonacci series up to n
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> # Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Anahtar kelime def
bir fonksiyon tanımını tanıtır. Bunu fonksiyon adı ve parantez içine alınmış resmi parametreler listesi takip etmelidir. Fonksiyonun gövdesini oluşturan ifadeler bir sonraki satırdan başlar ve girintili olmalıdır.
Fonksiyon gövdesinin ilk ifadesi isteğe bağlı olarak bir string literal olabilir; bu string literal fonksiyonun dokümantasyon stringi veya docstring ‘dir. (Docstringler hakkında daha fazla bilgi Dokümantasyon Stringler’i bölümünde bulunabilir.) Otomatik olarak çevrimiçi veya basılı dokümantasyon üretmek veya kullanıcının etkileşimli olarak kodda gezinmesini sağlamak için docstringleri kullanan araçlar vardır; yazdığınız koda docstringler eklemek iyi bir uygulamadır, bu yüzden bunu alışkanlık haline getirin.
Bir fonksiyonun çalıştırılması, fonksiyonun yerel değişkenleri için kullanılan yeni bir sembol tablosu ortaya çıkarır. Daha açık bir ifadeyle, bir fonksiyon içindeki tüm değişken atamaları değeri yerel sembol tablosunda saklar; oysa değişken referansları önce yerel sembol tablosuna, sonra çevreleyen fonksiyonların yerel sembol tablolarına, daha sonra global sembol tablosuna ve son olarak da yerleşik isimler tablosuna bakar. Bu nedenle, global değişkenlere ve çevreleyen fonksiyonların değişkenlerine bir fonksiyon içinde doğrudan değer atanamaz (global değişkenler için bir global
deyiminde veya çevreleyen fonksiyonların değişkenleri için bir nonlocal
deyiminde isimlendirilmedikçe), ancak bunlara referans verilebilir.
Bir fonksiyon çağrısının gerçek parametreleri (argümanları), çağrıldığında çağrılan fonksiyonun yerel sembol tablosunda tanıtılır; bu nedenle, argümanlar call by value (burada value her zaman bir nesne referans’dır, nesnenin değeri değildir) kullanılarak aktarılır. 1 Bir fonksiyon başka bir fonksiyonu çağırdığında veya kendini tekrarlı olarak çağırdığında, bu çağrı için yeni bir yerel sembol tablosu oluşturulur.
Bir fonksiyon tanımı, fonksiyon adını geçerli sembol tablosundaki fonksiyon nesnesiyle ilişkilendirir. Yorumlayıcı, bu adın işaret ettiği nesneyi kullanıcı tanımlı bir fonksiyon olarak tanır. Diğer isimler de aynı fonksiyon nesnesine işaret edebilir ve fonksiyona erişmek için kullanılabilir:
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
Diğer dillerden geliyorsanız, fib
‘in bir fonksiyon değil, değer döndürmediği için bir prosedür olduğuna itiraz edebilirsiniz. Aslında, return
ifadesi olmayan fonksiyonlar bile, oldukça sıkıcı olsa da, bir değer döndürürler. Bu değer None
olarak adlandırılır (yerleşik bir isimdir). Normalde None
değerinin yazılması, yazılan tek değer olacaksa yorumlayıcı tarafından bastırılır. Eğer gerçekten istiyorsanız print()
kullanarak görebilirsiniz:
>>> fib(0)
>>> print(fib(0))
None
Fibonacci serisindeki sayıların listesini döndürebilecek bir fonksiyon yazmak gayet basittir, onun yerine şunu yazdırarak:
>>> def fib2(n): # return Fibonacci series up to n
... """Return a list containing the Fibonacci series up to n."""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a) # see below
... a, b = b, a+b
... return result
...
>>> f100 = fib2(100) # call it
>>> f100 # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Bu örnek, her zamanki gibi, bazı yeni Python özelliklerini göstermektedir:
Bir
return
deyimi bir fonksiyondan bir değerle döner.return
deyimi bir ifade argümanı olmadanNone
döndürür. Bir fonksiyonun sonundan düşmek deNone
değerini döndürür.result.append(a)
ifadesiresult
liste nesnesinin bir metodunu çağırır. Bir yöntem, bir nesneye ‘ait’ olan veobj.methodname
olarak adlandırılan bir işlevdir; buradaobj
bir nesnedir (bu bir ifade olabilir) vemethodname
nesnenin türü tarafından tanımlanan bir yöntemin adıdır. Farklı türler farklı yöntemler tanımlar. Farklı türlerdeki yöntemler, belirsizliğe neden olmadan aynı ada sahip olabilir. (classes kullanarak kendi nesne türlerinizi ve yöntemlerinizi tanımlamak mümkündür, bkz Sınıflar) Örnekte gösterilenappend()
yöntemi liste nesneleri için tanımlanmıştır; listenin sonuna yeni bir öğe ekler. Bu örnekteresult = result + [a]
ile eşdeğerdir, ancak daha verimlidir.
4.7. İşlev Tanımlama hakkında daha fazla bilgi¶
Değişken sayıda argüman içeren fonksiyonlar tanımlamak da mümkündür. Birleştirilebilen üç form vardır.
4.7.1. Varsayılan Değişken Değerleri¶
En kullanışlı biçim, bir veya daha fazla bağımsız değişken için varsayılan bir değer belirtmektir. Bu, izin vermek üzere tanımlandığından daha az sayıda bağımsız değişkenle çağrılabilen bir fonksiyon oluşturur. Örneğin:
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
Bu fonksiyon çeşitli yollarla çağrılabilir:
sadece zorunlu argümanı vererek:
ask_ok('Gerçekten çıkmak istiyor musun?')
isteğe bağlı değişkenlerden birini vermek:
ask_ok('OK to overwrite the file?', 2)
ya da bütün değişkenleri vermek:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
Bu örnek ayrıca in
anahtar sözcüğünü de tanıtır. Bu, bir dizinin belirli bir değer içerip içermediğini test eder.
Varsayılan değerler tanımlayan kapsamdaki fonksiyon tanımlama noktasında değerlendirilir, böylece
i = 5
def f(arg=i):
print(arg)
i = 6
f()
5
çıktısını verecektir.
Önemli uyarı: Varsayılan değer yalnızca bir kez değerlendirilir. Varsayılan değer liste, sözlük veya çoğu sınıfın örnekleri gibi değiştirilebilir bir nesne olduğunda bu durum fark yaratır. Örneğin, aşağıdaki fonksiyon sonraki çağrılarda kendisine aktarılan argümanları biriktirir:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
Bu şu çıktıyı verecektir
[1]
[1, 2]
[1, 2, 3]
Varsayılan değerin sonraki çağrılar arasında paylaşılmasını istemiyorsanız, bunun yerine fonksiyonu şu şekilde yazabilirsiniz:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
4.7.2. Anahtar Kelime Değişkenleri¶
Fonksiyonlar ayrıca kwarg=value
şeklinde anahtar kelime argümanları kullanılarak da çağrılabilir. Örneğin, aşağıdaki fonksiyon:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
bir gerekli argüman (voltage
) ve üç isteğe bağlı argüman (state
, action
ve type
) kabul eder. Bu fonksiyon aşağıdaki yollardan herhangi biriyle çağrılabilir:
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
ancak aşağıdaki tüm çağrılar geçersiz olacaktır:
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
Bir fonksiyon çağrısında, anahtar kelime argümanları konumsal argümanları takip etmelidir. Aktarılan tüm anahtar sözcük argümanları fonksiyon tarafından kabul edilen argümanlardan biriyle eşleşmelidir (örneğin actor
parrot
fonksiyonu için geçerli bir argüman değildir) ve sıraları önemli değildir. Buna isteğe bağlı olmayan argümanlar da dahildir (örneğin parrot(voltage=1000)
da geçerlidir). Hiçbir argüman birden fazla değer alamaz. İşte bu kısıtlama nedeniyle başarısız olan bir örnek:
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function() got multiple values for argument 'a'
**name
biçiminde bir son biçimsel parametre mevcut olduğunda, biçimsel parametreye karşılık gelenler dışındaki tüm anahtar kelime argümanlarını içeren bir sözlük alır (bkz. Mapping Types — dict). Bu, biçimsel parametre tuple listesinin ötesindeki konumsal argümanları içeren bir *name
biçimindeki bir biçimsel parametre ile birleştirilebilir (bir sonraki alt bölümde açıklanmıştır). (*name
, **name
‘den önce gelmelidir.) Örneğin, aşağıdaki gibi bir fonksiyon tanımlarsak:
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
for kw in keywords:
print(kw, ":", keywords[kw])
Şöyle denebilir:
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
ve tabii ki yazdıracaktır:
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
Anahtar sözcük bağımsız değişkenlerinin yazdırılma sırasının, fonksiyon çağrısında sağlandıkları sırayla eşleşmesinin garanti edildiğini unutmayın.
4.7.3. Özel parametreler¶
Varsayılan olarak, argümanlar bir Python fonksiyonuna ya pozisyona göre ya da açıkça anahtar kelimeye göre aktarılabilir. Okunabilirlik ve performans için, argümanların geçirilme şeklini kısıtlamak mantıklıdır, böylece bir geliştiricinin öğelerin konumla mı, konumla ya da anahtar sözcükle mi yoksa anahtar sözcükle mi geçirildiğini belirlemek için yalnızca fonksiyon tanımına bakması gerekir.
Bir fonksiyon tanımı aşağıdaki gibi görünebilir:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
burada /
ve *
isteğe bağlıdır. Kullanılırsa, bu semboller, argümanların fonksiyona nasıl geçirilebileceğine göre parametre türünü gösterir: yalnızca konumsal, konumsal veya anahtar sözcük ve yalnızca anahtar sözcük. Anahtar sözcük parametreleri, adlandırılmış parametreler olarak da adlandırılır.
4.7.3.1. Konumsal veya Anahtar Kelime Argümanları¶
Eğer /
ve *
fonksiyon tanımında mevcut değilse, argümanlar bir fonksiyona pozisyon veya anahtar kelime ile aktarılabilir.
4.7.3.2. Yalnızca Konumsal Parametreler¶
Bu konuya biraz daha detaylı bakacak olursak, belirli parametreleri positional-only olarak işaretlemek mümkündür. Eğer konumsal-sadece ise, parametrelerin sırası önemlidir ve parametreler anahtar kelime ile aktarılamaz. Yalnızca konumsal parametreler bir /
(ileri eğik çizgi) önüne yerleştirilir. /
sadece konumsal parametreleri diğer parametrelerden mantıksal olarak ayırmak için kullanılır. Fonksiyon tanımında /
yoksa, sadece konumsal parametre yoktur.
/
işaretini takip eden parametreler konumsal veya anahtar sözcük veya sadece anahtar sözcük olabilir.
4.7.3.3. Yalnızca Anahtar Sözcük İçeren Değişkenler¶
Parametrelerin anahtar sözcük argümanıyla geçirilmesi gerektiğini belirterek parametreleri anahtar sözcüğe özel olarak işaretlemek için, argüman listesine ilk anahtar sözcüğe özel parametreden hemen önce bir *
yerleştirin.
4.7.3.4. Fonksiyon Örnekleri¶
/
ve *
işaretlerine çok dikkat ederek aşağıdaki örnek fonksiyon tanımlarını göz önünde bulundurun:
>>> def standard_arg(arg):
... print(arg)
...
>>> def pos_only_arg(arg, /):
... print(arg)
...
>>> def kwd_only_arg(*, arg):
... print(arg)
...
>>> def combined_example(pos_only, /, standard, *, kwd_only):
... print(pos_only, standard, kwd_only)
İlk fonksiyon tanımı, standard_arg
, en bilinen biçimdir, çağırma kuralına herhangi bir kısıtlama getirmez ve argümanlar konum veya anahtar kelime ile aktarılabilir:
>>> standard_arg(2)
2
>>> standard_arg(arg=2)
2
İkinci fonksiyon pos_only_arg
, fonksiyon tanımında bir /
olduğu için sadece konumsal parametreleri kullanacak şekilde sınırlandırılmıştır:
>>> pos_only_arg(1)
1
>>> pos_only_arg(arg=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'
Üçüncü fonksiyon kwd_only_args
sadece fonksiyon tanımında *
ile belirtilen anahtar kelime argümanlarına izin verir:
>>> kwd_only_arg(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
>>> kwd_only_arg(arg=3)
3
Sonuncusu ise aynı fonksiyon tanımında üç çağrı kuralını da kullanır:
>>> combined_example(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given
>>> combined_example(1, 2, kwd_only=3)
1 2 3
>>> combined_example(1, standard=2, kwd_only=3)
1 2 3
>>> combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() got some positional-only arguments passed as keyword arguments: 'pos_only'
Son olarak, name
konumsal argümanı ile name
anahtarına sahip **kwds
arasında potansiyel bir çakışma olan bu fonksiyon tanımını düşünün:
def foo(name, **kwds):
return 'name' in kwds
Anahtar kelime 'name'
her zaman ilk parametreye bağlanacağı için True
döndürmesini sağlayacak olası bir çağrı yoktur. Örneğin:
>>> foo(1, **{'name': 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for argument 'name'
>>>
Ancak /
(yalnızca konumsal argümanlar) kullanıldığında, name
bir konumsal argüman olarak ve 'name'
anahtar kelime argümanlarında bir anahtar olarak izin verdiği için mümkündür:
def foo(name, /, **kwds):
return 'name' in kwds
>>> foo(1, **{'name': 2})
True
Başka bir deyişle, yalnızca konumsal parametrelerin adları **kwds
içinde belirsizlik olmadan kullanılabilir.
4.7.3.5. Özet¶
Kullanım durumu, fonksiyon tanımında hangi parametrelerin kullanılacağını belirleyecektir:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
Rehber olarak:
Parametrelerin adının kullanıcı tarafından kullanılamamasını istiyorsanız sadece pozisyonel seçeneğini kullanın. Bu, parametre adlarının gerçek bir anlamı olmadığında, fonksiyon çağrıldığında bağımsız değişkenlerin sırasını zorlamak istediğinizde veya bazı konumsal parametreler ve rastgele anahtar sözcükler almanız gerektiğinde kullanışlıdır.
Adların bir anlamı olduğunda ve fonksiyon tanımının adlarla açık olmasıyla daha anlaşılır olduğunda veya kullanıcıların geçirilen argümanın konumuna güvenmesini önlemek istediğinizde yalnızca anahtar sözcük kullanın.
Bir API için, parametrenin adı gelecekte değiştirilirse API değişikliklerinin bozulmasını önlemek için yalnızca konumsal kullanın.
4.7.4. Keyfi Argüman Listeleri¶
Son olarak, en az kullanılan seçenek, bir fonksiyonun rastgele sayıda argümanla çağrılabileceğini belirtmektir. Bu argümanlar bir tuple içinde paketlenecektir (bkz Veri Grupları ve Diziler). Değişken argüman sayısından önce, sıfır veya daha fazla normal argüman olabilir.
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
Normally, these variadic arguments will be last in the list of formal
parameters, because they scoop up all remaining input arguments that are
passed to the function. Any formal parameters which occur after the *args
parameter are ‘keyword-only’ arguments, meaning that they can only be used as
keywords rather than positional arguments.
>>> def concat(*args, sep="/"):
... return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'
4.7.5. Argüman Listelerini Açma¶
Tersi durum, argümanlar zaten bir liste veya tuple içinde olduğunda, ancak ayrı konumsal argümanlar gerektiren bir fonksiyon çağrısı için paketten çıkarılması gerektiğinde ortaya çıkar. Örneğin, yerleşik range()
fonksiyonu ayrı start ve stop argümanları bekler. Eğer bunlar ayrı olarak mevcut değilse, argümanları bir listeden veya tuple’dan çıkarmak için fonksiyon çağrısını *
-operatörü ile yazın:
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
Aynı şekilde, sözlükler **
-operatörü ile anahtar sözcük argümanları sunabilir:
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
4.7.6. Lambda İfadeleri¶
Küçük anonim fonksiyonlar lambda
anahtar sözcüğü ile oluşturulabilir. Bu fonksiyon iki argümanının toplamını döndürür: lambda a, b: a+b
. Lambda fonksiyonları, fonksiyon nesnelerinin gerekli olduğu her yerde kullanılabilir. Sözdizimsel olarak tek bir ifadeyle sınırlıdırlar. Anlamsal olarak, normal bir fonksiyon tanımı için sadece sözdizimsel şekerdirler. İç içe işlev tanımları gibi, lambda işlevleri de içeren kapsamdaki değişkenlere başvurabilir:
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
Yukarıdaki örnekte bir fonksiyon döndürmek için bir lambda ifadesi kullanılmıştır. Başka bir kullanım da küçük bir fonksiyonu argüman olarak geçirmektir:
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
4.7.7. Dokümantasyon Stringler’i¶
Belge dizelerinin içeriği ve biçimlendirilmesiyle ilgili bazı kurallar aşağıda verilmiştir.
İlk satır her zaman nesnenin amacının kısa ve öz bir özeti olmalıdır. Öz olması için, nesnenin adı veya türü açıkça belirtilmemelidir, çünkü bunlar başka yollarla elde edilebilir (adın bir fonksiyonun çalışmasını açıklayan bir fiil olması durumu hariç). Bu satır büyük harfle başlamalı ve nokta ile bitmelidir.
Belgeleme string’inde daha fazla satır varsa, ikinci satır boş olmalı ve özeti açıklamanın geri kalanından görsel olarak ayırmalıdır. Sonraki satırlar, nesnenin çağrı kurallarını, yan etkilerini vb. açıklayan bir veya daha fazla paragraftan oluşmalıdır.
Python ayrıştırıcısı, Python’daki çok satırlı dize değişmezlerinden girintiyi çıkarmaz, bu nedenle belgeleri işleyen araçların istenirse girintiyi çıkarması gerekir. Bu, aşağıdaki kural kullanılarak yapılır. Dizenin ilk satırından sonraki boş olmayan ilk satır, tüm dokümantasyon dizesi için girinti miktarını belirler. (İlk satırı kullanamayız, çünkü genellikle dizenin açılış tırnaklarına bitişiktir, bu nedenle girintisi dize değişmezinde belirgin değildir) Bu girintiye “eşdeğer” boşluk daha sonra dizenin tüm satırlarının başlangıcından çıkarılır. Daha az girintili satırlar oluşmamalıdır, ancak oluşurlarsa başlarındaki tüm boşluklar çıkarılmalıdır. Beyaz boşlukların eşdeğerliği sekmelerin genişletilmesinden sonra test edilmelidir (normalde 8 boşluğa kadar).
İşte çok satırlı bir docstring örneği:
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything.
... """
... pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
4.7.8. Fonksiyon Ek Açıklamaları¶
Fonksiyon ek açıklamaları kullanıcı tanımlı fonksiyonlar tarafından kullanılan tipler hakkında tamamen isteğe bağlı meta veri bilgileridir (daha fazla bilgi için PEP 3107 ve PEP 484 sayfalarına bakınız).
İşaretlemeler, fonksiyonun __annotations__
özelliğinde bir sözlük olarak saklanır ve fonksiyonun diğer bölümleri üzerinde hiçbir etkisi yoktur. Parametre ek açıklamaları, parametre adından sonra iki nokta üst üste işareti ve ardından ek açıklamanın değerine göre değerlendirilen bir ifade ile tanımlanır. Dönüş ek açıklamaları, parametre listesi ile def
ifadesinin sonunu belirten iki nokta arasında bir ->
ifadesi ve ardından bir ifade ile tanımlanır. Aşağıdaki örnekte bir gerekli argüman, bir isteğe bağlı argüman ve dönüş değeri ek açıklamalıdır:
>>> def f(ham: str, eggs: str = 'eggs') -> str:
... print("Annotations:", f.__annotations__)
... print("Arguments:", ham, eggs)
... return ham + ' and ' + eggs
...
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
Arguments: spam eggs
'spam and eggs'
4.8. Intermezzo: Kodlama Stili¶
Artık daha uzun, daha karmaşık Python parçaları yazmak üzere olduğunuza göre, kodlama stili hakkında konuşmak için iyi bir zaman. Çoğu dil farklı stillerde yazılabilir (ya da daha özlü bir ifadeyle biçimlendirilebilir); bazıları diğerlerinden daha okunaklıdır. Başkalarının kodunuzu okumasını kolaylaştırmak her zaman iyi bir fikirdir ve güzel bir kodlama stili benimsemek buna çok yardımcı olur.
Python için PEP 8, çoğu projenin bağlı olduğu stil kılavuzu olarak ortaya çıkmıştır; okunabilir ve göze hoş gelen bir kodlama stilini teşvik eder. Her Python geliştiricisi bir noktada onu okumalıdır; işte sizin için çıkarılan en önemli noktalar:
4 aralıklı girinti kullanın ve sekme kullanmayın.
4 boşluk, küçük girinti (daha fazla iç içe geçme derinliği sağlar) ve büyük girinti (okunması daha kolay) arasında iyi bir uzlaşmadır. Sekmeler karışıklığa neden olur ve en iyisi dışarıda bırakmaktır.
Satırları 79 karakteri geçmeyecek şekilde sarın.
Bu, küçük ekranlı kullanıcılara yardımcı olur ve daha büyük ekranlarda birkaç kod dosyasının yan yana olmasını mümkün kılar.
Fonksiyonları ve sınıfları ve fonksiyonların içindeki büyük kod bloklarını ayırmak için boş satırlar kullanın.
Mümkün olduğunda, yorumları kendi başlarına bir satıra koyun.
Docstrings kullanın.
Operatörlerin etrafında ve virgüllerden sonra boşluk kullanın, ancak doğrudan parantez yapılarının içinde kullanmayın:
a = f(1, 2) + g(3, 4)
.Sınıflarınızı ve fonksiyonlarınızı tutarlı bir şekilde adlandırın; buradaki kural, sınıflar için
UpperCamelCase
, fonksiyonlarını; metotlar için delowercase_with_underscores
kullanmaktır. İlk yöntem argümanının adı olarak her zamanself
kullanın (sınıflar ve yöntemler hakkında daha fazla bilgi için Sınıflara İlk Bakış bölümüne bakın).Kodunuz uluslararası ortamlarda kullanılacaksa süslü kodlamalar kullanmayın. Python’un varsayılanı, UTF-8 veya hatta düz ASCII her durumda en iyi sonucu verir.
Aynı şekilde, farklı bir dil konuşan kişilerin kodu okuması veya muhafaza etmesi için en ufak bir şans varsa, tanımlayıcılarda ASCII olmayan karakterler kullanmayın.
Dipnotlar
- 1
Aslında, nesne referansı ile çağırma daha iyi bir tanımlama olacaktır, çünkü değiştirilebilir bir nesne aktarılırsa, çağıran, çağırılanın üzerinde yaptığı tüm değişiklikleri (bir listeye eklenen öğeler) görecektir.