Neden bazı işlevlerde işlev adından önce ve sonra alt çizgi “__” bulunur?


424

Bu "alt çizgi" çok sık görülüyor ve bunun Python dilinde bir gereklilik mi, yoksa sadece bir kongre meselesi mi olduğunu merak ediyordum?

Ayrıca, birisi hangi işlevlerin alt çizgilere sahip olma eğiliminde olduğunu ve nedenini ( __init__örneğin) açıklayabilir mi?


8
@AustinHenley: İsimden önce ve sonra çift ​​alt çizgi için değil . Sadece adından önce alt çizgileri düşünüyorsunuz .



Bu soru çizgi sorar o @MackM Not önce ve sonra adı ve önerdiği yinelenen hedef sadece alt çizgi sorar önce adı. Yine de, buradaki bazı cevapların da bu davayı kapsadığını itiraf ediyorum.
Georgy

Yanıtlar:


526

Gönderen Python Kodu için Stil Rehberi - Python PEP 8 :

Açıklayıcı: Stilleri Adlandırma

Baştaki veya sondaki alt çizgileri kullanan aşağıdaki özel formlar tanınır (bunlar genellikle herhangi bir durum sözleşmesiyle birleştirilebilir):

  • _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.

  • single_trailing_underscore_: kurallara göre Python anahtar kelimesi ile çakışmaları önlemek için kullanılır, ör.

    Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore: Bir sınıf niteliğini adlandırırken, ad yönetimini çağırır (FooBar sınıfının içinde __booolur _FooBar__boo; aşağıya bakın).

  • __double_leading_and_trailing_underscore__: kullanıcı tarafından kontrol edilen ad alanlarında yaşayan "sihirli" nesneler veya öznitelikler. Örneğin __init__, __import__veya __file__. Asla böyle isimleri icat etmeyin; bunları yalnızca belgelendiği gibi kullanın.

Başında çift ve sonda alt çizgi bulunan isimlerin esasen Python için ayrıldığını unutmayın: "Asla bu tür isimleri icat etmeyin; sadece belgelendiği gibi kullanın".


6
Raymond ayrıca, adın mangling davranışının yaklaşık 34 dakikadan bu videoya neden başlamasını istediğinizi de açıklıyor: youtube.com/watch?v=HTLu2DFOdTg
johncip

5
Yani bir isim tek önde gelen alt çizgi ve çift önde gelen alt çizgi arasındaki seçim biraz C ++ ve Java korumalı ve özel arasında seçim gibi mi? _single_leading_underscore çocuklar tarafından değiştirilebilir, ancak __double_leading_underscore değiştirilemez mi?
Alex W

2
__double_leading_underscoreolduğu hala kamu , değişken basitçe bir çatışma önlemek için yeniden adlandırıldı.
cz

59

Diğer katılımcılar, önde gelen ve arkadaki çift alt çizgileri "özel" veya "büyü" yöntemleri için bir adlandırma kuralı olarak tanımlamakta haklıdır.

Bu yöntemleri doğrudan çağırabilseniz de ( [10, 20].__len__()örneğin) alt çizgilerin varlığı, bu yöntemlerin dolaylı olarak çağrılması için bir ipucudur ( len([10, 20])örneğin). Çoğu python operatörünün ilişkili bir "sihirli" yöntemi vardır (örneğin, a[x]alışmanın normal yoludur a.__getitem__(x)).



5

Aslında üst ve alt sınıf adları arasında farklılık olması gerektiğinde _ yöntem adlarını kullanıyorum. Ebeveyn-çocuk sınıfları oluşturmak için bu şekilde kullanılan bazı kodları okudum. Örnek olarak ben bu kodu sağlayabilir:

class ThreadableMixin:
   def start_worker(self):
       threading.Thread(target=self.worker).start()

   def worker(self):
      try:
        self._worker()
    except tornado.web.HTTPError, e:
        self.set_status(e.status_code)
    except:
        logging.error("_worker problem", exc_info=True)
        self.set_status(500)
    tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.results))

...

ve _worker yöntemi olan çocuk

class Handler(tornado.web.RequestHandler, ThreadableMixin):
   def _worker(self):
      self.res = self.render_string("template.html",
        title = _("Title"),
        data = self.application.db.query("select ... where object_id=%s", self.object_id)
    )

...


Çift alt çizgi öneki bunun için uygun değil mi?
AMC

1

Bu sözleşme özel değişken ya gibi yöntemlerle (sözde “sihirli yöntemi”) için kullanılan __init__ve __len__. Bu yöntemler özel sözdizimsel özellikler sağlar veya özel işler yapar.

Örneğin, __file__Python dosyasının konumu gösterir __eq__çalıştırılan a == bifadesi çalıştırılır.

Bir kullanıcı elbette çok nadir bir durum olan özel bir özel yöntem yapabilir, ancak genellikle yerleşik özel yöntemlerden bazılarını değiştirebilir (örneğin __init__, bir sınıf örneği ilk kez çalıştırılacak olan sınıfı başlatmalısınız yaratıldı).

class A:
    def __init__(self, a):  # use special method '__init__' for initializing
        self.a = a
    def __custom__(self):  # custom special method. you might almost do not use it
        pass

0

Python'da __ kullanımını anlamak için bir örnek eklendi. İşte Tüm __ listesi

https://docs.python.org/3/genindex-all.html#_

Belirli tanımlayıcı sınıflarının (anahtar kelimelerin yanı sıra) özel anlamları vardır. Herhangi bir kullanımı * açıkça belgelenmiş kullanımını takip etmez başka bir bağlamda isimlerin, uyarı olmadan kırılma tabidir

__ kullanarak erişim kısıtlaması

"""
Identifiers:
-  Contain only (A-z, 0-9, and _ )
-  Start with a lowercase letter or _.
-  Single leading _ :  private
-  Double leading __ :  strong private
-  Start & End  __ : Language defined Special Name of Object/ Method
-  Class names start with an uppercase letter.
-

"""


class BankAccount(object):
    def __init__(self, name, money, password):
        self.name = name            # Public
        self._money = money         # Private : Package Level
        self.__password = password  # Super Private

    def earn_money(self, amount):
        self._money += amount
        print("Salary Received: ", amount, " Updated Balance is: ", self._money)

    def withdraw_money(self, amount):
        self._money -= amount
        print("Money Withdraw: ", amount, " Updated Balance is: ", self._money)

    def show_balance(self):
        print(" Current Balance is: ", self._money)


account = BankAccount("Hitesh", 1000, "PWD")  # Object Initalization

# Method Call
account.earn_money(100)

# Show Balance
print(account.show_balance())

print("PUBLIC ACCESS:", account.name)  # Public Access

# account._money is accessible because it is only hidden by convention
print("PROTECTED ACCESS:", account._money)  # Protected Access

# account.__password will throw error but account._BankAccount__password will not
# because __password is super private
print("PRIVATE ACCESS:", account._BankAccount__password)

# Method Call
account.withdraw_money(200)

# Show Balance
print(account.show_balance())

# account._money is accessible because it is only hidden by convention
print(account._money)  # Protected Access
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.