Modüller (ve paketler), programınızı ayrı ad alanlarına bölmenin harika bir Pythonic yoludur ve bu, bu sorunun örtük bir amacı gibi görünüyor. Aslında, Python'un temellerini öğrenirken, bir blok kapsam özelliğinin olmaması beni hayal kırıklığına uğrattı. Ancak Python modüllerini anladıktan sonra, blok kapsamına ihtiyaç duymadan önceki hedeflerimi daha zarif bir şekilde gerçekleştirebildim.
Motivasyon olarak ve insanları doğru yöne yönlendirmek için Python'un kapsam belirleme yapılarının bazılarının açık örneklerini vermenin faydalı olacağını düşünüyorum. Öncelikle, blok kapsamını uygulamak için Python sınıflarını kullanma konusundaki başarısız girişimimi açıklayacağım. Daha sonra Python modüllerini kullanarak nasıl daha faydalı bir şey başardığımı açıklayacağım. Sonunda, verilerin yüklenmesi ve filtrelenmesi için pratik bir paket uygulamasını ana hatlarıyla anlatıyorum.
Sınıflarla blok kapsamı deneniyor
Birkaç dakika boyunca bir sınıf bildiriminin içine kod yapıştırarak blok kapsamı elde ettiğimi düşündüm:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
print(x)
Ne yazık ki bu, bir işlev tanımlandığında bozulur:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(x)
printx2()
Bunun nedeni, bir sınıf içinde tanımlanan işlevlerin genel kapsam kullanmasıdır. Bunu düzeltmenin en kolay yolu (tek olmasa da) sınıfı açıkça belirtmektir:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(BlockScopeAttempt.x)
printx2()
Bu o kadar zarif değil çünkü bir sınıfta yer alıp almadıklarına bağlı olarak işlevleri farklı yazmalı.
Python modülleri ile daha iyi sonuçlar
Modüller statik sınıflara çok benzer, ancak modüller benim deneyimime göre çok daha temiz. Modüllerde de aynısını yapmak my_module.py
için şu anki çalışma dizininde şu içeriğe sahip bir dosya oluşturuyorum :
x = 10
print(x)
def printx():
global x
print(x)
Daha sonra ana dosyamda veya etkileşimli (örneğin Jupyter) oturumumda,
x = 5
import my_module
my_module.printx()
print(x)
Açıklama olarak, her Python dosyası kendi global ad alanına sahip bir modülü tanımlar. Bir modülü içe aktarmak, bu ad alanındaki değişkenlere .
sözdizimi ile erişmenizi sağlar .
Modüllerle etkileşimli bir oturumda çalışıyorsanız, bu iki satırı başlangıçta çalıştırabilirsiniz.
%load_ext autoreload
%autoreload 2
ve modüller, karşılık gelen dosyaları değiştirildiğinde otomatik olarak yeniden yüklenecektir.
Veri yükleme ve filtreleme paketleri
Paket fikri, modül konseptinin küçük bir uzantısıdır. Paket, __init__.py
içe aktarıldığında çalıştırılan (muhtemelen boş) bir dosya içeren bir dizindir . Bu dizindeki modüller / paketlere .
sözdizimi ile erişilebilir .
Veri analizi için genellikle büyük bir veri dosyası okumam ve ardından etkileşimli olarak çeşitli filtreler uygulamam gerekir. Bir dosyayı okumak birkaç dakika sürüyor, bu yüzden sadece bir kez yapmak istiyorum. Okulda nesne yönelimli programlama hakkında öğrendiklerime dayanarak, sınıfta yöntem olarak filtreleme ve yükleme için kod yazılması gerektiğine inanırdım. Bu yaklaşımın önemli bir dezavantajı, filtrelerimi yeniden tanımlarsam, sınıfımın tanımı değişir, bu nedenle veriler dahil tüm sınıfı yeniden yüklemem gerekir.
Günümüzde Python ile, ve my_data
adlı alt modülleri içeren bir paket tanımlıyorum . İçinde göreceli bir içe aktarma yapabilirim:load
filter
filter.py
from .load import raw_data
Değiştirirsem filter.py
, autoreload
değişiklikleri algılar. Yeniden load.py
yüklenmediğinden verilerimi yeniden yüklememe gerek yok. Bu şekilde filtreleme kodumun prototipini bir Jupyter not defterinde oluşturabilir, onu bir işlev olarak paketleyebilir ve ardından not defterimden doğrudan filter.py
. Bunu anlamak iş akışımda devrim yarattı ve beni bir şüpheciden "Python'un Zenine" inanan bir kişiye dönüştürdü.
One purpose (of many) is to improve code readability
- Doğru yazılmış Python kodu (yani, python zenini takip ederek ) okunabilir olması için böyle bir garnitüre ihtiyaç duymaz. Aslında, Python hakkında sevdiğim (birçok) şeyden biri.