Python มีตัวแปร "ส่วนตัว" ในชั้นเรียนหรือไม่?


578

ฉันมาจากโลก Java และการอ่านบรูซ Eckels' งูใหญ่ 3 รูปแบบสูตรและสำนวน

ในขณะที่อ่านเกี่ยวกับคลาสมันจะบอกว่าใน Python ไม่จำเป็นต้องประกาศตัวแปรอินสแตนซ์ คุณเพียงแค่ใช้พวกมันในตัวสร้างและบูมพวกมันอยู่ที่นั่น

ตัวอย่างเช่น:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

หากเป็นจริงวัตถุของคลาสใด ๆ ก็Simpleสามารถเปลี่ยนค่าของตัวแปรsนอกคลาสได้

ตัวอย่างเช่น:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

ใน Java เราได้รับการสอนเกี่ยวกับตัวแปรสาธารณะ / ส่วนตัว / ที่มีการป้องกัน คำหลักเหล่านั้นสมเหตุสมผลเพราะในบางครั้งคุณต้องการตัวแปรในคลาสที่ไม่มีใครอยู่นอกชั้นเรียนสามารถเข้าถึงได้

เหตุใดจึงไม่จำเป็นใน Python


17
คุณหมายถึงตัวแปรอินสแตนซ์ไม่ใช่ตัวแปรคลาสใช่มั้ย
PaulMcG

13
คุณควรตรวจสอบคุณสมบัติ: docs.python.org/library/functions.html#property เพียงใช้ทะเยอทะยานและตัวแปรของคุณจะได้รับการคุ้มครอง
rubik

คำตอบที่สั้นและคมชัดเป็นที่นี่ ฉันหวังว่านี่จะช่วยได้
Premkumar chalmeti

คำตอบ:


962

มันเป็นวัฒนธรรม ใน Python คุณไม่ได้เขียนอินสแตนซ์ของคลาสอื่นหรือตัวแปรคลาส ใน Java ไม่มีสิ่งใดที่ป้องกันไม่ให้คุณทำสิ่งเดียวกันถ้าคุณต้องการจริงๆคุณสามารถแก้ไขที่มาของคลาสตัวเองเพื่อให้ได้ผลเช่นเดียวกัน Python ลดระดับความปลอดภัยลงและกระตุ้นให้โปรแกรมเมอร์มีความรับผิดชอบ ในทางปฏิบัติมันใช้งานได้ดีมาก

หากคุณต้องการที่จะเลียนแบบตัวแปรส่วนตัวด้วยเหตุผลบางอย่างคุณก็สามารถใช้__คำนำหน้าจากPEP 8 Python รวบรวมชื่อของตัวแปรเช่น__fooนั้นไว้เพื่อไม่ให้สามารถมองเห็นโค้ดภายนอกคลาสที่มีตัวแปรเหล่านั้นได้อย่างง่ายดาย (แม้ว่าคุณจะสามารถหลีกเลี่ยงได้ถ้าคุณตั้งใจมากพอเช่นเดียวกับที่คุณสามารถป้องกัน Java ได้หากคุณทำงาน )

ในการประชุมเดียวกัน_คำนำหน้าหมายถึงอยู่ห่าง ๆ แม้ว่าคุณจะไม่ได้รับการป้องกันในทางเทคนิคก็ตาม คุณไม่ได้เล่นรอบกับตัวแปรของชั้นอื่นที่มีลักษณะเหมือนหรือ__foo_bar


14
นั่นทำให้รู้สึก อย่างไรก็ตามฉันไม่คิดว่าจะมีวิธีใดในจาวาที่จะเข้าถึงตัวแปรส่วนตัวนอกคลาส (ยกเว้นการเปลี่ยนแหล่งที่มาของคลาสของหลักสูตร) มีอะไรบ้าง
อยู่ทั่วไปทุกหนทุกแห่ง

168
ฉันมักจะชอบวิธีงูใหญ่ แต่ฉันไม่คิดว่าวิธี java จะไม่มีประโยชน์เท่าที่คุณทำออกมา การประกาศสิ่งที่เป็นส่วนตัวอย่างรวดเร็วบอกใครบางคนที่กำลังอ่านโค้ดบางอย่างที่มีประโยชน์มาก: ฟิลด์นี้มีการแก้ไขภายในคลาสนี้เท่านั้น
เน็ด

67
@Omnipresent คุณสามารถใช้การสะท้อน
rapadura

76
ให้ฉันได้สิ่งนี้โดยตรงดังนั้น Python จึงไม่ใช้คุณลักษณะสาธารณะหรือส่วนตัวเพราะ "เป็นข้ออ้างเรื่องความปลอดภัยและสนับสนุนให้โปรแกรมเมอร์รับผิดชอบ" อย่างไรก็ตามชุมชนสนับสนุนให้ใช้ "_" เพื่อแสดงถึงตัวแปรและวิธีการส่วนตัว? บางทีไพ ธ อนควรจะมีหมายเลขสาธารณะและส่วนตัวอย่างแน่นอน? วัตถุประสงค์หลักของพวกเขาคือเพื่อบอกคุณว่า API ที่คุณควรใช้เพื่อโต้ตอบกับชั้นเรียน พวกเขาทำหน้าที่เป็นเอกสารที่บอกให้คุณใช้วิธีการเหล่านี้และไม่ใช้สิ่งเหล่านั้น พวกเขาไม่ใช่ "ข้ออ้างเรื่องความปลอดภัย" เป็นเอกสาร API ซึ่ง IDE สามารถใช้เพื่อแนะนำคุณได้!
PedroD

19
นี่เป็นคำตอบที่ดีและการใช้เหตุผลของคุณนั้นถูกต้อง แต่ฉันไม่เห็นด้วยกับแง่มุมหนึ่ง วัตถุประสงค์ของการปรับเปลี่ยนการเข้าถึงที่ไม่เคยมีการรักษาความปลอดภัย แต่เป็นวิธีการแบ่งเขตอย่างชัดเจน (และในระดับสูงการบังคับใช้) ว่าส่วนใดของชั้นเรียนที่ถือว่าเป็นส่วนภายในและมีการเปิดเผยต่อผู้ใช้ภายนอกของชั้นเรียนนั้น อนุสัญญา (วัฒนธรรม) เป็นทางเลือกที่ถูกต้องแน่นอนในการเข้าถึงตัวดัดแปลงและทั้งสองวิธีมีข้อดีข้อเสีย แต่มันก็ทำให้เข้าใจผิดว่าจุดประสงค์ในการปรับเปลี่ยนการเข้าถึงระดับภาษานั้นมีจุดประสงค์เพื่อ "ปลอดภัย" ในทางปกติ คำ.
devios1

159

ตัวแปรส่วนตัวในไพ ธ อนมีการแฮ็กมากขึ้นหรือน้อยลงล่ามจะทำการเปลี่ยนชื่อตัวแปรโดยเจตนา

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

ตอนนี้ถ้าคุณพยายามเข้าถึง__varนอกคำจำกัดความของคลาสมันจะล้มเหลว:

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

แต่คุณสามารถหลีกเลี่ยงสิ่งนี้ได้โดยง่าย:

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

คุณอาจรู้ว่ามีการเรียกใช้เมธอดใน OOP เช่นนี้: x.printVar() => A.printVar(x)หากA.printVar()สามารถเข้าถึงบางฟิลด์ในได้xฟิลด์นี้สามารถเข้าถึงได้นอก A.printVar() ... หลังจากทั้งหมดฟังก์ชั่นถูกสร้างขึ้นเพื่อนำมาใช้ซ้ำได้ไม่มีอำนาจพิเศษใด ๆ

เกมจะแตกต่างเมื่อมีคอมไพเลอร์ที่เกี่ยวข้อง ( ความเป็นส่วนตัวเป็นแนวคิดระดับคอมไพเลอร์ ) รู้เกี่ยวกับคำจำกัดความของคลาสด้วยตัวดัดแปลงการควบคุมการเข้าถึงเพื่อให้สามารถเกิดข้อผิดพลาดได้หากไม่ปฏิบัติตามกฎในเวลารวบรวม


3
ในระยะสั้นนี่ไม่ใช่การห่อหุ้ม
watashiSHUN

2
ฉันสงสัยว่า PHP มีบางสิ่งที่คล้ายคลึงกับตัวแปรส่วนตัวที่โง่ ๆ หรือไม่เนื่องจากตัวแปรส่วนตัวไม่ค่อยเข้าใจในภาษาที่แปลแล้ว - ฉันหมายถึงการเพิ่มประสิทธิภาพสิ่งที่สามารถทำได้เมื่อรู้ว่าตัวแปร x เป็นส่วนตัวหรือไม่ถ้าไม่ได้รวบรวม?
NoBugs

1
เราจะสุ่มรูปแบบของตัวแปรส่วนตัวได้อย่างไร
crisron

@crisron คำถามเดียวกัน
IanS

5
@watashiSHUN "โดยย่อนี่ไม่ใช่การห่อหุ้ม" => ใช่ การห่อหุ้มนั้นเกี่ยวกับการใช้ API สาธารณะเท่านั้นดังนั้นรหัสลูกค้าจะได้รับการปกป้องจากการเปลี่ยนแปลงการใช้งาน ระเบียบการตั้งชื่อเป็นวิธีที่ถูกต้องสมบูรณ์ในการบอกว่า API คืออะไรและมีการนำไปใช้อย่างไรและประเด็นก็คือว่ามันใช้ได้
bruno desthuilliers

30

ตามที่กล่าวไว้อย่างถูกต้องโดยความคิดเห็นหลายข้อข้างต้นอย่าลืมเป้าหมายหลักของ Access Modifiers: เพื่อช่วยให้ผู้ใช้รหัสเข้าใจสิ่งที่ควรเปลี่ยนและสิ่งที่ไม่ควรทำ เมื่อคุณเห็นเขตข้อมูลส่วนตัวคุณจะไม่ยุ่งกับมัน ดังนั้นมันจึงเป็นน้ำตาลซินแทคติคซึ่งสามารถทำได้ง่ายใน Python โดย _ และ __


4
ฉันคิดว่านี่เป็นประเด็นที่สำคัญมาก เมื่อทำการดีบั๊กโค้ด (ฉันรู้ว่าฉันอ่อนแอเพื่อแนะนำบั๊ก) รู้ว่าคลาสใดที่สามารถเปลี่ยนตัวแปรสมาชิกทำให้กระบวนการดีบักง่ายขึ้น อย่างน้อยถ้าตัวแปรได้รับการคุ้มครองโดยขอบเขตบางอย่าง แนวคิดที่คล้ายกันคือฟังก์ชัน const ใน C ++ ฉันรู้ว่าตัวแปรของสมาชิกไม่ได้มีการเปลี่ยนแปลงดังนั้นฉันจึงไม่ได้ดูวิธีการนั้นเนื่องจากสาเหตุที่เป็นไปได้ของการตั้งค่าตัวแปรที่ไม่ดี แม้ว่าจะสามารถพัฒนาคุณสมบัติเพิ่มเติมสำหรับส่วนขยาย / เพิ่มคลาสได้ แต่การ จำกัด การมองเห็นโค้ดทำให้ง่ายต่อการตรวจแก้จุดบกพร่อง
MrMas

18

มีตัวแปรส่วนบุคคลในการประชุมที่ขีดล่าง

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

มีความแตกต่างเล็กน้อย แต่เพื่อความบริสุทธิ์ของรูปแบบการเขียนโปรแกรมอุดมการณ์ดีพอ

มีตัวอย่างจากผู้ตกแต่งส่วนบุคคลที่ @private ซึ่งใช้แนวคิดนี้อย่างใกล้ชิดมากกว่า แต่เป็น YMMV เนื้อหาที่เราสามารถเขียนคลาส defintion ที่ใช้เมตา


14
ฉันรู้ว่ามันค่อนข้างช้าไปงานปาร์ตี้ แต่ลิงค์นี้จะปรากฏขึ้นบน google เมื่อ googling ปัญหา สิ่งนี้ไม่ได้บอกเรื่องราวทั้งหมด __xเนื่องจากตัวแปรภายในคลาสAนั้นถูกคอมไพเลอร์เขียนใหม่ไปจริง ๆ_A__xมันยังไม่เป็นส่วนตัวอย่างสมบูรณ์และยังสามารถเข้าถึง
Zorf

1
แน่นอนถ้าฉันเห็นตัวแปรชื่อ_A__xฉันจะไม่แตะต้องมัน อาจติดต่อได้ ฉันจะหนีจากมันไป
Mateen Ulhaq

แน่นอนว่ามันไม่ได้เป็นส่วนตัวอย่างแท้จริง แต่เหตุผลหลักสำหรับการบังคับใช้ยากส่วนตัวใน C ++ และ Java (ฯลฯ ) การเพิ่มประสิทธิภาพของคอมไพเลอร์ไม่ได้มีอยู่จริงใน Python ดังนั้นการประชุมโดยส่วนตัวก็ดีพอ โดยทั่วไปแล้วการประชุมงูใหญ่นั้นเชื่อมั่นว่าคุณจะประพฤติตนโดยไม่มีการควบคุม (และเป็นกับดักของมือใหม่ แต่คุณก็รู้ แต่เพียงการไตร่ตรองเกี่ยวกับการออกแบบและการบริโภคในชั้นเรียน)
Shayne

14

"ใน java เราได้รับการสอนเกี่ยวกับตัวแปรสาธารณะ / ส่วนตัว / ที่มีการป้องกัน"

"ทำไมถึงไม่จำเป็นในงูใหญ่"

ด้วยเหตุผลเดียวกันมันไม่จำเป็นใน Java

คุณมีอิสระในการใช้งาน - หรือไม่ใช้และprivateprotected

ในฐานะที่เป็นโปรแกรมเมอร์ Python และ Java ฉันพบว่าprivateและprotectedเป็นแนวคิดการออกแบบที่สำคัญมาก แต่เป็นเรื่องจริงในนับหมื่นของเส้นของ Java และ Python ฉันไม่เคยจริงใช้หรือprivateprotected

ทำไมจะไม่ล่ะ?

นี่คือคำถามของฉัน "ป้องกันจากใคร"

โปรแกรมเมอร์คนอื่นในทีมของฉัน? พวกเขามีแหล่งที่มา การป้องกันหมายถึงอะไรเมื่อพวกเขาสามารถเปลี่ยนแปลงได้

โปรแกรมเมอร์คนอื่นในทีมอื่น ๆ ? พวกเขาทำงานให้กับ บริษัท เดียวกัน พวกเขาสามารถ - ด้วยการโทรศัพท์ - รับแหล่งที่มา

ลูกค้าได้อย่างไร มันเป็นโปรแกรมการจ้างงาน (โดยทั่วไป) ลูกค้า (โดยทั่วไป) เป็นเจ้าของรหัส

ดังนั้นฉันจะปกป้องใครจากใคร


118
-1: ฉันเห็นด้วยกับ Porculus มันไม่เกี่ยวกับการห้ามการเข้าถึงหรือซ่อนอะไรบางอย่างมันเกี่ยวกับเอกสาร API โดยนัย นักพัฒนารวมถึงคอมไพเลอร์ / ล่าม / ตัวตรวจสอบรหัสดูว่าสมาชิกคนไหนแนะนำให้ใช้และคนที่ไม่ควรแตะต้อง (หรืออย่างน้อยก็ต้องระวังด้วย) ในกรณีส่วนใหญ่มันจะเป็นเรื่องที่น่ากลัวหากสมาชิกทุกคนในชั้นเรียนหรือหน่วยงานสาธารณะ พิจารณาความแตกต่างของสมาชิกส่วนตัว / ที่ได้รับความคุ้มครอง / สาธารณะว่าเป็นบริการโดยกล่าวว่า "เฮ้สมาชิกเหล่านี้มีความสำคัญในขณะที่สมาชิกเหล่านั้นถูกใช้ภายในและอาจไม่เป็นประโยชน์สำหรับคุณ"
Oben Sonne

7
@ S.Lott: ฉันยอมรับว่าเอกสาร API มีลำดับความสำคัญสูงกว่าและบ่อยครั้งเป็นวิธีเดียวที่จะสื่อสารการใช้ API ที่ต้องการ แต่บางครั้งชื่อสมาชิกและการมองเห็น (ในแง่ของส่วนตัว / สาธารณะ) พูดอย่างเพียงพอด้วยตนเอง นอกจากนี้ฉันเห็นจุดของคุณว่าแนวคิดของเอกสารโดยนัยทำงานได้ไม่ดีนักในการตรวจสอบโดยไม่มี API แต่มันมีประโยชน์จริง ๆ ใน IDE ที่มีการทำให้โค้ดเสร็จสมบูรณ์ สมมติว่าคุณได้อ่านเอกสาร API แล้วเมื่อไม่นานมานี้มันช่วยให้คุณจำวิธีใช้คลาสได้ สิ่งต่าง ๆ ไม่ได้ผลที่ฉลาดถ้าไม่มีความแตกต่างระหว่างสมาชิกส่วนตัวและสาธารณะ
Oben Sonne

21
การอภิปรายล่าช้า แต่ทุกอย่าง Porculus และ Oben กำลังร้องขอที่นี่ได้รับการจัดการอย่างสมบูรณ์แบบเพียงพอโดยการประชุม "คำนำหน้าด้วยการขีดเส้นใต้" (และไม่มีอันตรายใด ๆ ที่บังคับใช้คอมไพเลอร์ของการประชุมนั้น)
ncoghlan

38
@ S.Lott ฉันไม่ใช่คนงูใหญ่ดังนั้นฉันจะไม่แสดงความคิดเห็นจากมุมมองนั้น อย่างไรก็ตามในฐานะนักพัฒนาจาวานี่เป็นคำแนะนำที่น่ากลัวอย่างแท้จริง -1
dbyrne

11
ว้าว. คุณพลาดประเด็นไปอย่างสิ้นเชิงคุณให้คำแนะนำที่แย่มากคุณดูถูกคนที่ไม่เห็นด้วยกับคุณในจุดนี้ แต่คุณยังคงได้รับป้ายและคะแนนชื่อเสียงกว่า 1,000 คำสำหรับคำตอบนี้
Eric Duminil

12

ดังที่ได้กล่าวไว้ก่อนหน้านี้คุณสามารถระบุว่าตัวแปรหรือเมธอดนั้นเป็นส่วนตัวโดยนำหน้าด้วยเครื่องหมายขีดล่าง หากคุณรู้สึกว่าไม่เพียงพอคุณสามารถใช้propertyมัณฑนากรได้ตลอดเวลา นี่คือตัวอย่าง:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

วิธีนี้บางคนหรือบางสิ่งที่อ้างอิงbarเป็นการอ้างอิงค่าส่งคืนของbarฟังก์ชันแทนที่จะเป็นตัวแปรเองดังนั้นจึงสามารถเข้าถึงได้ แต่ไม่สามารถเปลี่ยนแปลงได้ อย่างไรก็ตามถ้ามีคนต้องการจริงๆพวกเขาสามารถใช้_barและกำหนดค่าใหม่ให้กับมัน ไม่มีวิธีที่แน่นอนในการป้องกันบุคคลจากการเข้าถึงตัวแปรและวิธีการที่คุณต้องการซ่อนตามที่ได้รับการพูดซ้ำ ๆ อย่างไรก็ตามการใช้propertyเป็นข้อความที่ชัดเจนที่สุดที่คุณสามารถส่งได้ว่าไม่ควรแก้ไขตัวแปร propertyนอกจากนี้ยังสามารถใช้สำหรับเส้นทางเข้าถึง getter / setter / deleter ที่ซับซ้อนมากขึ้นดังที่อธิบายไว้ที่นี่: https://docs.python.org/3/library/functions.html#property


Django ยังชื่นชมในสิ่งนี้
babygame0ver

10

Python มีการสนับสนุนที่ จำกัด สำหรับตัวระบุส่วนบุคคลผ่านคุณสมบัติที่จะเพิ่มชื่อคลาสให้กับตัวระบุใด ๆ ที่เริ่มต้นด้วยขีดล่างสองอันโดยอัตโนมัติ นี่เป็นความโปร่งใสสำหรับโปรแกรมเมอร์ส่วนใหญ่ แต่ผลกระทบสุทธิคือตัวแปรใด ๆ ที่ชื่อวิธีนี้สามารถใช้เป็นตัวแปรส่วนตัวได้

ดูที่นี่สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนั้น

โดยทั่วไปการใช้การวางแนวของ Python เป็นวัตถุดั้งเดิมเมื่อเทียบกับภาษาอื่น แต่ฉันสนุกกับมันจริง มันเป็นการนำแนวคิดที่เรียบง่ายมาใช้และสอดคล้องกับสไตล์ของภาษา


อ๋อ ความงามคือความสามารถในการ metaprogramming ของ python หมายความว่าคุณสามารถใช้สิ่งที่แปลกใหม่ได้หากคุณต้องการ (และมีห้องสมุดที่ใช้เครื่องมือตกแต่ง @ private / @ protected / etc และอื่น ๆ นรกฉันเห็นห้องสมุดที่เลียนแบบคลาส JS ต้นแบบ สำหรับเหตุผลที่ไม่มีเหตุผล goddamn) แต่ในทางปฏิบัติมันก็ไม่จำเป็น .. ฉันเกลียด "python / js / อะไรก็ตามที่เป็นเสียงกระเพื่อม" meme เพราะมันแทบจะไม่เป็นความจริง แต่หลามไม่แบ่งปัน metaprogramming สับร่วมกับไวยากรณ์ง่ายๆ 'กับภาษานั้น
Shayne

8

เวลาเดียวที่ฉันเคยใช้ตัวแปรส่วนตัวคือเมื่อฉันต้องทำสิ่งอื่นเมื่อเขียนหรืออ่านจากตัวแปรและดังนั้นฉันจึงจำเป็นต้องบังคับให้ใช้ setter และ / หรือทะเยอทะยาน

อีกครั้งนี้ไปสู่วัฒนธรรมตามที่ระบุไว้แล้ว ฉันทำงานเกี่ยวกับโปรเจ็กต์ที่การอ่านและการเขียนตัวแปรคลาสอื่น ๆ นั้นฟรีสำหรับทุกคน เมื่อการติดตั้งครั้งเดียวเลิกใช้งานมันใช้เวลานานกว่านั้นในการระบุพา ธ โค้ดทั้งหมดที่ใช้ฟังก์ชันนั้น เมื่อมีการบังคับใช้ setters และ getters สามารถแก้ไขคำสั่ง debug ได้อย่างง่ายดายเพื่อระบุว่ามีการเรียกใช้เมธอดที่เลิกใช้แล้วและโค้ดพา ธ ที่เรียกใช้

เมื่อคุณอยู่ในโครงการที่ทุกคนสามารถเขียนส่วนขยายได้การแจ้งผู้ใช้เกี่ยวกับวิธีการที่เลิกใช้แล้วซึ่งจะหายไปในการเผยแพร่ไม่กี่ครั้งดังนั้นจึงเป็นสิ่งสำคัญที่จะทำให้โมดูลแตกอย่างน้อยที่สุดเมื่ออัพเกรด

ดังนั้นคำตอบของฉันคือ หากคุณและเพื่อนร่วมงานของคุณบำรุงรักษาชุดรหัสอย่างง่ายการปกป้องตัวแปรคลาสไม่จำเป็นเสมอไป หากคุณกำลังเขียนระบบที่ขยายได้มันจะกลายเป็นสิ่งจำเป็นเมื่อมีการเปลี่ยนแปลงในส่วนหลักที่จำเป็นต้องมีการจับโดยส่วนขยายทั้งหมดโดยใช้รหัส


8

ขออภัยพวกที่ "คืนชีพ" เธรด แต่ฉันหวังว่าสิ่งนี้จะช่วยให้ใครบางคน:

ใน Python3 หากคุณเพียงแค่ต้องการ "ห่อหุ้ม" คุณสมบัติคลาสเช่นใน Java คุณสามารถทำสิ่งเดียวกันนี้:

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

ในการสร้างอินสแตนซ์ให้ทำ:

ss = Simple("lol")
ss.show()

โปรดทราบว่า: print(ss.__s)จะโยนข้อผิดพลาด

ในทางปฏิบัติ Python3 จะทำให้งงงวยชื่อแอตทริบิวต์ทั่วโลก การเปลี่ยนให้เป็นแบบ "ส่วนตัว" เช่นใน Java ชื่อของแอ็ตทริบิวต์ยังคงเป็นแบบโกลบอล แต่ไม่สามารถเข้าถึงได้เช่นแอททริบิวต์ส่วนตัวในภาษาอื่น

แต่อย่ากลัวเลย มันไม่สำคัญ มันทำงานได้ดีเช่นกัน ;)


2
สิ่งนี้มีอยู่ตั้งแต่ Python 1.5.2 IIRC และยังไม่ป้องกันการเข้าถึงแอททริบิวต์ด้วยชื่อที่ถูกตัดคำ
bruno desthuilliers

7

แนวคิดส่วนตัวและการป้องกันมีความสำคัญมาก แต่ไพ ธ อน - เป็นเพียงเครื่องมือสำหรับการสร้างต้นแบบและการพัฒนาอย่างรวดเร็วพร้อมทรัพยากรที่ จำกัด สำหรับการพัฒนานั่นคือสาเหตุที่ระดับการป้องกันบางระดับไม่ได้เข้มงวดตามมาในไพ ธ อน คุณสามารถใช้ "__" ในสมาชิกของคลาสมันทำงานได้อย่างถูกต้อง แต่ดูไม่ดีพอ - การเข้าถึงแต่ละฟิลด์ดังกล่าวมีอักขระเหล่านี้

นอกจากนี้คุณสามารถสังเกตเห็นว่าแนวคิดของงูหลาม OOP นั้นไม่สมบูรณ์แบบไม่ว่าจะเป็น smolalk หรือ ruby ​​ที่ใกล้เคียงกับแนวคิด OOP บริสุทธิ์มาก แม้แต่ C # หรือ Java ก็ยังเข้าใกล้

Python เป็นเครื่องมือที่ดีมาก แต่มันเป็นภาษา OOP แบบง่าย ๆ ลดความซับซ้อนของ Syntactically และ conceptually เป้าหมายหลักของการมีอยู่ของไพ ธ อนคือการนำความเป็นไปได้ของนักพัฒนาในการเขียนโค้ดที่อ่านง่ายและมีระดับนามธรรมสูงอย่างรวดเร็ว


rearson Private and Protected มีความสำคัญคือในภาษาที่คอมไพล์แบบสแตติกคอมไพเลอร์สามารถสร้างการโทรแบบ diirect ไปยังเมธอดไพรเวต แต่ต้องพึ่งพาตารางการค้นหาสำหรับเมธอดสาธารณะ Thiis ไม่ได้มีปัญหากับภาษาแบบไดนามิก ในที่สุดภาษาเช่น C ++ มีความหมายสำหรับมรดกและวิธีการแก้ไข Python และ Ruby มีการนำไปใช้ที่คล้ายกันมากของ OO ดังนั้นการเปรียบเทียบจึงไม่มีความหมาย Smalltalk จริง ๆ แล้วไม่มีความเห็นของข้อความสาธารณะ / ส่วนตัว คุณสามารถเพิ่มความเป็นส่วนตัวในหมวดหมู่ของคุณได้ฟรี แต่เป็นคำแนะนำอย่างแท้จริง
เชน

เพื่อยืนยันของฉันต่อไป จากมุมมองด้านสุขลักษณะของการเขียนรหัสใช่ว่ามันมีความสำคัญต่อการห่อหุ้ม แต่ไม่จำเป็นสำหรับมันและดังนั้นผู้ตกแต่ง @private (ฯลฯ ) จึงเป็นที่ปรึกษามากกว่าสิ่งใด ๆ แต่ในฐานะส่วนตัว / สาธารณะ ภาษาที่ไม่คงที่มันไม่ได้ถูกนำมาใช้ในระดับลึกเช่นเดียวกับในภาษาที่คอมไพล์เช่น java หรือ c
Shayne

4

Python ไม่มีตัวแปรส่วนตัวเช่น C ++ หรือ Java คุณสามารถเข้าถึงตัวแปรสมาชิกได้ตลอดเวลาหากต้องการเช่นกัน อย่างไรก็ตามคุณไม่จำเป็นต้องใช้ตัวแปรส่วนตัวใน Python เพราะใน Python มันไม่ได้เลวร้ายที่จะเปิดเผยตัวแปรสมาชิกคลาสของคุณ หากคุณมีความต้องการที่จะแค็ปซูลตัวแปรสมาชิกคุณสามารถทำได้โดยใช้ "@property" ในภายหลังโดยไม่ทำลายรหัสลูกค้าที่มีอยู่

ในไพ ธ อนนั้นใช้เครื่องหมายขีดล่าง "_" เพื่อระบุว่าวิธีการหรือตัวแปรนั้นไม่ถือเป็นส่วนหนึ่งของ api สาธารณะของคลาสและส่วนนี้ของ api สามารถเปลี่ยนแปลงได้ระหว่างเวอร์ชันต่าง ๆ คุณสามารถใช้วิธีการ / ตัวแปรเหล่านี้ แต่รหัสของคุณอาจแตกถ้าคุณใช้รุ่นที่ใหม่กว่าของชั้นนี้

เครื่องหมายขีดล่างคู่ "__" ไม่ได้หมายความว่า "ตัวแปรส่วนตัว" คุณใช้มันเพื่อกำหนดตัวแปรที่เป็น "class local" และไม่สามารถถูกแทนที่ได้อย่างง่ายดายโดยคลาสย่อย มัน mangles ชื่อตัวแปร

ตัวอย่างเช่น:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

ชื่อตัวเองของ. foobar จะถูกทำให้เป็นตัวเองโดยอัตโนมัติ _A__foobar ในคลาส A ในคลาส B นั้นจะมีการจัดการกับตัวเอง _B__foobar ดังนั้นทุกคลาสย่อยสามารถกำหนดตัวแปร __foobar ของตัวเองโดยไม่ต้องแทนที่ตัวแปรพาเรนต์ แต่ไม่มีอะไรป้องกันคุณจากการเข้าถึงตัวแปรที่ขึ้นต้นด้วยเครื่องหมายขีดล่างคู่ อย่างไรก็ตามชื่อ -mangling ป้องกันคุณจากการเรียกตัวแปร / วิธีนี้โดยบังเอิญ

ฉันขอแนะนำอย่างยิ่งให้ดู Raymond Hettingers พูดคุย "Pythons class development tool" จาก Pycon 2013 (ควรมีใน Youtube) ซึ่งเป็นตัวอย่างที่ดีว่าทำไมและวิธีที่คุณควรใช้ @property และ "__" - ตัวแปรอินสแตนซ์


ฉันจะไปดูคำพูดนั้น เป็น@propertyส่วนหนึ่งของ Python มาตรฐานหรือเฉพาะกับ IDE หรือไม่
bballdave025

เป็นส่วนหนึ่งของมาตรฐานตั้งแต่ python 2.6 หากคุณควรใช้เวอร์ชั่นที่เก่ากว่าก็ยังมีความเป็นไปได้ที่จะใช้propertyฟังก์ชัน builtin ซึ่งมีให้ตั้งแต่ python 2.2
Hatatister

0

จริงๆแล้วคุณสามารถจำลองผู้C#ทะเยอทะยานและผู้ตั้งค่าโดยใช้เคล็ดลับง่ายๆนี้

class Screen(object):

    def getter_setter_y(self, y, get=True):
        if get is True:
            Screen.getter_setter_y.value = y
        else:
            return Screen.getter_setter_y.value

     def getter_setter_x(self, x, get=True):
         if get is True:
             Screen.getter_setter_x.value = x
         else:
             return Screen.getter_setter_x.value

จากนั้นใช้เหมือนในC#:

scr = Screen()
scr.getter_setter_x(100)
value =  scr.getter_setter_x(0, get=False)
print (value)

มันเป็นเพียงการประกาศตัวแปรโลคัลสแตติกในฟังก์ชันที่จะมีบทบาทรับ / ตั้งค่าเนื่องจากเป็นวิธีเดียวที่จะแบ่งปันตัวแปรผ่านวิธีรับและตั้งค่าโดยไม่ทำให้มันเป็นโลกสำหรับคลาสหรือไฟล์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.