Birisi Python'da bir nesnenin adından önce alt çizgi çizmenin tam anlamını ve her ikisi arasındaki farkı açıklayabilir mi?
Ayrıca, söz konusu nesnenin bir değişken, bir işlev, bir yöntem vb. Olması da aynı anlama geliyor mu?
Birisi Python'da bir nesnenin adından önce alt çizgi çizmenin tam anlamını ve her ikisi arasındaki farkı açıklayabilir mi?
Ayrıca, söz konusu nesnenin bir değişken, bir işlev, bir yöntem vb. Olması da aynı anlama geliyor mu?
Yanıtlar:
Bir sınıfta, önde gelen alt çizgiye sahip isimler, diğer programcılara, özniteliğin veya yöntemin özel olması gerektiğini belirtmek içindir. Ancak, adın kendisi ile özel bir şey yapılmaz.
PEP-8'den alıntı yapmak için :
_single_leading_underscore: zayıf "dahili kullanım" göstergesi. Örneğin
from M import *
, adı alt çizgi ile başlayan nesneleri içe aktarmaz.
Gönderen Python docs :
Formun herhangi bir tanımlayıcısı
__spam
(en az iki önde gelen alt çizgi, en fazla bir arka alt çizgi) metin ile değiştirilir_classname__spam
, buradaclassname
önde gelen alt çizgi (ler) çıkarılmış olan geçerli sınıf adıdır. Bu karıştırma, tanımlayıcının sözdizimsel konumu dikkate alınmadan yapılır, bu nedenle sınıf-özel durum ve sınıf değişkenlerini, yöntemleri, genel olarak depolanan değişkenleri ve hatta örneklerde depolanan değişkenleri tanımlamak için kullanılabilir. diğer sınıfların örnekleri için bu sınıfa özel.
Ve aynı sayfadan bir uyarı:
Ad yönetimi, sınıflara, türetilmiş sınıflar tarafından tanımlanan örnek değişkenleri hakkında endişelenmek zorunda kalmadan veya sınıf dışındaki kodla örnek değişkenleri ile mucking yapmak zorunda kalmadan "özel" örnek değişkenlerini ve yöntemlerini tanımlamak için kolay bir yol sağlamayı amaçlamaktadır. Mangling kurallarının çoğunlukla kazaları önlemek için tasarlandığını unutmayın; kararlı bir ruhun özel olarak kabul edilen bir değişkene erişmesi veya değiştirmesi yine de mümkündür.
>>> class MyClass():
... def __init__(self):
... self.__superprivate = "Hello"
... self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
__
değişken ad olarak basitçe çift alt çizginin anlamı nedir? gibia, __ = foo()
Şu ana kadar mükemmel cevaplar var ama bazı çerezler eksik. Tek bir lider çizgi tam olarak değil sadece bir kongre: kullanırsanız from foobar import *
, ve modül foobar
bir tanımlamıyor __all__
liste, modülün ithal isimler yok lider çizgi ile olanları içerir. Diyelim ki çoğunlukla bir kongre, çünkü bu dava oldukça belirsiz bir köşe ;-).
Lider-çizgi kongre yaygın değil sadece kullanılan özel adlar, aynı zamanda C ++ dediğimiz için korumalı , örneğin tam amaçlanan yöntemlerin isimleri alt sınıflara (hatta olanlar tarafından geçersiz kılınmış olması - olanlar var zira geçersiz kılınan olmak onlar raise NotImplementedError
!) temel sınıf ! -) genellikle , söz konusu yöntemlerin doğrudan çağrılmadığını belirten , o sınıfın (veya alt sınıfların) örneklerini kullanarak kodlama yapmak için kullanılan tekli satırların alt çizgi isimleridir .
Örneğin, FIFO'dan farklı bir kuyruk disipline sahip bir iş parçacığı için güvenli kuyruk oluşturmak için, Kuyruk, Alt Sıra Queue.Queue alt sınıfları içe aktarılır ve _get
ve _put
; "Müşteri kodu" asla bu ( "kanca") yöntemlerini çağırır fakat gibi oldukça ( "organize") Kamu yöntemler put
ve get
(bu olarak bilinir Şablon Yöntemi tasarım deseni - örneğin bkz burada bir videoya dayanarak ilginç bir sunum için konuyla ilgili konuşmamın, konuşma metninin özetlerinin eklenmesiyle).
Düzenle: Görüşmelerin açıklamasındaki video bağlantıları artık bozuk. İlk iki videoyu burada ve burada bulabilirsiniz .
_var_name
veya kullanmamaya nasıl karar verirsiniz ? var_name
__all__
__all__
modülü from spam import *
kolaylaştırmak istediğinizde açık kullanın . Yani çoğu zaman cevap her ikisidir .
_
özel dedikleri zaman hoşlanmıyorum . Açıkçası benzetmelerden bahsediyorum, çünkü Python'da hiçbir şey özel değildir . Semantik içine dalış biz bağlayabiliriz söyleyebilirim zaman _
Java'nın için korumalı beri proctected Java araçlarında "türetilmiş sınıfları ve / veya aynı paket içinde". PEP8 zaten ithalat _
hakkında konuşurken sadece bir konvansiyon olmadığını *
ve orada var olduğunu söylüyor çünkü paketi modülle değiştirin . Ve kesinlikle __
Java en eşdeğer olacaktır özel bir sınıf içinde tanımlayıcıları bahsederken.
__foo__
: Bu sadece bir kuraldır, Python sisteminin kullanıcı adlarıyla çakışmayan adları kullanmasının bir yoludur.
_foo
: Bu sadece bir kural, programcının değişkenin özel olduğunu (Python'da ne anlama gelirse) belirtmesinin bir yoludur.
__foo
: bunun gerçek bir anlamı vardır: yorumlayıcı _classname__foo
, adın başka bir sınıfta benzer bir adla örtüşmemesini sağlamak için bu adı değiştirir.
Python dünyasında başka hiçbir alt çizginin anlamı yoktur.
Bu sözleşmelerde sınıf, değişken, küresel vb. Arasında bir fark yoktur.
__foo
ve meraklıydı. Diğer Sınıflarla benzer yöntem adlarıyla nasıl çakışabilir? Yani hala instance.__foo()
(tercüman tarafından yeniden adlandırılmamışsa) erişmek zorundasınız , değil mi?
from module import *
, altı çizili önekli nesneleri almadığını belirtir . Bu nedenle, _foo
sadece bir sözleşmeden daha fazlasıdır.
B
alt sınıfları sınıf A
ve her ikisi de uygulanırsa foo()
, devralınan öğeyi B.foo()
geçersiz kılar . Üzerinden bir örnek yalnızca üzerinden erişebilecektir . .foo()
A
B
B.foo()
super(B).foo()
__dunder__
(bkz bazı durumlarda sadece bir adlandırma kuralı daha belki biraz daha yüzden isimler, örtük invokasyonlar, örnek sözlüğü atlamak özel yöntem arama datamodel bölümüne).
._variable
yarı özeldir ve sadece toplantı amaçlıdır
.__variable
genellikle yanlış özel olarak kabul edilir, ancak gerçek anlamı sadece yanlışlıkla erişimi önlemek için örnekleme yapmaktır [1]
.__variable__
genellikle yerleşik yöntemler veya değişkenler için ayrılmıştır
.__mangled
Umutsuzca istiyorsanız değişkenlere hala erişebilirsiniz . İkili, değişkenin sadece adlandırmalarını veya adını değiştirir, değişkeniinstance._className__mangled
Misal:
class Test(object):
def __init__(self):
self.__a = 'a'
self._b = 'b'
>>> t = Test()
>>> t._b
'b'
t._b'ye erişilebilir çünkü yalnızca kongre ile gizlidir
>>> t.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
t .__ a bulunamadı çünkü adlandırma nedeniyle artık mevcut değil
>>> t._Test__a
'a'
instance._className__variable
Yalnızca çift alt çizgi adı yerine erişerek gizli değere erişebilirsiniz
Başlangıçta tek alt çizgi:
Python'un gerçek özel yöntemleri yoktur. Bunun yerine, bir yöntemin veya öznitelik adının başlangıcında bir alt çizgi, API'ya dahil olmadığı için bu yönteme erişmemeniz gerektiği anlamına gelir.
class BaseForm(StrAndUnicode):
def _get_errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
errors = property(_get_errors)
(Bu kod snippet'i django kaynak kodundan alınmıştır: django / formlar / forms.py). Bu kodda, errors
genel bir özelliktir, ancak bu özelliğin _get_errors olarak adlandırdığı yöntem "özel" dir, bu nedenle ona erişmemelisiniz.
Başlangıçta iki alt çizgi:
Bu çok karışıklığa neden olur. Özel bir yöntem oluşturmak için kullanılmamalıdır. Yönteminizin bir alt sınıf tarafından geçersiz kılınmasını veya yanlışlıkla erişilmesini önlemek için kullanılmalıdır. Bir örnek görelim:
class A(object):
def __test(self):
print "I'm a test method in class A"
def test(self):
self.__test()
a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!
Çıktı:
$ python test.py
I'm test method in class A
I'm test method in class A
Şimdi bir alt sınıf B oluşturun ve __test yöntemi için özelleştirme yapın
class B(A):
def __test(self):
print "I'm test method in class B"
b = B()
b.test()
Çıktı ...
$ python test.py
I'm test method in class A
Gördüğümüz gibi, A.test () beklediğimiz gibi B .__ test () yöntemlerini çağırmadı. Ama aslında, bu __ için doğru davranış. __Test () adı verilen iki yöntem otomatik olarak _A__test () ve _B__test () olarak yeniden adlandırılır (karıştırılır), bu nedenle yanlışlıkla geçersiz kılmazlar. __ ile başlayan bir yöntem oluşturduğunuzda, kimsenin bunu geçersiz kılabilmesini istemediğiniz anlamına gelir ve yalnızca kendi sınıfının içinden erişmeyi düşünürsünüz.
Başlangıçta ve sonunda iki alt çizgi:
Gibi bir yöntem gördüğümüzde __this__
, böyle çağırma. Bu, python'un sizi çağırması gereken bir yöntemdir. Hadi bir bakalım:
>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11
>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60
Her zaman bu sihirli yöntemleri çağıran bir operatör veya yerel işlev vardır. Bazen sadece belirli durumlarda bir kanca python çağırır. Örneğin __init__()
, nesneyi __new__()
oluşturmak için çağrıldıktan sonra nesne oluşturulduğunda çağrılır ...
Bir örnek verelim ...
class FalseCalculator(object):
def __init__(self, number):
self.number = number
def __add__(self, number):
return self.number - number
def __sub__(self, number):
return self.number + number
number = FalseCalculator(20)
print number + 10 # 10
print number - 20 # 40
Daha fazla ayrıntı için PEP-8 kılavuzuna bakın . Daha fazla sihirli yöntem için bu PDF'ye bakın .
Bazen olduğu gibi önde gelen alt çizgiyle bir demet gibi görünen şeylere sahip olabilirsiniz.
def foo(bar):
return _('my_' + bar)
Bu durumda, _ (), yerel ayara göre metni doğru dile yerleştirmek için çalışan bir yerelleştirme işlevinin takma adıdır. Örneğin, Sfenks bunu yapar ve ithalatlar arasında bulacaksınız
from sphinx.locale import l_, _
ve sphinx.locale içinde _ () bazı yerelleştirme işlevlerinin takma adı olarak atanır.
Pek çok insan Raymond'un konuşmasına atıfta bulunduğundan , söylediklerini yazarak biraz daha kolaylaştıracağım:
Çift alt çizginin niyeti gizlilikle ilgili değildi. Amaç tam olarak böyle kullanmaktı
class Circle(object): def __init__(self, radius): self.radius = radius def area(self): p = self.__perimeter() r = p / math.pi / 2.0 return math.pi * r ** 2.0 def perimeter(self): return 2.0 * math.pi * self.radius __perimeter = perimeter # local reference class Tire(Circle): def perimeter(self): return Circle.perimeter(self) * 1.25
Aslında mahremiyetin tam tersi, tamamen özgürlükle ilgili. Alt sınıflarınızı, diğerlerini bozmadan herhangi bir yöntemi geçersiz kılmaktan kurtarır .
Eğer yerel bir referansı tutmuyorum ki perimeter
içinde Circle
. Artık türetilmiş bir sınıf , dokunmadan Tire
uygulanmasını geçersiz kılar . Aradığınızda , teoride hala hesaplama için kullanıyor olmalı , ancak gerçekte , amaçlanan davranış değil, kullanıyor . Bu yüzden Circle'da yerel bir referansa ihtiyacımız var.perimeter
area
Tire(5).area()
Circle.perimeter
Tire.perimeter
Ama neden __perimeter
yerine _perimeter
? Çünkü _perimeter
hala türetilmiş sınıfa geçersiz kılma şansı veriyor:
class Tire(Circle):
def perimeter(self):
return Circle.perimeter(self) * 1.25
_perimeter = perimeter
Çift alt çizginin ad yönetimi vardır, bu nedenle üst sınıftaki yerel başvurunun türetilmiş sınıfta geçersiz kılma olasılığı çok düşüktür. böylece " alt sınıflarınızı herhangi bir yöntemi diğerlerini bozmadan geçersiz kılar ".
Sınıfınız devralınmayacaksa veya yöntem geçersiz kılma hiçbir şeyi bozmazsa, ihtiyacınız yoktur __double_leading_underscore
.
Eğer gerçekten bir değişken salt okunur yapmak istiyorsa, IMHO en iyi yol, özellik () 'i sadece alıcıyla geçirilmiş olarak kullanmak olacaktır. Property () ile veriler üzerinde tam kontrol sahibi olabiliriz.
class PrivateVarC(object):
def get_x(self):
pass
def set_x(self, val):
pass
rwvar = property(get_p, set_p)
ronly = property(get_p)
OP'nin biraz farklı bir soru sorduğunu anlıyorum ama 'özel değişkenlerin nasıl ayarlanacağını' soran başka bir soru bulduğumdan, bununla çift olarak işaretlendi, bu ek bilgiyi buraya eklemeyi düşündüm.
Accroding https://dbader.org/blog/meaning-of-underscores-in-python
Harika cevaplar ve hepsi doğru, basit tanım / anlam ile birlikte basit bir örnek verdim.
Anlamı:
some_variable --► herkes bunu görebilir.
_some_variable --► herkes bunu görebilir herkese açık ama Python tarafından hiçbir yaptırım yapılmadığını bildiren özel ... uyarısı bir kuraldır .
__some_varaible --► Python, değişken adını _classname__some_varaible (AKA ad yönetimi) ile değiştirir ve görünürlüğünü azaltır / gizler ve daha çok özel değişken gibi olur.
Burada dürüst olmak gerekirse Python belgelerine göre
"Python'da bir nesnenin içinden erişilemeyen" özel "örnek değişkenleri yok"
Örnek:
class A():
here="abc"
_here="_abc"
__here="__abc"
aObject=A()
print(aObject.here)
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable
#print(aObject.__here)
Tek önde gelen alt çizgiler bir kongre. isimlerin tek bir alt çizgi ile başlayıp başlamaması durumunda tercümanın bakış açısından bir fark yoktur.
Çift ön ve arka alt çizgi için kullanılan dahili gibi yöntemlerle, __init__
, __bool__
vs.
/ Y arka meslektaşları w çift gelen alt çizgi de, ancak, sınıf yöntemleri olacak bir Kongre olan karıştırılmış yorumlayıcı tarafından. Değişkenler veya temel işlev adları için hiçbir fark yoktur.
Sorunuz iyi, sadece yöntemlerle ilgili değil. Modüllerdeki işlevler ve nesneler genellikle bir alt çizgi ile önek olarak eklenir ve iki ile önek eklenebilir.
Ancak __double_underscore adları, örneğin modüllerde isimlendirilmiş değildir. Bir veya daha fazla alt çizgiyle başlayan adların tümü bir modülden (modül içe aktarma *) içe aktarılırsa veya yardımda (modül) gösterilen adlar içe aktarılmaz.
Çift alt çizgi özelliklerinin miras alınan bir sınıfı nasıl etkileyebileceğine dair basit bir açıklayıcı örnek. Yani aşağıdaki kurulumla:
class parent(object):
__default = "parent"
def __init__(self, name=None):
self.default = name or self.__default
@property
def default(self):
return self.__default
@default.setter
def default(self, value):
self.__default = value
class child(parent):
__default = "child"
daha sonra python REPL'de bir alt örnek oluşturursanız, aşağıdakileri görürsünüz
child_a = child()
child_a.default # 'parent'
child_a._child__default # 'child'
child_a._parent__default # 'parent'
child_b = child("orphan")
## this will show
child_b.default # 'orphan'
child_a._child__default # 'child'
child_a._parent__default # 'orphan'
Bu bazıları için açık olabilir, ama çok daha karmaşık bir ortamda beni hazırlıksız yakaladı
Bir nesnenin içinden erişilemeyen “özel” örnek değişkenleri Python'da mevcut değildir. Bununla birlikte, çoğu Python kodunun izlediği bir kural vardır: bir alt çizgi (örn. _Spam) önekine sahip bir ad, API'nın herkese açık olmayan bir parçası olarak ele alınmalıdır (bir işlev, yöntem veya veri üyesi olsun) . Bir uygulama detayı olarak düşünülmeli ve haber verilmeden değiştirilebilir.
referans https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
_ Ve __ 'nin gerçeklerini öğrenmek oldukça kolaydır; diğer cevaplar onları oldukça iyi ifade ediyor. Kullanımın belirlenmesi çok daha zordur.
Ben böyle görüyorum:
_
Bir işlevin örneğin bir API gibi genel kullanım için olmadığını belirtmek için kullanılmalıdır. Bu ve alma kısıtlaması internal
c # 'daki gibi davranmasını sağlar .
__
Kalıtım hirarşisinde isim çarpışmasını önlemek ve geç bağlanmayı önlemek için kullanılmalıdır. Çok c # özel gibi.
==>
Bir şeyin kamusal kullanım için olmadığını, ancak protected
kullanım gibi davranması gerektiğini belirtmek istiyorsanız _
. Bir şeyin kamusal kullanım için olmadığını, ancak private
kullanım gibi davranması gerektiğini belirtmek istiyorsanız __
.
Bu da çok sevdiğim bir teklif:
Sorun şu ki, bir sınıfın yazarı meşru bir şekilde "bu öznitelik / yöntem adı özel olmalı, sadece bu sınıf tanımından erişilebilir" ve __private kuralını kullanabilir. Ancak daha sonra, bu sınıfın bir kullanıcısı, bu ada meşru bir şekilde erişmesi gereken bir alt sınıf oluşturabilir. Bu yüzden ya üst sınıfın değiştirilmesi (zor ya da imkansız olabilir) ya da alt sınıf kodunun elle karıştırılmış adları (en iyi çirkin ve kırılgan) kullanması gerekir.
Ancak, bence sorun, yöntemleri geçersiz kıldığınızda sizi uyaran bir IDE yoksa, bir taban sınıfından bir yöntemi yanlışlıkla geçersiz kıldığınızda hatayı bulmak biraz zaman alabilir.