2016-03-15 13 views
5

Python üzerinde çalışıyorum. Genel bir api ortaya koyan bir kütüphanenin nasıl tasarlanacağını anlamaya çalışıyorum. Gelecekte değişebilecek içsel yöntemleri ortaya çıkarmaktan kaçınmak istiyorum. Bunu yapmak için basit ve pythonic bir yol arıyorum. Bir grup dersi içeren bir kütüphanem var. Bu sınıfların bazı yöntemleri sınıflar arasında dahili olarak kullanılır. Bu yöntemleri istemci koduna maruz bırakmak istemiyorum. İç mimarları ortaya çıkarmaktan kaçınan bir kütüphane api nasıl tasarlanır?

Kütüphanemin (F. E. mylib) iki yöntem istemci kodu ve kütüphane koduna bazı işler yapmak için kullanılan C.internal() yönteminden kullanıldığı düşünülmektedir bir C.public() yöntem ile bir sınıf C içerdiğini varsayalım. Kendimi genel api'ye ( C.public()) dahil etmek istiyorum ancak ileride parametrelerin eklenmesi veya kaldırılması için C.internal() yöntemini değiştirmeyi umuyorum.

mylib/c.py:

class C: 
    def public(self): 
     pass 

    def internal(self): 
     pass 

mylib/f.py:

class F: 
    def build(): 
     c = C() 
     c.internal() 
     return c 

mylib/__init__.py:

from mylib.c import C 
from mylib.f import F 

Aşağıdaki kod sorumu göstermektedir

client/client.py:

import mylib 
f = mylib.F() 
c = f.build() 
c.public() 
c.internal() # I wish to hide this from client code 

ben düşündüm aşağıdaki çözümleri:

  • belge yalnızca kamu API, özel kütüphane api kullanmayın için belgelerinde kullanıcıyı ikaz. Müşterilerin sadece halka api kullanacağını umarak huzur içinde yaşayın. Bir sonraki kütüphane sürümü istemci kodunu kırıyorsa, istemci arızası :). Bir tür adlandırma kuralı kullanın, örn. önek "_" ile her bir yöntem, (korunan yöntemler için ayrılmıştır ve ide'ye uyarı verir), belki de diğer önekleri kullanabilirim. İç yöntemleri gizlemek için nesne bileşimini kullanın. Örneğin, kitaplık, nesnelerinin C nesnelerini yerleştirdiği yalnızca PC nesnesine geri dönebilir.

mylib/pc.py

:

class PC: 
    def __init__(self, c): 
     self.__c__ 

    def public(self): 
     self.__cc__.public() 

Ama bu biraz yapmacık görünüyor.

Herhangi bir öneri bu soru Bu benzer soru ama kapsamı hakkında biraz farklıdır Does Python have “private” variables in classes?

arasında yineleniyor olduğu öne sürüldü

Güncelleme

:-) takdir edilmektedir. Benim kapsamım tek bir sınıf değil bir kütüphanedir.Bir kütüphanenin kamu metotları/sınıfları/fonksiyonları olan işaretleme (veya zorlama) hakkında bazı kurallar var mı diye merak ediyorum. Örneğin, genel sınıfları veya işlevleri vermek için __init__.py kullanın. Sınıf yöntemlerini dışa aktarma ya da yalnızca belgelere güvenebileceğim bazı kurallar var mı diye merak ediyorum. Korunan yöntemleri işaretlemek için "_" önekini kullanabileceğimi biliyorum. Bildiğim kadarıyla korunan yöntem, sınıf hiyerarşisinde kullanılabilecek bir yöntemdir.

Bir dekoratör @apiSphinx Public API documentation ile genel yöntem işaretleme hakkında bir soru buldum ama yaklaşık 3 yıl önce oldu. Yaygın olarak kabul edilen bir çözüm var, bu yüzden eğer birisi benim kodumu okuyorsa, kütüphane halkı api olması için tasarlanan yöntemleri ve kütüphanede dahili olarak kullanılması amaçlanan yöntemleri anlıyor musunuz? Umut Sorularımı açıklığa kavuşturdum. Herkese teşekkürler!

+0

Olası çoğaltılabilir [Python'un sınıflarında “özel” değişkenleri var mı?] (Http://stackoverflow.com/questions/1641219/does-python-have-private-variables-in-classes –

+2

Özel şeyler yapmak için yolumdan çıkmamalısınız, Pythonic değil – Anentropic

+0

Belirtilen '@ API 'çoğunlukla belgeleme amaçlıdır. – Nikita

cevap

2

Nesnelerin yöntemlerini ve özniteliklerini gerçekten gizleyemezsiniz. Eğer iç yöntemler maruz olmadığından emin olmak için, sarma gitmek yoludur:

class PublicC: 
    def __init__(self): 
     self._c = C() 

    def public(self): 
     self._c.public() 

Çift çizgi Ben piton iç elemanlar çarpışmayı önlemek için bildiği gibi bir önek genellikle kadarıyla önerilmez olarak. , Anentropic

Eğer subclassing tercih ederseniz - önerilmez Ne

çift alt çizgi öneki + sonek ile __myvar__ isimler ... bu adlandırma tarzı birçok piton iç yapıları tarafından kullanılır ve kaçınılmalıdır vardır Eğer iç yöntemleri üzerine ve Hataları yükseltebilir: bazı piton büyü kullanmak istiyorsanız, __getattribute__ bir göz olabilir

class PublicC(C): 
    def internal(self): 
     raise Exception('This is a private method') 

. Burada, kullanıcının bir dahili/kara listeye alınmış bir yöntem için gitmek istemesi durumunda, kullanıcının ne almaya çalıştığını (bir işlev veya öznitelik) ve AttributeError'u yükseltebilirsiniz.

class C(object): 
    def public(self): 
     print "i am a public method" 

    def internal(self): 
     print "i should not be exposed" 

class PublicC(C): 
    blacklist = ['internal'] 

    def __getattribute__(self, name): 
     if name in PublicC.blacklist: 
      raise AttributeError("{} is internal".format(name)) 
     else: 
      return super(C, self).__getattribute__(name) 

c = PublicC() 
c.public() 
c.internal() 

# --- output --- 

i am a public method 
Traceback (most recent call last): 
    File "covering.py", line 19, in <module> 
    c.internal() 
    File "covering.py", line 13, in __getattribute__ 
    raise AttributeError("{} is internal".format(name)) 
AttributeError: internal is internal 

Bunun en az kod ek yüküne neden olduğunu ancak bazı bakım gerektirdiğini varsayalım. Ayrıca işaretini ve beyaz listesi yöntemlerini tersine çevirebilirsiniz.

Beyaz liste muhtemelen kara liste kadar sık ​​değişmeyeceğinden, bu durum sizin durumunuz için daha iyi olabilir.

Sonunda size kalmış. Kendin söylediğin gibi: Her şey belgeleme ile ilgili.

Başka sözler:

Belki de sınıf yapısını yeniden gözden geçirmek istiyorum. Zaten C için F fabrika sınıfınız var. F tüm dahili yöntemlere sahip olsun. Bu durumda, herhangi bir şey sarmak veya alt sınıfa sarmak zorunda kalmazsınız. Bu imkansız hale getirmek için sert tasarım kısıtlamaları yoksa, bu yaklaşımı tavsiye ederim.

+2

"Python internals ile çarpışmayı önlemek için bildiğim kadarıyla önek olarak çift alt çizgi genellikle önerilmez." Bu doğru değil ... çift alt çizgi öneki _is_ özel üyeler yapma python yolu ... sınıfınızın dışında adı gizlenir ve erişmek daha zor. Cesaretsiz nedir '__myvar__' isimleri çift altçizgi _prefix + suffix_ ... bu adlandırma stili birçok python internals tarafından kullanılır ve kaçınılmalıdır – Anentropic

+0

@aleneum Cevabınız için çok teşekkür ederim. – Giovanni

+0

@Giovanni, rica ederim. Yine de dikkatli ol. Müşterilerin kendi deneyimlerini yapmasına izin vermektense, müşterilerin işleri yapmasını engelleyen daha fazla sorunla karşılaşabilirsiniz. Özellikle __getattribute__ güçlü ama aynı zamanda hataların/hataların ortak bir kaynağıdır. Projenizde bol şanslar! – aleneum

2

ben aşağıdaki çözümleri düşündüm:

  • belge yalnızca kamu api, özel kütüphane api kullanmayın için belgelerinde kullanıcıyı ikaz. Müşterilerin sadece genel API'sini kullanmasını umuyoruz. Bir sonraki kütüphane sürümü istemci kodunu bozarsa istemci arızası :). Bir tür adlandırma kuralı kullanın, örn. önek "_", ile her yöntem (korunan yöntemler için ayrılmıştır ve ide'ye bir uyarı yükler), belki de diğer önekleri kullanabilirim. İç yöntemleri gizlemek için nesne bileşimini kullanın. Örneğin, kitaplığı, yalnızca C nesnelerini gömer.

İlk iki puan ile oldukça doğru var.

Pythonic yolu, tek alt çizgi '_' ile başlayan iç yöntemleri adlandırmaktır, bu şekilde tüm Python geliştiricileri bu yöntemin orada olduğunu bilir, ancak kullanımı önerilmez ve kullanmayacaktır. (Bazı maymun yamalarını yapmaya karar verene kadar, ancak bu senaryoyu umursamamanız gerekir.) Yeni başlayanlar için altyazı ile başlayan yöntemleri kullanmama konusunda açıkça belirtmek isteyebilirsiniz. Ayrıca, "özel" yöntemleriniz için herkese açık dokümanları sağlamayın, yalnızca dahili referans için kullanın.

"name mangling" konusuna bakmak isteyebilirsiniz, ancak daha az yaygındır. Nesne kompozisyonu veya __getattribute__ vb. Gibi yöntemlerle içeriğin gizlenmesi genellikle Python'da önerilmez.

Bunu nasıl yönettiklerini görmek için bazı popüler kitaplıkların kaynak koduna bakmak isteyebilirsiniz, örn. Django, Twisted, vb.

+0

Cevabınız için çok teşekkür ederim. Şimdilik, içsel yöntemleri belgelememekle gideceğim. Bazı popüler kütüphanelerin kaynak kodunu okuma şansım olacak. – Giovanni

+0

@Giovanni, tek alt çizgi '_ ile içsel yöntem adlarını da başlatmayı unutmayın ve sorununuza tam bir Pythonic çözümü olacaktır. – Nikita

+0

@Nikita: "İçerdekileri" __getattribute__ "vb. Yöntemlerle gizlemek genelde Python'da önerilmez". Gerçekten?Ben her zaman bunun tam olarak bunun amacını düşündüm. İfadeniz için referans var mı? Özetle Python'dan alıntı: "Ancak, alt sınıfınızın örnekleri için devralınan sınıf özniteliklerini (ör. Yöntemler) gizleme gibi" __getattribute__ "öğesini özel amaçlarla geçersiz kılabilirsiniz. – aleneum

İlgili konular