Python'da özel modül işlevlerini tanımlama


238

Http://www.faqs.org/docs/diveintopython/fileinfo_private.html adresine göre :

Çoğu dil gibi Python da özel unsurlar konseptine sahiptir:

  • Modüllerinin dışından çağrılamayan özel işlevler

Ancak, iki dosya tanımlarsam:

#a.py
__num=1

ve:

#b.py
import a
print a.__num

Ben çalıştırdığınızda herhangi bir istisna vermeden b.pyyazdırır 1. Diveintopython yanlış mı yoksa bir şeyi yanlış mı anladım? Ve bazı yol var özel olarak bir modülün işlevi tanımlayın?


Diveintopython yanlış değildir, ancak örneklerinde >>> import fileinfo >>> m = fileinfo.MP3FileInfo() >>> m.__parse("/music/_singles/kairo.mp3") 1 Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'MP3FileInfo' instance has no attribute '__parse' fileinfo.MP3FileInfo () sınıfın bir örneğidir. Bu, çift alt çizgi kullandığınızda bu özel durumu verir. Sizin durumunuzda bir sınıf oluşturmadığınız halde, sadece bir modül oluşturdunuz. Ayrıca bakınız: stackoverflow.com/questions/70528/…
Homero Esmeraldo

Yanıtlar:


323

Python'da "gizlilik", "yetişkinlerin rızasını" kabul etme düzeylerine bağlıdır - zorlayamazsınız (gerçek hayatta yapabileceğinizden daha fazla ;-). Tek bir önde gelen alt çizgi, ona "dışarıdan" erişmemeniz gerektiği anlamına gelir - iki önde gelen alt çizgi (arkadaki alt çizgiler olmadan) iletiyi daha da güçlü bir şekilde taşır ... ancak sonunda, yine de sosyal konvansiyon ve fikir birliği: Python'un içgözlemi, dünyadaki diğer tüm programcılara isteklerinize saygı göstermesi için kelepçeleyemeyeceğiniz kadar güçlüdür.

O özenle saklanan bir sır olsa ((Btw, hemen aynı C ++ için de geçerlidir: En derleyicileriyle, basit #define private publicönce hat #includesenin ing .h! Dosyayı sizin "gizlilik" karmasını yapmak kurnaz kodlayıcılar için yeterlidir ... -) )


82
C ++ ile ilgili notunuz yanlış. #Define private public'i kullanarak derleyiciye gönderilen kodu değiştirirsiniz, bu da mangling adının gerçekleştiği yerdir.
rhinoinrepose

14
Ayrıca C ++ mangling belirsiz, ancak çok gizli. Ayrıca C ++ tarafından üretilen bir ikili "introspect" olabilir. OT, üzgünüm.
Prof. Falken

47
@Rhinoinrepose için bir güncelleme olarak, sadece yanlış değil, bir önişlemci makrosuna sahip bir anahtar kelimeyi yeniden tanımlamak , standarda göre tanımlanmamış bir davranıştır .
Cory Kramer

3
@AlexMartelli Olabildiği static void foo()kadar özel değil . En azından bağlayıcıya gizlenmiştir ve fonksiyon satır içi ile tamamen kaldırılabilir.
user877329

3
Gerçek hayatta insanlar yasaları çiğnediklerinde yargılanırlar
Lay González

288

Sınıf yetkileri ile modül yetkileri arasında karışıklık olabilir .

Bir modül, özel ile başlar alt çizgi bir
Böyle bir eleman kullanılırken birlikte kopyalanır from <module_name> import *alma komutu şeklini; ancak import <moudule_name>sözdizimi kullanılıyorsa içe aktarılır ( Ben Wilhelm'in cevabına bakın )
Sorunun örneğinin a .__ num değerinden bir alt çizgiyi kaldırmanız yeterlidir ve from a import *sözdizimini kullanarak a.py ithal eden modüllerde gösterilmez .

Özel bir sınıf iki alt çizgiyle başlar (diğer bir deyişle dunder yani d-ouble düşük puan)
Böyle bir değişken, sınıf adını dahil etmek için adını "karıştırılır" vb.
Bu duruma, karıştırılmış adla sınıf mantığının dışında da erişilebilir.
Ad yönetimi yetkisiz erişime karşı hafif bir önleme aracı olarak hizmet edebilse de, asıl amacı, ata sınıflarının sınıf üyeleriyle olası isim çarpışmalarını önlemektir. Alex Martelli'nin bu değişkenlerle ilgili olarak kullanılan sözleşmeyi tanımladığı için yetişkinlere rıza gösteren komik ama doğru referansına bakın .

>>> class Foo(object):
...    __bar = 99
...    def PrintBar(self):
...        print(self.__bar)
...
>>> myFoo = Foo()
>>> myFoo.__bar  #direct attempt no go
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__bar'
>>> myFoo.PrintBar()  # the class itself of course can access it
99
>>> dir(Foo)    # yet can see it
['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__
format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__
', '__subclasshook__', '__weakref__']
>>> myFoo._Foo__bar  #and get to it by its mangled name !  (but I shouldn't!!!)
99
>>>

TIL. __private_functionYine de, modül düzeyinde zorlanmalarının bir nedeni var mı? Ben bununla karşılaştım ve bu yüzden hatalarla karşılaştım.
Noel Baba

@Terrabits nazik sözleri için teşekkür ederim, ama memnuniyetle Alex'e (Python ') her konuda ikinci sıradayım. Dahası, Alex'in dile ve topluma kapsamlı katkıları göz önüne alındığında, cevapları genellikle daha özlü ve mizahi.
mjv

1
@mjv Bu çok yardımcı oldu! Teşekkür ederim! Bir süredir bu davranış hakkında oldukça şaşkınım. Ben doğrudan özel sınıfa erişmeye çalıştığınızda seçim AttributeError dışında bir tür hata atmak olmuştu isterdim; belki bir "PrivateAccessError" ya da bir şey daha açık / yararlı olurdu. (Özniteliği olmadığı hatayı almak gerçekten doğru değildir ).
HFBrowning

82

Modül gizliliği tamamen geleneksel olmadığından ve içe aktarma işlevinin nasıl kullanıldığına bağlı olarak modül gizliliğini tanıyabildiğinden veya tanımayacağından bu soru tam olarak yanıtlanmamıştır .

Eğer bir modülde özel adlar tanımlarsanız, o isimler olacak sözdizimi, 'ithalat modül_ismi' kullanan herhangi komut aktarılır. Böylece, örneğinizde private, _num, a.py'de olduğu gibi doğru bir şekilde tanımladığınızı varsayarsak.

#a.py
_num=1

.. modül ad sembolüyle b.py ile erişebilirsiniz:

#b.py
import a
...
foo = a._num # 1

A.py dosyasından yalnızca özel olmayanları içe aktarmak için from sözdizimini kullanmanız gerekir :

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined

Bununla birlikte, netlik açısından, adları '*' ile içe aktarmak yerine modüllerden içe aktarırken açık olmak daha iyidir:

#b.py
from a import name1 
from a import name2
...

1
hangi işlevlerin / kitaplıkların alınacağını nereden belirlersiniz? içinde init .py?
FistOfFury

_namesÇağrıldığında ad çakışmaları riski yoktur import a- a._namesbu stili kullanırken olduğu gibi erişebilirler .
Josiah Yoder

@FistOfFury Evet, __init__.pydosyaya içe aktarılan işlevleri belirtirsiniz . Bununla ilgili biraz yardım için buraya bakın .
Mike Williamson

29

Python , çift alt çizgi önekiyle özel sınıf üyelerine izin verir . Bu teknik bir modül düzeyinde çalışmıyor, bu yüzden bunun Dalış Into Python bir hata olduğunu düşünüyorum.

Özel sınıf işlevlerine bir örnek:

class foo():
    def bar(self): pass
    def __bar(self): pass

f = foo()
f.bar()   # this call succeeds
f.__bar() # this call fails

2
OP'nin amacı, örneğin ticari bir paketin dışında erişilemeyen işlevler yazmaktır. Bu bağlamda, bu cevap tam değildir. __Bar () işlevine f._foo__bar () aracılığıyla dışarıdan erişilebilir. Bu nedenle, çift önde gelen alt çizgiler onu özel yapmaz.
SevakPrime

24

Bir iç fonksiyon ekleyebilirsiniz:

def public(self, args):
   def private(self.root, data):
       if (self.root != None):
          pass #do something with data

Gerçekten bu gizlilik düzeyine ihtiyacınız varsa böyle bir şey.


9
Bu neden en iyi cevap değil?
safay


1

kapaklar veya işlevlerle gömülü bir yoludur. Bu, JS'de, tarayıcı dışı platformlar veya tarayıcı çalışanları için gerekli olmamasına rağmen yaygındır.

Python'da biraz garip görünüyor, ancak bir şeyin gerçekten gizlenmesi gerekiyorsa, yol bu olabilir. Dahası, python API'sını kullanmak ve C'de (veya başka bir dilde) gizlenmesi gereken şeyleri tutmak muhtemelen en iyi yoldur. Ben bir fonksiyonun içine kodu koymak için gidip, o çağrı ve vermek istediğiniz öğeleri iade olması için başarısız.


-11

Python,., Özel, genel ve korumalı olmak üzere üç moda sahiptir. Bir modülü içe aktarırken yalnızca genel moda erişilebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.