ใครช่วยอธิบายความหมายที่แท้จริงของการมีขีดเส้นใต้นำหน้าชื่อวัตถุใน Python และความแตกต่างระหว่างทั้งสองได้หรือไม่?
นอกจากนี้ความหมายนั้นยังคงเหมือนเดิมไม่ว่าวัตถุที่เป็นปัญหาจะเป็นตัวแปรฟังก์ชันวิธีการหรือไม่?
ใครช่วยอธิบายความหมายที่แท้จริงของการมีขีดเส้นใต้นำหน้าชื่อวัตถุใน Python และความแตกต่างระหว่างทั้งสองได้หรือไม่?
นอกจากนี้ความหมายนั้นยังคงเหมือนเดิมไม่ว่าวัตถุที่เป็นปัญหาจะเป็นตัวแปรฟังก์ชันวิธีการหรือไม่?
คำตอบ:
ชื่อในคลาสที่มีเครื่องหมายขีดเส้นใต้นำหน้าเป็นเพียงเพื่อบ่งบอกถึงโปรแกรมเมอร์คนอื่น ๆ ว่าคุณลักษณะหรือวิธีการนั้นมีวัตถุประสงค์เพื่อเป็นส่วนตัว อย่างไรก็ตามไม่มีอะไรพิเศษที่ทำกับชื่อตัวเอง
เพื่ออ้างอิงPEP-8 :
_single_leading_underscore: ตัวบ่งชี้ "การใช้ภายใน" อ่อน เช่น
from M import *
ไม่นำเข้าวัตถุที่ชื่อขึ้นต้นด้วยเครื่องหมายขีดล่าง
จากPython docs :
ตัวระบุใด ๆ ของแบบฟอร์ม
__spam
(อย่างน้อยสองเครื่องหมายขีดเส้นใต้ชั้นนำอย่างน้อยหนึ่งขีดขีดล่าง) จะถูกแทนที่ด้วยข้อความโดย_classname__spam
ที่classname
เป็นชื่อคลาสปัจจุบันที่มีเครื่องหมายขีดเส้นใต้นำอยู่ mangling นี้ทำโดยไม่คำนึงถึงตำแหน่งทางไวยากรณ์ของตัวระบุดังนั้นจึงสามารถใช้เพื่อกำหนดอินสแตนซ์ของคลาสส่วนตัวและตัวแปรคลาสวิธีการตัวแปรที่เก็บไว้ใน globals และแม้แต่ตัวแปรที่เก็บไว้ในอินสแตนซ์ ส่วนตัวกับคลาสนี้ในอินสแตนซ์ของคลาสอื่น
และคำเตือนจากหน้าเดียวกัน:
ชื่อ mangling มีจุดประสงค์เพื่อให้คลาสเป็นวิธีที่ง่ายในการกำหนดตัวแปรอินสแตนซ์ "ส่วนตัว" และวิธีการโดยไม่ต้องกังวลเกี่ยวกับตัวแปรอินสแตนซ์ที่กำหนดโดยคลาสที่ได้รับหรือการสิด้วยตัวแปรอินสแตนซ์ โปรดทราบว่ากฎ mangling ออกแบบมาเพื่อหลีกเลี่ยงอุบัติเหตุส่วนใหญ่ มันยังคงเป็นไปได้สำหรับจิตวิญญาณที่มุ่งมั่นที่จะเข้าถึงหรือแก้ไขตัวแปรที่ถือว่าเป็นส่วนตัว
>>> 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!'}
__
ขีดเส้นใต้คู่เพียงแค่เป็นชื่อตัวแปรคืออะไร? ชอบa, __ = foo()
คำตอบที่ยอดเยี่ยมจนถึงขณะนี้ แต่เกร็ดเล็กเกร็ดบางส่วนขาดหายไป เครื่องหมายขีดเส้นใต้เดียวนำหน้าไม่ได้เป็นเพียงแค่การประชุม: ถ้าคุณใช้from foobar import *
และโมดูลfoobar
ไม่ได้กำหนด__all__
รายการชื่อที่นำเข้าจากโมดูลจะไม่รวมสิ่งที่มีเครื่องหมายขีดเส้นใต้ สมมติว่าส่วนใหญ่เป็นการประชุมเนื่องจากกรณีนี้เป็นมุมที่ค่อนข้างคลุมเครือ ;-)
การประชุมระดับขีดถูกนำมาใช้กันอย่างแพร่หลายไม่เพียง แต่สำหรับส่วนตัวชื่อ แต่ยังสำหรับสิ่งที่ C ++ จะเรียกการคุ้มครองคน - ตัวอย่างเช่นชื่อของวิธีการที่มีความตั้งใจอย่างเต็มที่ที่จะถูกแทนที่โดย subclasses (แม้คนที่มีที่จะแทนที่เนื่องจากใน คลาสฐานพวกเขาraise NotImplementedError
! -) มักจะเป็นชื่อเดียวที่ขีดเส้นใต้เดียวเพื่อระบุถึงรหัสโดยใช้อินสแตนซ์ของคลาสนั้น (หรือคลาสย่อย) ที่วิธีการดังกล่าวไม่ได้ตั้งใจจะเรียกโดยตรง
ตัวอย่างเช่นเมื่อต้องการสร้างคิวแบบเธรดที่ปลอดภัยด้วยวินัยการจัดคิวที่แตกต่างจาก FIFO ให้อิมพอร์ตคิวหนึ่งคลาสย่อยคิวคิวคิวและแทนที่เมธอดดังกล่าวเป็น_get
และ_put
; "รหัสลูกค้า" ไม่เคยเรียกวิธีการเหล่านั้น ("hook") แต่เป็นวิธีการสาธารณะ ("การจัดระเบียบ") เช่นput
และget
(ซึ่งเป็นที่รู้จักกันในรูปแบบการออกแบบวิธีแม่แบบ - ดูตัวอย่างที่นี่เพื่อการนำเสนอที่น่าสนใจจากวิดีโอ ของการพูดคุยของฉันในเรื่องด้วยการเพิ่มบทสรุปของการถอดเสียง)
แก้ไข: ลิงก์วิดีโอในคำอธิบายของการเจรจาขาดไป คุณสามารถค้นหาวิดีโอสองครั้งแรกที่นี่และที่นี่
_var_name
หรือใช้var_name
+ ยกเว้นมันได้__all__
อย่างไร
__all__
ทุกครั้งที่คุณต้องการทำให้โมดูลfrom spam import *
เป็นมิตร (รวมถึงที่ล่ามแบบโต้ตอบ) ดังนั้นเวลาส่วนใหญ่ของคำตอบคือทั้งสอง
_
เห็นได้ชัดว่าฉันกำลังพูดถึงการเปรียบเทียบเนื่องจากไม่มีอะไรเป็นส่วนตัวอย่างแท้จริงใน Python เมื่อดำน้ำในความหมายฉันจะบอกว่าเราสามารถผูกกับ_
การป้องกันของ Java ตั้งแต่proctectedใน Java หมายถึง "เรียนที่ได้รับและ / หรือภายในแพคเกจเดียวกัน" แทนที่แพ็คเกจด้วยโมดูลเนื่องจาก PEP8 แจ้งให้เราทราบว่า_
ไม่ใช่เพียงแค่การประชุมเมื่อพูดถึง*
การนำเข้าและคุณก็มี และแน่นอน__
จะเทียบเท่ากับ Java ส่วนตัวเมื่อพูดถึงตัวระบุภายในชั้นเรียน
__foo__
: นี่เป็นเพียงข้อตกลงวิธีสำหรับระบบ Python ในการใช้ชื่อที่จะไม่ขัดแย้งกับชื่อผู้ใช้
_foo
: นี่เป็นเพียงการประชุมวิธีที่โปรแกรมเมอร์จะระบุว่าตัวแปรนั้นเป็นแบบส่วนตัว (ไม่ว่าจะมีความหมายอะไรใน Python)
__foo
: นี่มีความหมายที่แท้จริง: ล่ามมาแทนที่ชื่อนี้ด้วย_classname__foo
เพื่อให้แน่ใจว่าชื่อจะไม่ทับซ้อนกับชื่อที่คล้ายกันในคลาสอื่น
ไม่มีรูปแบบอื่น ๆ ของขีดเส้นใต้มีความหมายในโลกหลาม
ไม่มีความแตกต่างระหว่างคลาสตัวแปรโกลบอลและอื่น ๆ ในแบบแผนเหล่านี้
__foo
และอยากรู้อยากเห็น มันจะทับซ้อนกับชื่อเมธอดที่คล้ายกันกับคลาสอื่นได้อย่างไร? ฉันหมายความว่าคุณยังคงต้องเข้าถึงมันเหมือนinstance.__foo()
(ถ้ามันไม่ได้เปลี่ยนชื่อโดยล่าม) ใช่ไหม?
from module import *
จะไม่นำเข้าวัตถุที่อยู่ใต้คำนำหน้า ดังนั้น_foo
เป็นมากกว่าแค่การประชุม
B
ชั้นย่อยA
และทั้งสองใช้foo()
แล้วB.foo()
จะลบล้างสืบทอดมาจาก.foo()
A
ตัวอย่างของการB
จะสามารถเข้าถึงยกเว้นผ่านB.foo()
super(B).foo()
__dunder__
ชื่อการร้องขอโดยนัยข้ามพจนานุกรมอินสแตนซ์ดังนั้นจึงอาจเป็นมากกว่าเพียงแค่แผนการตั้งชื่อในบางกรณี (ดูที่ส่วนวิธีการค้นหาพิเศษใน datamodel)
._variable
เป็นแบบกึ่งอิสระและมีความหมายสำหรับการประชุมเท่านั้น
.__variable
มักถูกพิจารณาว่าเป็น superprivate อย่างไม่ถูกต้องในขณะที่ความหมายที่แท้จริงคือเพียง namemangle เพื่อป้องกันการเข้าถึงโดยไม่ตั้งใจ[1]
.__variable__
โดยทั่วไปจะสงวนไว้สำหรับวิธีการหรือตัวแปรในตัว
คุณยังคงสามารถเข้าถึง.__mangled
ตัวแปรได้หากคุณต้องการอย่างยิ่ง เครื่องหมายขีดล่างคู่เป็นเพียง namemangles หรือเปลี่ยนชื่อตัวแปรเป็นอย่างเช่นinstance._className__mangled
ตัวอย่าง:
class Test(object):
def __init__(self):
self.__a = 'a'
self._b = 'b'
>>> t = Test()
>>> t._b
'b'
t._b สามารถเข้าถึงได้เพราะถูกซ่อนไว้โดยการประชุมเท่านั้น
>>> t.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
t .__ a ไม่พบเพราะไม่มีอีกแล้วเนื่องจาก namemangling
>>> t._Test__a
'a'
ด้วยการเข้าถึงinstance._className__variable
แทนที่จะใช้ชื่อขีดเส้นใต้คู่คุณสามารถเข้าถึงค่าที่ซ่อนอยู่ได้
ขีดเส้นใต้เดี่ยวที่จุดเริ่มต้น:
Python ไม่มีวิธีการส่วนตัวที่แท้จริง แทนหนึ่งขีดล่างที่จุดเริ่มต้นของวิธีการหรือชื่อแอตทริบิวต์หมายความว่าคุณไม่ควรเข้าถึงวิธีนี้เพราะไม่ใช่ส่วนหนึ่งของ API
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)
(ข้อมูลโค้ดนี้นำมาจากซอร์สโค้ด django: django / forms / forms.py) ในรหัสerrors
นี้เป็นคุณสมบัติสาธารณะ แต่วิธีที่คุณสมบัตินี้เรียกว่า _get_errors เป็น "ส่วนตัว" ดังนั้นคุณไม่ควรเข้าถึง
ขีดเส้นใต้สองอันที่จุดเริ่มต้น:
ทำให้เกิดความสับสนมาก ไม่ควรใช้เพื่อสร้างวิธีการส่วนตัว มันควรจะใช้เพื่อหลีกเลี่ยงวิธีการของคุณถูกแทนที่โดยคลาสย่อยหรือเข้าถึงโดยไม่ตั้งใจ ลองดูตัวอย่าง:
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!
เอาท์พุท:
$ python test.py
I'm test method in class A
I'm test method in class A
ตอนนี้สร้างคลาสย่อย B และทำการปรับแต่งสำหรับเมธอด __test
class B(A):
def __test(self):
print "I'm test method in class B"
b = B()
b.test()
ผลผลิตจะเป็น ....
$ python test.py
I'm test method in class A
ดังที่เราได้เห็น A.test () ไม่ได้เรียกวิธีการทดสอบ B .__ () ตามที่เราคาดหวัง แต่อันที่จริงนี่เป็นพฤติกรรมที่ถูกต้องสำหรับ __ วิธีการสองวิธีที่เรียกว่า __test () จะถูกเปลี่ยนชื่อโดยอัตโนมัติ (mangled) เป็น _A__test () และ _B__test () ดังนั้นพวกเขาจึงไม่ได้แทนที่โดยไม่ตั้งใจ เมื่อคุณสร้างวิธีการที่เริ่มต้นด้วย __ หมายความว่าคุณไม่ต้องการให้ใครก็ตามสามารถลบล้างมันได้และคุณตั้งใจจะเข้าถึงจากภายในชั้นเรียนของตัวเองเท่านั้น
ขีดเส้นใต้สองอันที่จุดเริ่มต้นและตอนท้าย:
เมื่อเราเห็นวิธีที่ชอบ__this__
อย่าเรียกมันว่า นี่คือวิธีการที่หลามมีไว้สำหรับโทรหาไม่ใช่คุณ ลองดู:
>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11
>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60
มีโอเปอเรเตอร์หรือฟังก์ชันเนทีฟเสมอซึ่งเรียกวิธีการเวทย์มนตร์เหล่านี้ บางครั้งมันเป็นเพียงการขอหลามแบบหลามในบางสถานการณ์ ตัวอย่างเช่น__init__()
เรียกว่าเมื่อวัตถุถูกสร้างขึ้นหลังจาก__new__()
ถูกเรียกให้สร้างตัวอย่าง ...
ลองยกตัวอย่าง ...
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
สำหรับรายละเอียดเพิ่มเติมโปรดดูที่คู่มือ PEP-8 สำหรับวิธีมหัศจรรย์เพิ่มเติมให้ดูPDFนี้
บางครั้งคุณมีสิ่งที่ดูเหมือนจะเป็น tuple กับขีดเส้นใต้นำใน
def foo(bar):
return _('my_' + bar)
ในกรณีนี้สิ่งที่เกิดขึ้นคือ _ () เป็นนามแฝงสำหรับฟังก์ชั่นการโลคัลไลซ์เซชันที่ทำงานกับข้อความเพื่อให้มันเป็นภาษาที่เหมาะสมและอื่น ๆ ตามสถานที่เกิดเหตุ ตัวอย่างเช่นสฟิงซ์ทำสิ่งนี้และคุณจะพบกับการนำเข้า
from sphinx.locale import l_, _
และใน sphinx.locale, _ () ถูกกำหนดให้เป็นนามแฝงของฟังก์ชั่นการแปลบางภาษา
เนื่องจากผู้คนมากมายพูดถึงการพูดคุยของเรย์มอนด์ฉันจะทำให้มันง่ายขึ้นโดยเขียนสิ่งที่เขาพูดว่า:
ความตั้งใจของขีดเส้นใต้คู่ไม่ได้เกี่ยวกับความเป็นส่วนตัว ความตั้งใจที่จะใช้มันอย่างนี้
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
จริงๆแล้วมันตรงกันข้ามกับความเป็นส่วนตัวมันคือทั้งหมดที่เกี่ยวกับอิสรภาพ มันทำให้ subclasses ของคุณฟรีที่จะแทนที่ใดวิธีการหนึ่งโดยไม่ทำลายคนอื่น ๆ
สมมติว่าคุณไม่ให้มีการอ้างอิงของท้องถิ่นในperimeter
Circle
ตอนนี้ชั้นมาTire
แทนที่การดำเนินการโดยไม่ต้องสัมผัสperimeter
area
เมื่อคุณโทรTire(5).area()
ในทางทฤษฎีมันควรจะใช้Circle.perimeter
สำหรับการคำนวณ แต่ในความเป็นจริงมันกำลังใช้Tire.perimeter
ซึ่งไม่ใช่พฤติกรรมที่ตั้งใจ นั่นเป็นเหตุผลที่เราต้องการการอ้างอิงในแวดวง
แต่ทำไม__perimeter
แทน_perimeter
? เพราะ_perimeter
ยังให้ชั้นเรียนที่ได้รับโอกาสในการแทนที่:
class Tire(Circle):
def perimeter(self):
return Circle.perimeter(self) * 1.25
_perimeter = perimeter
เครื่องหมายขีดล่างคู่มีชื่อเป็น mangling ดังนั้นจึงมีโอกาสน้อยมากที่การอ้างอิงแบบโลคัลในคลาสพาเรนต์จะถูกแทนที่ในคลาสที่ได้รับ ดังนั้น " ทำให้คลาสย่อยของคุณมีอิสระที่จะแทนที่วิธีใดวิธีหนึ่งโดยไม่ทำให้ส่วนย่อยอื่น "
__double_leading_underscore
ถ้าชั้นของคุณจะไม่ได้รับมรดกหรือวิธีการเอาชนะไม่ได้ทำลายอะไรแล้วคุณก็ไม่จำเป็นต้อง
หากต้องการทำให้ตัวแปรเป็นแบบอ่านอย่างเดียว IMHO วิธีที่ดีที่สุดคือการใช้คุณสมบัติ () โดยมีเพียง getter เท่านั้นที่ส่งผ่านไป ด้วยคุณสมบัติ () เราสามารถควบคุมข้อมูลได้อย่างสมบูรณ์
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 ถามคำถามที่แตกต่างออกไปเล็กน้อย แต่เนื่องจากฉันพบคำถามอื่นที่ขอคำว่า 'วิธีการตั้งค่าตัวแปรส่วนตัว' ซ้ำกับคำถามนี้ฉันจึงคิดว่าจะเพิ่มข้อมูลเพิ่มเติมที่นี่
ไปที่https://dbader.org/blog/meaning-of-underscores-in-python
คำตอบที่ยอดเยี่ยมและถูกต้องฉันได้ให้ตัวอย่างง่ายๆพร้อมกับคำนิยาม / ความหมายที่เรียบง่าย
ความหมาย:
some_variable --►เป็นสาธารณะทุกคนสามารถดูได้
_some_variable - ►เป็นสาธารณะทุกคนสามารถดูสิ่งนี้ได้ แต่เป็นแบบแผนเพื่อระบุว่าเป็นส่วนตัว ... การเตือนห้ามใช้ Python
__some_varaible - ► Python แทนที่ชื่อตัวแปรด้วย _classname__some_varaible (ชื่อ AKA ชื่อ mangling) และลด / ซ่อนการมองเห็นและเป็นเหมือนตัวแปรส่วนตัว
เพียงเพื่อความซื่อสัตย์ที่นี่ตามเอกสาร Python
ตัวแปรอินสแตนซ์ "ส่วนตัว" ที่ไม่สามารถเข้าถึงได้ยกเว้นจากภายในวัตถุไม่มีอยู่ใน Python "
ตัวอย่าง:
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)
การขีดเส้นใต้เดี่ยวชั้นนำเป็นการประชุม ไม่มีความแตกต่างจากมุมมองของล่ามหากชื่อเริ่มต้นด้วยการขีดเส้นใต้เดียวหรือไม่
ดับเบิลขีดชั้นนำและต่อท้ายจะใช้สำหรับในตัววิธีการเช่น__init__
, __bool__
ฯลฯ
เครื่องหมายขีดล่างคู่ที่ไม่มีคู่ท้ายเป็นระเบียบเช่นกันอย่างไรก็ตามเมธอดคลาสจะถูกmangledโดยล่าม สำหรับตัวแปรหรือชื่อฟังก์ชั่นพื้นฐานไม่มีความแตกต่าง
คำถามของคุณดีไม่เพียงเกี่ยวกับวิธีการเท่านั้น ฟังก์ชั่นและวัตถุในโมดูลมักจะนำหน้าด้วยการขีดเส้นใต้อย่างใดอย่างหนึ่งเช่นกันและสามารถนำหน้าด้วยสอง
แต่ชื่อ __double_underscore ไม่ใช่ชื่อที่ mangled ในโมดูลตัวอย่างเช่น สิ่งที่เกิดขึ้นคือชื่อที่ขึ้นต้นด้วยเครื่องหมายขีดล่างหนึ่ง (หรือมากกว่า) จะไม่ถูกนำเข้าหากคุณนำเข้าทั้งหมดจากโมดูล (จากโมดูลนำเข้า *) หรือชื่อที่แสดงในวิธีใช้ (โมดูล)
นี่คือตัวอย่างที่เรียบง่ายเกี่ยวกับวิธีที่คุณสมบัติขีดเส้นใต้คู่สามารถส่งผลกระทบต่อคลาสที่สืบทอด ดังนั้นด้วยการตั้งค่าต่อไปนี้:
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"
หากคุณสร้างอินสแตนซ์ลูกใน python REPL คุณจะเห็นด้านล่าง
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'
สิ่งนี้อาจเห็นได้ชัดสำหรับบางคน แต่มันทำให้ฉันระวังตัวในสภาพแวดล้อมที่ซับซ้อนกว่านี้มาก
ตัวแปรอินสแตนซ์“ ส่วนตัว” ที่ไม่สามารถเข้าถึงได้ยกเว้นจากภายในวัตถุไม่มีอยู่ใน Python อย่างไรก็ตามมีการประชุมที่ตามด้วยรหัส Python ส่วนใหญ่: ชื่อที่นำหน้าด้วยเครื่องหมายขีดล่าง (เช่น _spam) ควรได้รับการปฏิบัติเสมือนเป็นส่วนที่ไม่เปิดเผยต่อสาธารณะของ API (ไม่ว่าจะเป็นฟังก์ชันวิธีการหรือสมาชิกข้อมูล) . ควรพิจารณารายละเอียดการดำเนินการและอาจมีการเปลี่ยนแปลงโดยไม่ต้องแจ้งให้ทราบล่วงหน้า
การอ้างอิง https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
การรับข้อเท็จจริงของ _ และ __ นั้นง่ายมาก คำตอบอื่น ๆ แสดงพวกเขาค่อนข้างดี การใช้งานนั้นยากต่อการพิจารณา
นี่คือวิธีที่ฉันเห็น:
_
ควรใช้เพื่อระบุว่าฟังก์ชั่นนั้นไม่ได้มีไว้สำหรับการใช้สาธารณะเช่นเป็น API สิ่งนี้และข้อ จำกัด การนำเข้าทำให้มันทำงานเหมือนinternal
ใน c #
__
ควรใช้เพื่อหลีกเลี่ยงการชนกันของชื่อในลำดับชั้นของสืบทอดและเพื่อหลีกเลี่ยงการผูกปลาย เหมือนส่วนตัวใน c #
==>
หากคุณต้องการที่จะแสดงให้เห็นอะไรบางอย่างที่ไม่ได้สำหรับการใช้ที่สาธารณะ แต่มันควรจะทำหน้าที่เหมือนการใช้งานprotected
_
หากคุณต้องการที่จะแสดงให้เห็นอะไรบางอย่างที่ไม่ได้สำหรับการใช้ที่สาธารณะ แต่มันควรจะทำหน้าที่เหมือนการใช้งานprivate
__
นี่เป็นคำพูดที่ฉันชอบมาก:
ปัญหาคือผู้แต่งชั้นเรียนอาจคิดว่า "ชื่อแอตทริบิวต์ / วิธีการนี้ควรเป็นส่วนตัวโดยสามารถเข้าถึงได้จากภายในคำจำกัดความของชั้นนี้เท่านั้น" และใช้ __private Convention แต่ในภายหลังผู้ใช้ของคลาสนั้นอาจสร้างคลาสย่อยที่ถูกต้องตามกฎหมายต้องเข้าถึงชื่อนั้น ดังนั้นทั้งคลาสซูเปอร์จะต้องมีการแก้ไข (ซึ่งอาจเป็นเรื่องยากหรือเป็นไปไม่ได้) หรือรหัสย่อยต้องใช้ชื่อ mangled ด้วยตนเอง (ซึ่งน่าเกลียดและเปราะบางที่สุด)
แต่ปัญหาที่อยู่ในความคิดของฉันว่าถ้าไม่มี IDE ที่เตือนคุณเมื่อคุณแทนที่วิธีการค้นหาข้อผิดพลาดอาจใช้เวลาสักครู่ถ้าคุณมีวิธีการ overriden จากคลาสฐานโดยไม่ได้ตั้งใจ