หากมีข้อสงสัยให้ปล่อยไว้ "สาธารณะ" - ฉันหมายถึงอย่าเพิ่มสิ่งใด ๆ เพื่อปิดบังชื่อแอตทริบิวต์ของคุณ หากคุณมีคลาสที่มีค่าภายในไม่ต้องกังวลกับมัน แทนที่จะเขียน:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
เขียนสิ่งนี้โดยค่าเริ่มต้น:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
แน่นอนว่านี่เป็นวิธีที่ขัดแย้งกันในการทำสิ่งต่างๆ มือใหม่ Python แค่เกลียดมันและแม้แต่ Python เก่า ๆ บางคนก็ดูถูกค่าเริ่มต้นนี้ - แต่มันก็เป็นค่าเริ่มต้นอยู่ดีดังนั้นฉันขอแนะนำให้คุณทำตามแม้ว่าคุณจะรู้สึกไม่สบายใจก็ตาม
หากคุณจริงๆต้องการส่งข้อความ "ไม่สามารถสัมผัสนี้!" ให้กับผู้ใช้ของคุณทางปกติคือการนำหน้าตัวแปรที่มีหนึ่งขีด นี่เป็นเพียงอนุสัญญา แต่ผู้คนเข้าใจและดูแลเป็นสองเท่าเมื่อจัดการกับสิ่งเหล่านี้:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
สิ่งนี้มีประโยชน์เช่นกันสำหรับการหลีกเลี่ยงความขัดแย้งระหว่างชื่อคุณสมบัติและชื่อแอตทริบิวต์:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
แล้วขีดล่างคู่ล่ะ? ดีขีดมายากลคู่ส่วนใหญ่จะใช้เพื่อหลีกเลี่ยงการบรรทุกเกินพิกัดอุบัติเหตุของวิธีการและความขัดแย้งที่มีคุณลักษณะที่ชื่อ superclasses' จะมีประโยชน์มากหากคุณเขียนคลาสที่คาดว่าจะขยายออกไปหลาย ๆ ครั้ง
หากคุณต้องการใช้เพื่อวัตถุประสงค์อื่นคุณสามารถทำได้ แต่ไม่เป็นปกติหรือไม่แนะนำ
แก้ไข : ทำไมถึงเป็นเช่นนั้น? สไตล์ Python ตามปกติไม่ได้เน้นการทำให้สิ่งต่างๆเป็นส่วนตัวในทางตรงกันข้าม! มีสาเหตุหลายประการ - ส่วนใหญ่ขัดแย้งกัน ... ให้เราดูบางส่วน
Python มีคุณสมบัติ
ภาษา OO ส่วนใหญ่ในปัจจุบันใช้แนวทางตรงกันข้าม: สิ่งที่ไม่ควรใช้ไม่ควรมองเห็นได้ดังนั้นแอตทริบิวต์ควรเป็นแบบส่วนตัว ในทางทฤษฎีแล้วสิ่งนี้จะทำให้เกิดการจัดการเรียนรู้ร่วมกันได้น้อยกว่าเนื่องจากไม่มีใครเปลี่ยนค่าภายในวัตถุโดยประมาท
อย่างไรก็ตามมันไม่ง่ายอย่างนั้น ตัวอย่างเช่นคลาส Java มีแอตทริบิวต์จำนวนมากและ getters ซึ่งได้รับค่าและตัวตั้งค่าที่เพิ่งกำหนดค่า คุณต้องบอกเราว่าโค้ดเจ็ดบรรทัดเพื่อประกาศแอตทริบิวต์เดียวซึ่งโปรแกรมเมอร์ Python จะบอกว่าซับซ้อนโดยไม่จำเป็น นอกจากนี้ในทางปฏิบัติคุณเพียงแค่เขียนโค้ดจำนวนมากนี้เพื่อรับฟิลด์สาธารณะหนึ่งฟิลด์เนื่องจากคุณสามารถเปลี่ยนค่าได้โดยใช้ getters และ setters
เหตุใดจึงต้องปฏิบัติตามนโยบายส่วนตัวโดยปริยายนี้ เพียงทำให้แอตทริบิวต์ของคุณเป็นแบบสาธารณะตามค่าเริ่มต้น แน่นอนว่านี่เป็นปัญหาใน Java เพราะถ้าคุณตัดสินใจที่จะเพิ่มการตรวจสอบความถูกต้องให้กับแอตทริบิวต์ของคุณคุณจะต้องเปลี่ยนทั้งหมด
person.age = age;
ในรหัสของคุณเพื่อให้เราพูดว่า
person.setAge(age);
setAge()
ความเป็น:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
ดังนั้นใน Java (และภาษาอื่น ๆ ) ค่าเริ่มต้นคือการใช้ getters และ setters ต่อไปเพราะอาจเป็นเรื่องน่ารำคาญในการเขียน แต่อาจทำให้คุณเสียเวลาได้มากหากคุณพบว่าตัวเองอยู่ในสถานการณ์ที่ฉันได้อธิบายไว้
อย่างไรก็ตามคุณไม่จำเป็นต้องทำใน Python เนื่องจาก Python มีคุณสมบัติ หากคุณมีคลาสนี้:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
จากนั้นคุณจึงตัดสินใจที่จะตรวจสอบอายุคุณไม่จำเป็นต้องเปลี่ยนperson.age = age
ส่วนของรหัสของคุณ เพียงแค่เพิ่มคุณสมบัติ (ตามที่แสดงด้านล่าง)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
ถ้าคุณทำได้และยังใช้ได้อยู่ person.age = age
ทำไมคุณถึงเพิ่มฟิลด์ส่วนตัวและ getters และ setters?
(โปรดดูที่Python ไม่ใช่ Javaและบทความนี้เกี่ยวกับอันตรายของการใช้ getters และ setters )
ทุกอย่างสามารถมองเห็นได้ - และการพยายามซ่อนก็ทำให้งานของคุณซับซ้อนขึ้น
แม้ในภาษาที่มีคุณลักษณะส่วนตัวคุณสามารถเข้าถึงได้ผ่านห้องสมุดการไตร่ตรอง / วิปัสสนาบางประเภท และผู้คนก็ทำกันมากตามกรอบและเพื่อแก้ปัญหาความจำเป็นเร่งด่วน ปัญหาคือห้องสมุดวิปัสสนาเป็นเพียงวิธีที่ยากในการทำสิ่งที่คุณสามารถทำได้กับคุณลักษณะสาธารณะ
เนื่องจาก Python เป็นภาษาที่มีไดนามิกมากจึงเป็นเพียงการต่อต้านการเพิ่มภาระนี้ให้กับชั้นเรียนของคุณ
ปัญหาคือไม่สามารถมองเห็นได้ - จำเป็นต้องดู
สำหรับ Pythonista การห่อหุ้มไม่ใช่ความสามารถในการมองเห็นภายในของคลาส แต่เป็นไปได้ที่จะหลีกเลี่ยงการมองไปที่มัน สิ่งที่ฉันหมายถึงคือการห่อหุ้มเป็นคุณสมบัติของส่วนประกอบที่ช่วยให้สามารถใช้งานได้โดยที่ผู้ใช้ไม่ต้องกังวลเกี่ยวกับรายละเอียดภายใน หากคุณสามารถใช้คอมโพเนนต์ได้โดยไม่ต้องกังวลเกี่ยวกับการนำไปใช้งานแสดงว่ามันถูกห่อหุ้ม (ตามความเห็นของโปรแกรมเมอร์ Python)
ตอนนี้ถ้าคุณเขียนชั้นเรียนด้วยวิธีดังกล่าวคุณสามารถใช้งานได้โดยไม่ต้องคิดถึงรายละเอียดการใช้งานก็ไม่มีปัญหาหากคุณต้องการดูภายในชั้นเรียนด้วยเหตุผลบางประการ ประเด็นคือ API ของคุณควรจะดีและส่วนที่เหลือคือรายละเอียด
กุยโดกล่าวเช่นนั้น
อย่างนี้ไม่ได้เป็นความขัดแย้ง: เขากล่าวว่าเป็นเช่นนั้นจริง (มองหา "ชุดกิโมโนแบบเปิด")
นี่คือวัฒนธรรม
ใช่มีเหตุผลบางประการ แต่ไม่มีเหตุผลสำคัญ ส่วนใหญ่เป็นลักษณะทางวัฒนธรรมของการเขียนโปรแกรมใน Python ตรงไปตรงมาอาจเป็นวิธีอื่นเช่นกัน - แต่ก็ไม่ใช่ นอกจากนี้คุณสามารถถามวิธีอื่น ๆ ได้ง่ายๆเช่นทำไมบางภาษาจึงใช้แอตทริบิวต์ส่วนตัวเป็นค่าเริ่มต้น ด้วยเหตุผลหลักเดียวกันกับการฝึกฝน Python: เนื่องจากเป็นวัฒนธรรมของภาษาเหล่านี้และแต่ละตัวเลือกมีข้อดีและข้อเสีย
เนื่องจากมีวัฒนธรรมนี้อยู่แล้วจึงขอแนะนำให้ปฏิบัติตาม มิฉะนั้นคุณจะรำคาญโดยโปรแกรมเมอร์ Python ที่บอกให้คุณลบออก__
จากโค้ดของคุณเมื่อคุณถามคำถามใน Stack Overflow :)