Python PEP8 ile Okunabilir Kod Yazımı

2 0
Okuma Süresi:10 Dakika, 14 Saniye
python pep8

Merhaba, uzun bir aradan sonra yeni bir yazı ile karşınızdayım. Bu yazıda başlıktan anlayacağınız üzere python kodlarımızın okunabilirlik seviyesini üst noktalara çekebilmek için PEP8 stil rehberinden bahsedeceğim.

Birçok projede satırlarca kod yazıyoruz ancak üzerinden belli bir müddet geçince tekrar koda baktığımızda kodu anlamayabiliyoruz. Bunun önüne geçmek için yorum satırları kullanıyoruz ancak bazen bunun bile işe yaramadığını gözlemlemiş olmalısınız. Hiç düşündünüz mü yazdığınız kodun görünümü kodunuzun okunabilirliğini ne ölçüde etkiliyor?

Gerçekten kodunuzu belirli kurallara göre yazdığınızda ve bunu yorum satırları ile desteklediğinizde kodunuzun bir başkası tarafından ya da sizin tarafınızdan tekrar tekrar okunabilirlik seviyesini zirveye taşımış oluyorsunuz.

Python geliştiricileri bu sorunu çözebilmek için PEP8 adında bir stil rehberi yayınlayarak python dili üzerinde kodlama yaparken bir standart belirlemek istemişlerdir. (Burada standart diyorum ancak uyup uymamak size kalmış 🙂 ) Bu rehber Guido‘nun orjinal python stil rehberi yazısından ve Barry‘nin stil rehberinden uyarlanmıştır.

Yazılan bir kod, yazıldığından daha fazla okunur.

Guido

Kodumuzu belirli kurallara uyarak geliştirmek istiyorsak tutarlı (consistency) olmamız gerekmektedir. Nasıl başladıysak kodumuzu o şekilde sürdürmeliyiz. Ancak bazen stil kılavuzunun bazı önerileri sizin kod yapınızda uygulanamayabilir. Bu gibi durumlarda çeşitli örnekleri inceleyin ve en iyi görünen yapıyı seçin.

Gelin kodumuzun görünümünü daha okunur hale nasıl getirebileceğimizi başlık başlık inceleyelim.

1. Kod Düzeni

Girinti (Indentation)

Python’da her bir girinti bir scope’a karşılık gelmektedir. Hangi kod bloğunun nerede çalışacağını girintiler ile gösteririz. PEP8‘e göre her girinti seviyesi için 4 boşluk karakteri kullanın. Bir fonksiyon tanımı ya da kullanımı sırasında parametreler bir satıra sığmayacak şekilde ise parametre atama düzeni aşağıdaki gibi olmalıdır. Parametreler dikey görünüm elde etmelidir.

def fuction(var1, var2,
            var3, var4)

hoo = function(
    var1, var2,
    var3, var4)

def function(
        var1, var2,
        var3, var4):
    print(var1)

If ifadelerinin içerisindeki koşul sayısı bir satıra sığmayacak şekilde ise bunu satırlara parçalayabiliriz. Bu durum için kesin olması gerekir diye bir kural yok ancak aşağıdaki iki yöntemden birini tercih edebilirsiniz.

if (this_is_one_cond and
    that_is_another_cond):
    do_something()

if (this_is_one_thing
        and this_is_two_cond
        and that_is_another_cond):
    do_something()

Çok satırlı yapıları bitirmek için kullanılan parantez, köşeli parantez gibi karakterler aşağıdaki örneklerdeki gibi konumlandırılabilir.

my_list = [
    1, 2, 3,
    4, 5, 6]

result = function_arg(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

result = function_arg(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

Not: Tab tuşu yerine boşluk karakterinin kullanılması gerektiği söylenmektedir. Ancak text editör seçeneklerinde Tab tuşunu 4 karakter boşluk bırakma olarak ayarlarsanız Tab tuşunu da kullanabilirsiniz.

Maksimum Satır Uzunluğu

Eğer çoklu pencerede çalışıyorsanız ve incelediğiniz kodun satır uzunlukları çok fazla ise devamlı mouse ile kod penceresini sağa sola çekiştirmek bir ızdıraba dönüşebilir. Bunu engellemek için satır uzunluklarına bir limit koymak en doğru çözüm olacaktır.

PEP8 stil rehberi yorum satırları için 72 karakter kod satırları için ise 79 karakteri limit olarak belirlemiştir.

Not: Kod satır karakter limitini 99 karaktere kadar artırabilirsiniz.

Not: Python söz dizimi parantez, köşeli parantez gibi karakterlerle çevrelenen bir ifadenin satırlara bölünse de ifadenin devam ettiğini anlamaktadır. Ancak parantez içine alamayacağımız durumlarda bir alt satırdan devam etmek için / karakterini kullanırız.

def function(arg_one, arg_two,
             arg_three, arg_four):
    return arg_one

with open('/path/to/some/file/you/want/to/read') as file_1, \
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

Bir Sonraki Satıra Operatör Konularak mı Geçilmeli Konulmayarak mı?

Genelde okunurluluk düzeyini düşüren en büyük hatalardan biriside burada yapılıyor. Kodu yazarken operatörü koyup sonra bir alt satıra geçiyoruz ancak bu durum hangi işlemin yapıldığını tam olarak görmemizi engellemektedir. Önerilen yöntem aşağıdaki gibidir.

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

Boş Satırlar (Blank Lines)

Hiç boş satır bırakılmadan iç içe yazılan kodların anlaşılması oldukça zordur. Çok fazla boş satır bırakmakta kodunuzun kötü gözükmesine yol açacaktır. Boş satırlar için aşağıdaki kuralları uygulamanız yararlı olacaktır.

Üst seviye fonksiyonları ve sınıfları tanımlamadan önce ve tanımladıktan sonra iki satır boşluk bırakın.

class FirstClass:
    pass


class SecondClass:
    pass


def top_level_function():
    return None

Sınıflar içinde tanımlanan metotlar arasında bir satır boşluk bırakın.

class MyClass:
    def first_method(self):
        return None

    def second_method(self):
        return None

Karmaşık bir işlevi gerçekleştiren bir fonksiyonsa anlaşılırlığı arttırmak için işlevin her adımını boş satırla birbirinden ayırabilirsiniz.

Kütüphane Dahil Etme (Import)

Kütüphanelerinizi projenize dahil etmek istiyorsanız sayfanın en üstüne yazmalısınız. Genellikle kütüphaneler ayrı ayrı satırlarda import edilir.

# Doğru:
import os
import sys

# Hatalı:
import sys, os

# Doğru:
from subprocess import Popen, PIPE

Kütüphaneleri projenize aşağıdaki sırayla dahil etmeniz önerilmektedir. Her grup arasına bir satır boşluk bırakın.

  1. Standart Kütüphaneler
  2. Üçüncü Parti Kütüphaneler
  3. Sizin Geliştirdiğiniz Local Kütüphaneleriniz

Not: Sistem yolunu belirterek import etmeniz önerilmektedir. (Absolute import)

import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example

2. String Tırnak Kullanımı

Python’da tek tırnaklı string’ler ve çift tırnaklı string’ler aynıdır. Bunun için PEP8 bir tavsiyede bulunmaz. Bir kural seçin ve ona bağlı kalın. Bir dize tek veya çift tırnak karakterleri içerdiğinde, dizede ters eğik çizgileri önlemek için diğerini kullanın. Okunabilirliği artırır.

3. Expressions ve Statements’larda Boşluk

Aşağıdaki durumlarda gereksiz boşluk kullanımından kaçının.

Parantez, köşeli parantez veya süslü parantez içerisinde:

# Doğru:
spam(ham[1], {eggs: 2})

# Hatalı:
spam( ham[ 1 ], { eggs: 2 } )

Sondaki virgül ve takip eden kapatma parantezi:

# Doğru:
foo = (0,)

# Hatalı:
bar = (0, )

Virgül, noktalı virgül, iki noktadan önce:

# Doğru:
if x == 4: print x, y; x, y = y, x

# Hatalı:
if x == 4 : print x , y ; x , y = y , x

İki nokta, slice operatörü olarakta kullanılmaktadır. Bu şekilde kullanılırsa her iki tarafa da aynı sayıda boşluk uygulanmalıdır.

ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]

Fonksiyon çağrısının parametre listesini başlatacak açma parantezinden hemen önce:

def spam(var1):
    print(var1)

# Doğru:
spam(1)

# Hatalı:
spam (1)

İndis üzerinden erişim sağlarken köşeli parantezden hemen önce:

# Doğru:
dct['key'] = lst[index]

# Hatalı:
dct ['key'] = lst [index]

Bir atama (veya başka) operatörünü bir başkasıyla hizalamak için birden fazla boşluk:

# Doğru:
x = 1
y = 2
long_variable = 3

# Hatalı:
x             = 1
y             = 2
long_variable = 3
Boşluk Kullanımı ile İlgili Öneriler

Aşağıdaki operatörlerin her iki tarafına da bir boşluk bırakmanız yeterli olacaktır.

  • Atama operatörleri (=, +=, -=)
  • Karşılaştırma operatörleri (==, !=, >, <, >=, <=) ve (is, is not, in, not in)
  • Booleans (and, or, not)

Not: Fonksiyon argüman değerlerine varsayılan değer ataması yaparken boşluk karakteri kullanmaya gerek yoktur.

# Önerilen
def function(default_parameter=5):
    pass


# Önerilmeyen
def function(default_parameter = 5):
    pass

Not: Karmaşık matematiksel işlemlerde çok fazla boşluk kullanımı anlam güçlüğüne neden olabiliyor. Bu durumlarda işlem önceliği en düşük olan operatörlerin her iki tarafına boşluk konulması önerilmektedir.

# Önerilen
y = x**2 + 5
z = (x+y) * (x-y)

# Önerilmeyen
y = x ** 2 + 5
z = (x + y) * (x - y)

4. Sondaki Virgüller Ne Zaman Kullanılmalı

Sondaki virgüller genellikle isteğe bağlıdır, ancak bir öğeden oluşan bir demet oluştururken zorunludur. Listeleri tanımlarken, fonksiyon çağırımları yaparken çoklu satır ifadesi kullanıyorsanız sonuna virgül koymanızın bir sakıncası bulunmuyor. Ancak tek bir satırda bu işlemleri yapıyorsanız sonuna virgül konması önerilmemektedir.

# Doğru:
FILES = [
    'setup.cfg',
    'tox.ini',
    ]

# Hatalı:
FILES = ['setup.cfg', 'tox.ini',]

5. Yorum Satırları (Comments)

Kodunuzu yorum satırları ile desteklerseniz daha okunur bir koda sahip olmuş olacaksınız. Ancak yorum satırı eklemiş olayım diye de baştan savma bir duruma kodunuzu sürüklemeyin.

  • Yorumlar düzgün cümleler olması gerekir. Cümlenin ilk karakteri büyük harfle başlamalıdır.
  • Çok cümleli yorumlarda, son cümleden sonra iki satır boşluk bırakılmalıdır.
  • Yorumlarınızın net ve yazdığınız dilin diğer konuşanları tarafından kolayca anlaşılabilir olmasını sağlayın.
  • Kodunuzu global seviyeye çekebilmek için yorum satırlarını İngilizce yazın.
  • Kodunuz değiştiğinde yorum satırlarınızı da güncelleyin.
  • Yorum satırı uzunluğunu 72 karakter ile sınırlayınız.

Block Comments

Belirli bir kod bloğunu açıklamak amacıyla sıklıkla kullanılan bir yorum türüdür. PEP8 , blok yorum satırları yazmak için aşağıdaki kuralları sağlar:

  • Blok yorumları açıkladıkları kodla aynı seviyede olmalıdırlar.
  • Her satıra bir # karakteri ve ardından bir boşluk bırakarak başlayın.
  • Paragrafları # karakterleri ile ayırın.
for i in range(0, 10):
    # Loop over i ten times and print out the value of i, followed by a
    # new line character
    #
    # Loop over i ten times and print out the value of i
    print(i, '\n')

Inline Comments

Satır içi yorumlar tek bir ifadeyi açıklamak için kullanılır. Bu ifadenin neden kullanıldığını hatırlamaya ihtiyacınız olduğunda kullanılması önerilmektedir. PEP8’in satır içi yorumlar üzerine kuralları:

  • Satır içi yorumları ifadeden 2 veya daha fazla boşluk ile ayırın.
  • Satır içi açıklamaları, blok açıklamaları gibi bir # ve tek boşlukla başlatın.
x = 5  # This is an inline comment

Documentation Strings

Bir fonksiyonun, sınıfın, metodun, modülün ne olduğunu ne amaçla yazıldığını açıklamak için kullanılmaktadır. Diğer bir adı docstrings’tir. Kodu başkaları okumasa dahi her genel yapının dokümantasyonunu yazmanız olumlu bir adım olacaktır. “”” işaretleri ile yorum satırını açın ve kapatın.

def quadratic(a, b, c, x):
    """Solve quadratic equation via the quadratic formula.

    A quadratic equation has the following form:
    ax**2 + bx + c = 0

    There always two solutions to a quadratic equation: x_1 & x_2.
    """
    x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
    x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)

    return x_1, x_2

6. İsimlendirme Kuralları

Anlamlı değişken isimleri vermek işinizi ne kadar kolaylaştırdığının farkındasınızdır. Anlamlı isimler sizi ek yorum satırlarından kurtarırken kodu daha hızlı okumanızı sağlamaktadır. Anlamsız isimler sizi ve kodu inceleyen kişileri bataklığa doğru sürükleyecektir.

Not: Yazı tipine bağlı olarak 1 ve 0 ile karıştırılabileceğinden, asla l, O veya I tek harfli isimler kullanmayın.

Aşağıdaki tablo, isimlendirme stilleri ve nasıl yapılacağı hakkında bilgilendirme sunmaktadır.

Türİsimlendirme KuralıÖrnek
Function (Fonksiyon)Kelime veya kelimeler kullanılmalı. lowerCamelCase ya da lower_case_with_underscore yazı tipleri kullanılmalıdır.myFunction,
my_function
Variable (Değişken)Tek bir harf, kelime veya kelimeler kullanılabilir. lowerCamelCase ya da lower_case_with_underscore yazı tipleri kullanılmalıdır.y,
myVariable,
my_variable
Class (Sınıf)Her kelime büyük harfle başlamalıdır. Bu yazı tipine UpperCamelCase denir.MyClass
MetotKelime veya kelimeler kullanılmalı. lowerCamelCase ya da lower_case_with_underscore yazı tipleri kullanılmalıdır.myMethod,
my_method
Constant (Sabit)Tüm harfleri büyük olmalıdır. Harf, kelime veya kelimeler kullanılabilir. uppercase_with_underscore yazı tipi kullanılmalıdır.MY_CONSTANT
Moduleİsimlendirme kısa olmalıdır. lower_case_with_underscore yazı tipi kullanılmalıdır.module.py,
my_module.py
PackageKısa kelime veya kelimeler kullanın. lowercase yazı tipi kullanılmalıdır.mypackage
ExceptionSınıf isimlendirme kurallarını içermektedir.

7. Programlama Önerileri

Bu bölümde PEP8 tarafından standart kod yazımı sağlanması için bazı öneriler ve ipuçları anlatılacaktır.

Lambda ifadesini doğrudan bir tanımlayıcıya bağlayan bir atama ifadesi yerine her zaman bir def ifadesi kullanın:

# Doğru:
def f(x): return 2*x

# Hatalı:
f = lambda x: 2*x

BaseException yerine Exception’dan istisnalar türetin. BaseException’dan doğrudan miras alma, hataları yakalamak için yapılan bariz hatalardan birisidir. Bir sorun oluştu yerine ne ters gitti sorusuna cevap arayın.

Hataları yakalamaya çalışırken spesifik hataları yazarak yakalamaya çalışın.

try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

İşletim sistemi hatalarını yakalarken, errno değerlerinin iç gözlemi yerine Python 3.3’te tanıtılan açık istisna hiyerarşisini tercih edin.

try/except ifaadesindeki try bloğunu minimum kod satırında tutun.

Bir fonksiyonda return ifadesi tutarlı olmalıdır. Fonksiyon her halükarda bir değer döndürmelidir. Hiçbir şey döndürmeyecekse None değer döndürebilirsiniz.

def bar(x):
    if x < 0:
        return None
    return math.sqrt(x)

String modülünün içerisindeki string metotları kullanın.

String’in başını veya sonunu kontrol ederken string slicing yerine startswith() veya endswith() metotlarını kullanın.

# Doğru:
if foo.startswith('bar'):

# Hatalı:
if foo[:3] == 'bar':

Nesne türlerini doğrudan karşılaştırma yerine isinstance() fonksiyonunu kullanın.

# Doğru:
if isinstance(obj, int):

# Hatalı:
if type(obj) is type(1):

Listerin, tupple’ların, string’lerin boş olup olmadığını aşağıdaki yöntemle kontrol ediniz.

if not seq:
if seq:

Bool değerleri True ya da False ile karşılaştırmayın. Doğru kullanımı aşağıdaki gibidir:

# Doğru:
if greeting:

# Hatalı:
if greeting == True:

# Hatalı:
if greeting is True:

try….finally bloğunun kullanılması tavsiye edilmez.

8. Kodunuzu PEP8 ‘e Göre Kontrol Eden Araçlar

Kodu analiz eden ve hataları çıktı olarak sunan programlara linters denir. Aşağıda birkaç tane PEP8 kurallarına göre kodunuzu analiz eden python linters kütüphanesi sunulmuştur.

Kodu otomatik olarak tekrardan formatlayan programlara ise autoformatters denir. Aşağıda birkaç tane PEP8 kurallarına göre kodunuzu yeniden formatlayan python autoformatters kütüphanesi sunulmuştur.



Sonuç olarak artık kodunuzu daha okunur bir şekilde yazacağınızı ve insanlardan güzel dönütler alacağınızı düşünüyorum. Her şeyden önemlisi kodunuzu tekrar tekrar hızlı bir şekilde okuyabileceksiniz. PEP8 standartı ne kadar Python dili için çerçeveler oluştursa da bu kuralları diğer dillerde de kullanabileceğinizi düşünüyorum.

Kaynaklar

Umarım sizin için faydalı bir yazı olmuştur. Bilgi her zaman paylaşılmalıdır.

Happy
Happy
67 %
Sad
Sad
0 %
Excited
Excited
33 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %

Enes Sönmez

Lise eğitimimi Otocenter Mesleki ve Teknik Anadolu Lisesi’nde tamamladım. Bilgisayar programcılığı ve veri tabanı bölümü üzerine liseyi bitirdim. 2017 yılında Karadeniz Teknik Üniversitesi Bilgisayar Mühendisliği bölümünü kazandım. Hala eğitim hayatımı burada sürdürmekteyim. Makine öğrenmesi, derin öğrenme, görüntü işleme ve veri bilimi üzerine çalışmaktayım. Ek olarak Deep Learning Türkiye ve KTÜ Yapay Zeka Topluluğu üyesiyim.

Average Rating

5 Star
0%
4 Star
0%
3 Star
0%
2 Star
0%
1 Star
0%

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir