ความคิดที่แย่คือการใช้ไฟล์ Python เป็นไฟล์กำหนดค่า


72

ฉันใช้ไฟล์JSONเพื่อกำหนดค่าแอปพลิเคชันของฉันเสมอ ฉันเริ่มใช้พวกเขาตั้งแต่ตอนที่ฉันเขียนโค้ด Java จำนวนมากและตอนนี้ฉันทำงานเป็นหลักเกี่ยวกับการพัฒนา Python ด้านเซิร์ฟเวอร์และวิทยาศาสตร์ข้อมูลและฉันไม่แน่ใจว่าJSONเป็นวิธีที่เหมาะสมที่จะไปอีกต่อไป

ฉันเห็น Celery ใช้ไฟล์ Python ที่แท้จริงเพื่อกำหนดค่า ตอนแรกฉันสงสัยเกี่ยวกับมัน แต่แนวคิดของการใช้โครงสร้างข้อมูล Python ง่าย ๆ สำหรับการกำหนดค่าเริ่มที่จะเพิ่มขึ้น ข้อดีบางประการ:

  • โครงสร้างข้อมูลจะเหมือนกับที่ฉันเขียนตามปกติดังนั้นฉันไม่จำเป็นต้องเปลี่ยนกรอบความคิด
  • IDE ของฉัน (PyCharm) เข้าใจการเชื่อมต่อระหว่างการกำหนดค่าและรหัส Ctrl+ Bทำให้สามารถข้ามไปมาระหว่างการกำหนดค่าและรหัสได้อย่างง่ายดาย
  • ฉันไม่ต้องการที่จะทำงานกับที่ไม่จำเป็น IMO เข้มงวดJSON ฉันกำลังดูคุณสองคำพูดไม่มีเครื่องหมายจุลภาคต่อท้ายและไม่มีความคิดเห็น
  • ฉันสามารถเขียนการกำหนดค่าการทดสอบในแอปพลิเคชันที่ฉันกำลังทำงานอยู่จากนั้นจึงย้ายพวกเขาไปยังไฟล์กำหนดค่าโดยไม่ต้องทำการแปลงใด ๆ และการแยกวิเคราะห์ JSON
  • เป็นไปได้ที่จะทำสคริปต์ง่าย ๆ ในไฟล์กำหนดค่าถ้าจำเป็นจริงๆ (แม้ว่าสิ่งนี้ควรมี จำกัด มาก)

ดังนั้นคำถามของฉันคือถ้าฉันสลับฉันจะยิงตัวเองในเท้าได้อย่างไร

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

(ฉันเคยพิจารณาYAMLแต่มีบางอย่างเกี่ยวกับมันทำให้ฉันรำคาญดังนั้นสำหรับตอนนี้มันอยู่นอกโต๊ะอเมริกัน)


39
ไม่ชำนาญไม่ใช่ปัญหาของคุณ เป็นอันตราย
Blrfl

9
คุณหมายถึงอะไรโดย"ปิดตารางอเมริกัน" ?
ปีเตอร์มอร์เทนเซ่น

24
"ตอนนี้มันอยู่นอกโต๊ะอเมริกันแล้ว" === "ตอนนี้เป็นไปตามที่ชาวอเมริกันพูดออกไปจากโต๊ะ"
บิชอป

7
หากคุณไม่ชอบ JSON คุณควรลอง yaml ฉันชอบมันมากสำหรับการกำหนดค่า โดยเฉพาะอย่างยิ่งเมื่อสตริงที่เกี่ยวข้องมีขนาดใหญ่ YAML สามารถอ่านได้มากขึ้นแล้ว JSON
คริสเตียนซาวเออร์

5
@ บิชอป "ออกจากตาราง" ในสหราชอาณาจักรอังกฤษหมายถึงไม่ได้พิจารณาอีกต่อไปจากการเคลื่อนไหวของรัฐสภาถูกวางบนโต๊ะกลางสภาเพื่อการอ้างอิงเมื่อมีการหารือดังนั้นจึง 'บัญชีสำหรับการสนทนา' (บันทึกรัฐสภา 1799 - books.google.co.th/… ), AFAIK ความหมายของสหรัฐเหมือนกัน แต่ฉันไม่รู้ว่าคุณมีโต๊ะในรัฐสภาของคุณหรือไม่
Pete Kirkham

คำตอบ:


92

การใช้ภาษาสคริปต์ในสถานที่ของไฟล์ config ดูดีได้อย่างรวดเร็วก่อน: คุณมีอำนาจเต็มของภาษาที่มีอยู่และสามารถเพียงeval()หรือimportมัน ในทางปฏิบัติมี gotchas ไม่กี่:

  • มันเป็นภาษาการเขียนโปรแกรมซึ่งจำเป็นต้องเรียนรู้ ในการแก้ไขการกำหนดค่าคุณจำเป็นต้องรู้ภาษานี้อย่างเพียงพอ โดยทั่วไปไฟล์การกำหนดค่าจะมีรูปแบบที่ง่ายกว่าและยากที่จะผิดพลาด

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

  • มันเป็นภาษาการเขียนโปรแกรมซึ่งทำให้ยากที่จะรักษาแยกที่ชัดเจนระหว่างการกำหนดค่าและโปรแกรมจริง บางครั้งคุณต้องการความสามารถในการขยายตัวแบบนี้ แต่ ณ จุดนั้นคุณอาจมองหาระบบปลั๊กอินที่แท้จริง

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

ดังนั้นการใช้สคริปต์สำหรับการกำหนดค่าอาจเป็นไปได้ว่าผู้ชมเครื่องมือของคุณคือผู้พัฒนาเช่น Sphinx config หรือ setup.py ในโครงการ Python โปรแกรมอื่นที่มีการกำหนดค่าที่สามารถเรียกใช้งานได้คือเชลล์เช่น Bash และโปรแกรมแก้ไขเช่น Vim

การใช้ภาษาการเขียนโปรแกรมสำหรับการกำหนดค่าเป็นสิ่งจำเป็นหากการกำหนดค่าประกอบด้วยส่วนที่มีเงื่อนไขมากมายหรือหากมีการเรียกกลับ / ปลั๊กอิน การใช้สคริปต์โดยตรงแทนที่จะเป็น eval () - เนื่องจากมีฟิลด์การตั้งค่าบางอย่างที่สามารถ debuggable ได้มากกว่า (ลองนึกถึงร่องรอยสแต็กและหมายเลขบรรทัด!)

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

ในกรณีส่วนใหญ่ไฟล์ INI, ไฟล์คุณสมบัติ Java หรือเอกสาร YAML เหมาะสำหรับการกำหนดค่ามากขึ้น สำหรับโมเดลข้อมูลที่ซับซ้อน XML อาจใช้งานได้เช่นกัน ดังที่คุณได้บันทึกไว้ JSON มีบางแง่มุมที่ทำให้ไม่เหมาะสมกับไฟล์การกำหนดค่าที่มนุษย์สามารถแก้ไขได้แม้ว่าจะเป็นรูปแบบการแลกเปลี่ยนข้อมูลที่ดี


25
มีสองรูปแบบไฟล์การกำหนดค่าซึ่งเป็น "บังเอิญทัวริงสมบูรณ์" sendmail.cfมีชื่อเสียงมากที่สุด นั่นอาจเป็นการบ่งชี้ว่าการใช้ภาษาสคริปต์จริงอาจมีประโยชน์เนื่องจากภาษานั้นถูกออกแบบมาให้ใช้ในทัวริงจริง อย่างไรก็ตามทัวริง - ความสมบูรณ์และ "Tetris - ครบถ้วน" เป็นสองสิ่งที่แตกต่างกันและในขณะที่sendmail.cfสามารถคำนวณฟังก์ชั่นโดยพลการมันไม่สามารถส่ง/etc/passwdผ่านเน็ตหรือฟอร์แมตฮาร์ดดิสก์ของคุณซึ่ง Python หรือ Perl จะสามารถ
Jörg W Mittag

3
@ JörgWMittagตูรินความสมบูรณ์ไม่ได้หมายความว่าจะสามารถส่งสิ่งต่าง ๆ ผ่านเครือข่ายหรือเข้าถึงฮาร์ดดิสก์ นั่นคือความสมบูรณ์ของตูรินนั้นเกี่ยวกับการประมวลผลที่ไม่เกี่ยวกับ I / O ตัวอย่างเช่น CSS ถือว่า Turin เสร็จสมบูรณ์ แต่จะไม่ยุ่งกับที่เก็บข้อมูลถาวรของคุณ คุณได้กล่าวไว้ที่อื่นว่า "ไอดริสเป็นภาษาที่ใช้งานได้จริงทั้งหมดดังนั้นจึงเป็นคำจำกัดความที่ไม่ใช่ทัวริงสมบูรณ์" ซึ่งไม่ได้ติดตามและเห็นได้ชัดว่ามันคือตูรินที่สมบูรณ์ ฉันเชื่อว่าการใช้ Testris-complete หมายความว่าภาษาตูรินนั้นสมบูรณ์ แต่ไม่สามารถทำ I / O ได้อย่างสมบูรณ์ ... ดูเหมือนว่าไม่ใช่สิ่งที่คุณหมายถึง
ธีระโรจน์

6
@Theraot: "ยอดรวม" หมายความว่าจะส่งคืนเสมอ เครื่องทัวริงสามารถทำการวนลูปไม่สิ้นสุดนั่นคือมันมีความสามารถที่จะไม่ส่งคืน ดังนั้นไอดริสไม่สามารถทำทุกอย่างที่ทัวริงทำซึ่งหมายความว่ามันไม่สมบูรณ์แบบ นี่เป็นความจริงสำหรับทุกภาษาที่พิมพ์อย่างพึ่งพา จุดสำคัญของภาษาที่พิมพ์ขึ้นอยู่กับว่าคุณสามารถตัดสินใจคุณสมบัติโดยพลการเกี่ยวกับโปรแกรมในขณะที่ภาษาทัวริงที่สมบูรณ์คุณไม่สามารถตัดสินใจคุณสมบัติที่ไม่สำคัญเช่น "โปรแกรมนี้หยุดทำงานได้หรือไม่" ภาษาทั้งหมดเป็นคำจำกัดความที่ไม่ได้ทำให้ทัวริงสมบูรณ์เพราะทัวริงมีบางส่วน
Jörg W Mittag

10
คำนิยามของ "ทัวริงสมบูรณ์" คือ "สามารถใช้เครื่องทัวริง" คำจำกัดความของ "Tetris-complete" คือ "สามารถใช้ Tetris" ได้ ประเด็นทั้งหมดของคำนิยามนี้คือความสมบูรณ์แบบของทัวริงนั้นไม่น่าสนใจมากนักในโลกแห่งความเป็นจริง มีภาษาที่มีประโยชน์มากมายที่ไม่สมบูรณ์ทัวริงเช่น HTML, SQL (ก่อนปี 1999), DSL ต่าง ๆ , ฯลฯ OTOH, ทัวริงสมบูรณ์ครบถ้วนเท่านั้นที่แสดงว่าคุณสามารถคำนวณฟังก์ชันมากกว่าตัวเลขธรรมชาติได้ การพิมพ์ไปที่หน้าจอการเข้าถึงเครือข่ายการโต้ตอบกับผู้ใช้ระบบปฏิบัติการสิ่งแวดล้อมซึ่งล้วนเป็นสิ่งสำคัญ
Jörg W Mittag

4
เหตุผลที่เอ็ดวินเบรดี้ใช้ตัวอย่างนี้เป็นเพราะหลายคนคิดว่าภาษาที่ไม่สมบูรณ์ไม่สามารถใช้สำหรับการเขียนโปรแกรมวัตถุประสงค์ทั่วไปได้ ฉันเองก็เคยคิดเช่นกันว่าหลังจากนั้นโปรแกรมที่น่าสนใจมากมายก็คือลูปที่ไม่มีที่สิ้นสุดซึ่งเราไม่ต้องการหยุดเช่นเซิร์ฟเวอร์ระบบปฏิบัติการลูปเหตุการณ์ใน GUI ลูปเกม โปรแกรมจำนวนมากประมวลผลข้อมูลที่ไม่มีที่สิ้นสุดเช่นสตรีมเหตุการณ์ ฉันเคยคิดว่าคุณไม่สามารถเขียนมันเป็นภาษาทั้งหมด แต่ฉันได้เรียนรู้ว่าคุณสามารถทำได้ดังนั้นฉันจึงคิดว่ามันเป็นความคิดที่ดีที่จะมีคำศัพท์สำหรับความสามารถนั้น
Jörg W Mittag

50

+1 เพื่อทุกอย่างในคำตอบของอมร ฉันต้องการเพิ่มสิ่งนี้:

คุณจะเสียใจที่ใช้รหัส Python เป็นภาษาการกำหนดค่าของคุณในครั้งแรกที่คุณต้องการนำเข้าการกำหนดค่าเดียวกันจากภายในรหัสที่เขียนในภาษาอื่น ตัวอย่างเช่นหากรหัสที่เป็นส่วนหนึ่งของโครงการของคุณและเขียนใน C ++ หรือ Ruby หรืออย่างอื่นที่จำเป็นต้องดึงในการกำหนดค่าคุณจะต้องเชื่อมโยงใน Python interpreter เป็นไลบรารีหรือแยกวิเคราะห์การกำหนดค่าในกระบวนการร่วมหลาม ซึ่งอึดอัดยากหรือค่าใช้จ่ายสูง

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

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

แก้ไขสำหรับบันทึก: หลายคนแสดงความคิดเห็นต่อคำตอบนี้เกี่ยวกับความเป็นไปได้หรือไม่น่าเป็นไปได้ว่าโครงการจะถูกเขียนใหม่อย่างสมบูรณ์ในภาษาอื่น มันยุติธรรมที่จะกล่าวว่าการเขียนซ้ำที่เข้ากันได้แบบย้อนหลังอาจจะไม่ค่อยเห็น สิ่งที่ฉันคิดอยู่ในใจคือบิตและชิ้นส่วนของโครงการเดียวกัน (และจำเป็นต้องเข้าถึงการกำหนดค่าเดียวกัน) ที่เขียนในภาษาต่างๆ ตัวอย่างเช่นการให้บริการสแต็กใน C ++ สำหรับความเร็วการล้างค่าฐานข้อมูลชุดใน Python เชลล์สคริปต์บางตัวเป็นกาว ดังนั้นใช้ความคิดสำหรับกรณีนั้นด้วย :)


1
@ เสาขอโทษ แต่ฉันไม่ทำตาม ชื่อของไฟล์ (หรือไม่ว่าจะลงท้ายด้วย. py) จะไม่อยู่ที่นี่หรือตรงนั้น ประเด็นที่ฉันพยายามทำคือถ้ามันเขียนด้วย Python คุณต้องใช้ Python interpreter เพื่ออ่านมัน
Celada

12
@Mast ฉันคิดว่าคุณกำลังแยกวิเคราะห์ผิด จุดที่ฉันได้จากคำตอบนี้ (ทั้งต้นฉบับและแก้ไข) คือตัวเลือกในการเขียนไฟล์การกำหนดค่าในภาษาการเขียนโปรแกรมคือมันทำให้การเขียนโค้ดในภาษาอื่นยากขึ้น เช่นคุณตัดสินใจย้ายแอพของคุณไปที่ Anrdoid / iPhone และจะใช้ภาษาอื่น คุณต้อง (a) พึ่งพาล่าม Python ในแอพโทรศัพท์มือถือ (ไม่เหมาะ), (b) เขียนการกำหนดค่าใหม่ในรูปแบบที่ไม่ขึ้นกับภาษาและเขียนรหัส Python ที่ใช้มันหรือ (c) บำรุงรักษา สองรูปแบบการกำหนดค่าก้าวไปข้างหน้า
Jon Bentley

4
@JonBentley ฉันคิดว่าความกังวลนั้นจะเกี่ยวข้องถ้ามีแผนการที่จะทำโครงการหลายภาษา ฉันไม่ได้รับความประทับใจนั้นจาก OP นอกจากนี้การใช้ไฟล์ข้อความสำหรับการกำหนดค่ายังคงต้องใช้รหัสเพิ่มเติม (ทุกภาษา) สำหรับการวิเคราะห์ / การแปลงค่าจริง ในทางเทคนิคหากพวกเขา จำกัด ด้าน Python key=valueสำหรับการกำหนดค่าฉันไม่เห็นว่าทำไมโปรแกรม Java / C ++ ไม่สามารถอ่านไฟล์ Python เป็นไฟล์ข้อความธรรมดาและแยกมันได้ถ้าพวกเขาต้องการย้ายไปยังสิ่งอื่นใน อนาคต. ฉันไม่เห็นความต้องการผู้แปล Python ที่เต็มเปี่ยม
code_dredd

3
@ray True แต่คำตอบยังคงมีประโยชน์บนพื้นฐานที่ว่าคำถามไม่ควรนำไปใช้กับผู้ที่โพสต์พวกเขา หากคุณใช้รูปแบบที่ได้มาตรฐาน (เช่น INI, JSON, YAML, XML ฯลฯ ) คุณอาจจะใช้ห้องสมุดการแยกวิเคราะห์ที่มีอยู่แทนที่จะเขียนด้วยตัวคุณเอง ที่ช่วยลดการทำงานเพิ่มเติมให้กับคลาสอะแดปเตอร์เพื่อเชื่อมต่อกับไลบรารีการแยกวิเคราะห์ หากคุณกำลัง จำกัด ตัวเองให้อยู่ที่ key = value นั่นหมายความว่าเหตุผลส่วนใหญ่ของ OP จะใช้ Python ในตอนแรกและคุณอาจจะไปกับรูปแบบที่เป็นที่รู้จัก
Jon Bentley

3
ฉันต้องทำสิ่งนี้เมื่อไม่กี่ปีที่ผ่านมาเมื่อเครื่องมือที่เขียนใน Lua ใช้สคริปต์ Lua เป็นค่ากำหนดจากนั้นพวกเขาต้องการให้เราเขียนเครื่องมือใหม่ใน C # และขอให้เราใช้สคริปต์ Lua โดยเฉพาะ พวกเขามีทั้งหมด 2 บรรทัดที่ตั้งโปรแกรมได้จริงและไม่ใช่ x = y ง่าย ๆ แต่ฉันยังต้องเรียนรู้เกี่ยวกับล่าม Lua โอเพนซอร์ซสำหรับ. net เพราะพวกเขา มันไม่ได้เป็นข้อโต้แย้งทางทฤษฎีอย่างหมดจด
ค่าธรรมเนียมของเควิน

21

คำตอบอื่น ๆ นั้นดีมากฉันจะนำประสบการณ์การใช้งานจริงมาใช้ในโครงการไม่กี่โครงการ

ข้อดี

พวกเขาส่วนใหญ่สะกดออกมาแล้ว:

  • หากคุณอยู่ในโปรแกรม Python การแยกวิเคราะห์เป็นเรื่องง่าย ( eval); มันทำงานโดยอัตโนมัติแม้สำหรับชนิดข้อมูลที่ซับซ้อนมากขึ้น (ในโปรแกรมของเราเรามีจุดทางเรขาคณิตและการแปลงซึ่งถูกทิ้ง / โหลดได้ดีผ่านrepr/ eval);
  • การสร้าง "การกำหนดค่าปลอม" โดยมีโค้ดเพียงไม่กี่บรรทัดนั้นไม่สำคัญ
  • คุณมีโครงสร้างที่ดีขึ้นและ IMO มีไวยากรณ์ที่ดีกว่า JSON (jeez เพียงแค่มีความคิดเห็นและไม่ต้องใส่เครื่องหมายคำพูดคู่ล้อมรอบคีย์พจนานุกรมเป็นการชนะการอ่านได้มาก)

จุดด้อย

  • ผู้ใช้ที่เป็นอันตรายสามารถทำอะไรก็ได้ที่โปรแกรมหลักของคุณสามารถทำได้ ฉันไม่ได้พิจารณาปัญหานี้มากนักเนื่องจากโดยทั่วไปหากผู้ใช้สามารถแก้ไขไฟล์กำหนดค่าเขา / เธอสามารถทำสิ่งที่แอปพลิเคชันสามารถทำได้
  • หากคุณไม่อยู่ในโปรแกรม Python อีกต่อไปตอนนี้คุณมีปัญหา ในขณะที่ไฟล์การกำหนดค่าของเราหลายไฟล์ยังคงเป็นส่วนตัวกับแอปพลิเคชันดั้งเดิมของพวกเขาหนึ่งในนั้นมาเพื่อเก็บข้อมูลที่ใช้โดยหลาย ๆ โปรแกรมซึ่งส่วนใหญ่อยู่ใน C ++ ซึ่งตอนนี้มี parser ที่แฮ็กเข้าด้วยกัน reprเซตของงูใหญ่ เห็นได้ชัดว่านี่เป็นสิ่งที่ไม่ดี
  • แม้ว่าโปรแกรมของคุณจะยังคงอยู่ใน Python คุณสามารถเปลี่ยนรุ่น Python ได้ สมมติว่าแอปพลิเคชันของคุณเริ่มต้นใน Python 2 หลังจากที่จำนวนมากของการทดสอบคุณมีการจัดการที่จะโยกย้ายไปยังหลาม 3 - น่าเสียดายที่คุณไม่ได้จริงๆทดสอบทั้งหมดของรหัสของคุณ - คุณมีแฟ้มการกำหนดค่าโกหกรอบบนเครื่องของลูกค้าที่เขียนขึ้นสำหรับงูหลาม 2 และที่คุณดอน ควบคุมไม่ได้จริงๆ คุณไม่สามารถแม้แต่จะให้ "โหมดความเข้ากันได้" เพื่ออ่านไฟล์การกำหนดค่าเก่า (ซึ่งมักทำในรูปแบบไฟล์) เว้นแต่คุณจะยินดีที่จะมัด / โทรล่าม Python 2!
  • แม้ว่าคุณจะอยู่ใน Python การแก้ไขไฟล์การกำหนดค่าจากรหัสเป็นปัญหาจริงเพราะ ... ดีการแก้ไขโค้ดนั้นไม่สำคัญเลยโดยเฉพาะอย่างยิ่งรหัสที่มีไวยากรณ์ที่หลากหลายและไม่ได้อยู่ใน LISP หรือที่คล้ายกัน หนึ่งในโปรแกรมของเรามีการตั้งค่าไฟล์ที่เป็นงูหลามเขียนด้วยมือ แต่ซึ่งต่อมาได้เปิดออกมามันจะมีประโยชน์ในการจัดการผ่านซอฟต์แวร์ (การตั้งค่าโดยเฉพาะอย่างยิ่งเป็นรายการของสิ่งที่เป็นวิธีที่ง่ายในการเรียงลำดับการใช้ GUI) นี่เป็นปัญหาใหญ่เพราะ:

    • แม้เพียงแค่ดำเนินการแยกวิเคราะห์→ AST →การเขียนไปกลับไม่สำคัญ (คุณจะสังเกตเห็นว่าครึ่งหนึ่งของวิธีแก้ปัญหาที่เสนอถูกทำเครื่องหมายในภายหลังว่า "ล้าสมัยไม่ใช้ไม่สามารถใช้งานได้ในทุกกรณี");
    • แม้ว่าพวกเขาจะทำงาน AST ก็ต่ำเกินไป โดยทั่วไปคุณสนใจที่จะจัดการกับผลลัพธ์ของการคำนวณที่ดำเนินการในไฟล์ไม่ใช่ขั้นตอนที่นำมาใช้
    • ซึ่งนำเราไปสู่ความจริงง่ายๆที่คุณไม่สามารถเพียงแค่แก้ไขค่าที่คุณสนใจเพราะอาจถูกสร้างขึ้นโดยการคำนวณที่ซับซ้อนบางอย่างที่คุณไม่สามารถเข้าใจ / จัดการผ่านรหัสของคุณ

    เปรียบเทียบสิ่งนี้กับ JSON, INI หรือ (God forbid!) XML ซึ่งการแสดงในหน่วยความจำสามารถแก้ไขและเขียนกลับได้เสมอโดยไม่สูญเสียข้อมูล (XML ซึ่ง parsers DOM ส่วนใหญ่สามารถเก็บช่องว่างในโหนดข้อความและโหนดความคิดเห็น) หรือ อย่างน้อยจะสูญเสียการจัดรูปแบบบางอย่าง (JSON ซึ่งรูปแบบนั้นไม่อนุญาตให้มากกว่าข้อมูลดิบที่คุณกำลังอ่าน)


ดังนั้นตามปกติไม่มีวิธีแก้ปัญหาที่ชัดเจน นโยบายปัจจุบันของฉันเกี่ยวกับปัญหาคือ:

  • หากไฟล์การกำหนดค่าคือ:

    • แน่นอนสำหรับแอปพลิเคชั่น Python และเป็นส่วนตัว - เหมือนที่ไม่มีใครเคยลองอ่านจากมัน
    • ที่เขียนด้วยมือ;
    • มาจากแหล่งที่เชื่อถือได้;
    • การใช้ชนิดข้อมูลแอปพลิเคชันเป้าหมายนั้นเป็นสิ่งที่มีคุณภาพ

    ไฟล์ Python อาจเป็นแนวคิดที่ถูกต้อง

  • ถ้าแทน:

    • อาจมีความเป็นไปได้ที่จะมีแอปพลิเคชั่นอื่นอ่านอยู่
    • มีความเป็นไปได้ว่าไฟล์นี้อาจถูกแก้ไขโดยแอปพลิเคชันอาจเป็นไปได้ว่าแอปพลิเคชันของฉันเอง
    • ให้บริการโดยแหล่งที่ไม่น่าเชื่อถือ

    รูปแบบ "data only" อาจเป็นแนวคิดที่ดีกว่า

โปรดสังเกตว่าไม่จำเป็นต้องเลือกตัวเลือกเดียว - เมื่อเร็ว ๆ นี้ฉันเขียนแอปพลิเคชันที่ใช้ทั้งสองวิธี ฉันมีไฟล์ที่แทบไม่เคยแก้ไขด้วยการตั้งค่าครั้งแรกการตั้งค่าที่เขียนด้วยลายมือซึ่งมีข้อดีของการได้รับโบนัส Python ที่ดีและไฟล์ JSON สำหรับการกำหนดค่าที่แก้ไขจาก UI


1
จุดที่ดีมากเกี่ยวกับการสร้างหรือเขียนการตั้งค่าใหม่! แต่รูปแบบอื่นนอกเหนือจาก XML สามารถเก็บความคิดเห็นไว้ในผลลัพธ์ได้ รูปแบบอื่น ๆ บางครั้งแนะนำnote:เขตข้อมูลที่ถูกละเว้นสำหรับการกำหนดค่า
amon

2
"ถ้าผู้ใช้สามารถแก้ไขไฟล์กำหนดค่าเขา / เธอสามารถทำสิ่งใดก็ได้ที่แอปพลิเคชันสามารถทำได้" - นี่ไม่เป็นความจริงเลย วิธีการเกี่ยวกับการทดสอบกว่าไฟล์กำหนดค่ามันวาวคนที่คุณไม่รู้จักอัพโหลดบน pastebin
Dmitry Grigoryev

2
@DmitryGrigoryev: หากคุณกำลังเล็งไปที่เป้าหมายคุณอาจบอกเหยื่อของคุณให้ทำสำเนาบางส่วนcurl ... | bashมันเป็นเรื่องยุ่งยากน้อยลง :-P
Matteo Italia

@DmitryGrigoryev: และเป็นประเภทของสิ่งที่อาจทำให้ใครบางคนทำลายระบบการผลิตอย่างสมบูรณ์ในวันแรกของการทำงาน หาก 'eval' เป็นตัวแยกวิเคราะห์ของคุณนั่นหมายความว่าไม่มีโอกาสตรวจสอบปัญหาก่อนที่จะถูกอ่าน (เหตุผลเดียวกันกับที่ว่าทำไมเชลล์สคริปต์ไม่ดีในการผลิต) INI, YAML หรือ JSON นั้นปลอดภัยในเรื่องนี้
Joe

1
@DmitryGrigoryev: จุดของฉันคือว่าถ้าประเภทเหยื่อของคุณโง่พอที่จะคัดลอกวางไฟล์การตั้งค่าคุณอาจหลอกให้เขา / เธอทำสิ่งใด ๆ บนเครื่องของพวกเขาด้วยวิธีการเอียงน้อยลง ("วางลงในคอนโซลเพื่อ แก้ไขปัญหาของคุณ! ") นอกจากนี้แม้จะมีไฟล์กำหนดค่าที่ไม่สามารถเรียกใช้งานได้ แต่ก็มีความเป็นไปได้ที่จะก่อให้เกิดอันตราย - แม้เพียงแค่การบันทึกข้อมูลไฟล์สำคัญ (หากแอปพลิเคชันทำงานด้วยสิทธิ์ที่เพียงพอ) คุณสามารถสร้างความเสียหาย นั่นเป็นเหตุผลที่ฉันคิดว่าในทางปฏิบัติมันไม่ได้มีความแตกต่างในแง่ความปลอดภัย
Matteo Italia

8

คำถามหลักคือ: คุณต้องการให้ไฟล์การกำหนดค่าของคุณเป็นภาษาทัวริงที่สมบูรณ์ (เช่น Python หรือไม่) หากคุณต้องการคุณอาจพิจารณาฝังภาษาสคริปต์ (ทัวริงสมบูรณ์) อื่น ๆเช่นGuileหรือLua (เพราะอาจถูกมองว่าเป็น "ง่ายกว่า" เพื่อใช้หรือฝังมากกว่า Python คืออ่านบทเกี่ยวกับการขยาย & การฝัง Python ) ฉันจะไม่พูดคุยเรื่องนี้เพิ่มเติม (เพราะคำตอบอื่น ๆ- โดย Amon - กล่าวถึงเรื่องนี้ในเชิงลึก) แต่โปรดสังเกตว่าการฝังภาษาสคริปต์ในแอปพลิเคชันของคุณเป็นตัวเลือกสถาปัตยกรรมที่สำคัญที่คุณควรพิจารณาก่อน; ฉันไม่แนะนำให้เลือกในภายหลัง!

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

อย่างไรก็ตาม (อย่างน้อยในระบบ POSIX) คุณอาจพิจารณาความสะดวกในการเปิดใช้งานการกำหนดค่า "ไฟล์" ที่จะคำนวณแบบไดนามิกในเวลาเริ่มต้น (แน่นอนทำให้ภาระในการตั้งค่าสติไปยังผู้ดูแลระบบหรือผู้ใช้ของคุณจริงๆแล้วมันเป็นการกำหนดค่าข้อความที่มาจากไฟล์บางไฟล์หรือจากบางคำสั่ง) เพื่อที่คุณก็สามารถนำมาใช้ในการประชุม (และเอกสารมัน) ที่เส้นทางแฟ้มการกำหนดค่าเริ่มต้นด้วยเช่น!หรือ|เป็นจริงเปลือกคำสั่งที่คุณจะอ่านเป็นท่อ สิ่งนี้จะทำให้ผู้ใช้ของคุณมีตัวเลือกในการใช้ "preprocessor" หรือ "ภาษาสคริปต์" ที่ผู้ใช้คุ้นเคยที่สุด

(คุณต้องไว้วางใจผู้ใช้ของคุณเกี่ยวกับปัญหาด้านความปลอดภัยหากคุณยอมรับการกำหนดค่าที่คำนวณแบบไดนามิก)

ดังนั้นในรหัสการเริ่มต้นของคุณmainจะ (ตัวอย่าง) ยอมรับ--config ข้อโต้แย้ง confargและรับบางอย่างFILE*configf;จากมัน ถ้าอาร์กิวเมนต์ที่เริ่มต้นด้วย!(เช่นถ้า(confarg[0]=='!').... ) คุณจะใช้และปิดท่อที่มีconfigf = popen(confarg+1, "r"); pclose(configf);มิฉะนั้นคุณจะใช้configf=fopen(confarg, "r");และปิดไฟล์นั้นด้วยfclose(configf);(อย่าลืมตรวจสอบข้อผิดพลาด) ดูท่อ (7) , popen (3) , fopen (3) สำหรับแอปพลิเคชันที่เขียนใน Python อ่านเกี่ยวกับos.popenฯลฯ ...

(เอกสารยังสำหรับผู้ใช้ที่ต้องการแปลกที่จะผ่านการตั้งค่าไฟล์ชื่อ!foo.configที่จะผ่าน./!foo.configข้ามpopenเคล็ดลับด้านบน)

BTW กลอุบายดังกล่าวเป็นเพียงความสะดวกสบาย (เพื่อหลีกเลี่ยงการต้องการผู้ใช้ขั้นสูงเช่นรหัสเชลล์สคริปต์บางส่วนเพื่อสร้างไฟล์การกำหนดค่า) หากผู้ใช้ต้องการรายงานข้อผิดพลาดใด ๆ เขาควรส่งไฟล์การกำหนดค่าที่สร้างขึ้นให้คุณ...

โปรดสังเกตว่าคุณสามารถออกแบบแอปพลิเคชันของคุณด้วยความสามารถในการใช้และโหลดปลั๊กอินในเวลาเริ่มต้นเช่นด้วยdlopen (3) (และคุณต้องเชื่อใจผู้ใช้ของคุณเกี่ยวกับปลั๊กอินนั้น) นี่คือการตัดสินใจทางสถาปัตยกรรมที่สำคัญมาก (และคุณต้องกำหนดและให้APIและระเบียบที่มีความเสถียรเกี่ยวกับปลั๊กอินและแอปพลิเคชันของคุณ)

สำหรับแอปพลิเคชันที่เขียนด้วยภาษาสคริปต์เช่น Python คุณสามารถยอมรับอาร์กิวเมนต์ของโปรแกรมบางอย่างสำหรับevalหรือexecหรือ primitives ที่คล้ายกัน อีกครั้งปัญหาด้านความปลอดภัยแล้วความกังวลของ (ขั้นสูง) ของผู้ใช้

เกี่ยวกับรูปแบบข้อความสำหรับไฟล์กำหนดค่าของคุณ (ไม่ว่าจะสร้างขึ้นหรือไม่ก็ตาม) ฉันเชื่อว่าส่วนใหญ่คุณต้องจัดทำเอกสารให้ดี (และการเลือกรูปแบบเฉพาะบางอย่างนั้นไม่สำคัญ) อย่างไรก็ตามฉันแนะนำให้ผู้ใช้ของคุณวาง มีความคิดเห็น -skipped- อยู่ข้างใน) คุณสามารถใช้ JSON (โดยเฉพาะกับตัวแยกวิเคราะห์ JSON บางส่วนที่ยอมรับและข้ามความคิดเห็นด้วยปกติ//จนถึง eol หรือ/*... */... ) หรือ YAML หรือ XML หรือ INI หรือของคุณเอง การแยกไฟล์การกำหนดค่านั้นง่ายมาก (และคุณจะพบกับไลบรารีจำนวนมากที่เกี่ยวข้องกับงานนั้น)


+1 สำหรับการกล่าวถึงทัวริงสมบูรณ์ของภาษาโปรแกรม งานที่น่าสนใจบางอย่างเผยให้เห็นว่าการ จำกัด อำนาจการคำนวณของรูปแบบอินพุตเป็นกุญแจสำคัญในการรักษาความปลอดภัยเลเยอร์การจัดการอินพุต การใช้ภาษาโปรแกรมทัวริงที่สมบูรณ์จะไปในทิศทางตรงกันข้าม
Matheus Moreira

2

การเพิ่มคำตอบของอมรมีคุณพิจารณาทางเลือก? JSON อาจมากกว่าที่คุณต้องการ แต่ไฟล์ Python อาจจะทำให้คุณมีปัญหาในอนาคตด้วยเหตุผลดังกล่าวข้างต้น

อย่างไรก็ตาม Python มีตัวแยกวิเคราะห์การกำหนดค่าสำหรับภาษาการกำหนดค่าแบบง่าย ๆ ที่อาจตอบสนองทุกความต้องการของคุณ ConfigParserโมดูลดำเนินการตั้งค่าภาษาที่เรียบง่าย


1
การใช้บางสิ่งที่ 'คล้ายกับ ... ไฟล์ Microsoft Windows INI' ดูเหมือนจะเป็นความคิดที่ไม่ดีทั้งที่มันไม่ใช่รูปแบบที่ยืดหยุ่นเป็นพิเศษและเพราะ 'คล้ายกัน' หมายถึงความไม่ลงรอยกันที่ไม่มีเอกสาร
Pete Kirkham

1
@PeteKirkham มันง่ายมันเป็นเอกสารและเป็นส่วนหนึ่งของ Python standard library อาจเป็นโซลูชั่นที่สมบูรณ์แบบสำหรับความต้องการของ OPs เพราะเขากำลังค้นหาบางสิ่งที่ Python สนับสนุนโดยตรงและง่ายกว่า JSON ตราบใดที่เขาไม่ได้ระบุว่าเขาต้องการอะไรฉันคิดว่าคำตอบนี้อาจเป็นประโยชน์กับเขา
CodeMonkey

1
ฉันจะแนะนำสิ่งนี้ - ดูว่าไฟล์การกำหนดค่าชนิดใดที่ Python libs สนับสนุนและเลือกหนึ่งในนั้น นอกจากนี้ Powershell ยังมีแนวคิดเกี่ยวกับส่วนของข้อมูลซึ่งอนุญาตให้มีการสร้างภาษา Powershell ที่ จำกัด เพื่อปกป้องรหัสที่เป็นอันตราย หาก Python มี lib ที่สนับสนุนชุดย่อยของ Python ที่ จำกัด สำหรับการกำหนดค่าอย่างน้อยก็ช่วยลดข้อเสียข้อใดข้อหนึ่งต่อแนวคิดใน OP
Χpẘ

1
@PeteKirkham มีโอกาสมากขึ้นที่จะเป็นปัญหาในทางกลับกัน Windows มีแนวโน้มที่จะมีอึที่ไม่มีเอกสารซึ่งจะระเบิดคุณ Python มีเอกสารที่ดีและตรงไปตรงมา ที่กล่าวว่าหากคุณต้องการเพียงคีย์คู่ / ค่า ( อาจมีส่วน) ก็เป็นตัวเลือกที่ดีทีเดียว ฉันสงสัยว่ากรณีนี้ครอบคลุม 90% ของกรณีการใช้งาน หากไฟล์การกำหนดค่าของ. NET เป็น ini แทนที่จะเป็น XML ที่ชั่วร้ายที่มีสคีมาซึ่งจริง ๆ แล้วทำการปลอมแปลงรหัสเป็นการตั้งค่าเราทุกคนต่างออกไปดีกว่า
jpmc26

1
@ PetKirkham ไม่ได้จริงๆ INI ดีที่สุดสำหรับกรณีการใช้งานง่ายตั้งแต่แรกโอกาสที่คุณสามารถหลีกเลี่ยงความไม่ลงรอยกันได้ พวกเขายังไม่สำคัญหากคุณไม่ได้ใช้ไฟล์ที่มีสองภาษาที่แตกต่างกันและแม้ว่าคุณจะเป็นคุณอาจพบว่าการใช้งานแบบเปิดในภาษาใด ๆ (ช่วยให้คุณไม่มีความเข้ากันไม่ได้หรืออย่างน้อยที่สุด พวกเขาคือ). ฉันยอมรับว่าคุณควรใช้รูปแบบอื่นหากกรณีการใช้งานของคุณมีความซับซ้อนมากพอที่จะเริ่มใช้งานได้หรือถ้าคุณไม่พบการใช้งานที่มีอยู่คุณสามารถเชื่อถือได้ แต่นั่นไม่ใช่เรื่องปกติ
jpmc26

1

ฉันทำงานเป็นเวลานานกับซอฟต์แวร์ที่รู้จักกันดีซึ่งมีไฟล์กำหนดค่าที่เขียนใน TCL ดังนั้นแนวคิดจึงไม่ใช่เรื่องใหม่ วิธีนี้ใช้งานได้ดีเนื่องจากผู้ใช้ที่ไม่ทราบว่าภาษายังคงสามารถเขียน / แก้ไขไฟล์การกำหนดค่าง่าย ๆ โดยใช้set name valueคำสั่งเดียวในขณะที่ผู้ใช้และนักพัฒนาขั้นสูงสามารถดึงลูกเล่นที่ซับซ้อนได้

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

การเขียนทับการกำหนดค่าเป็นปัญหา แต่ก็ไม่ได้เลวร้ายอย่างที่คิด การอัปเดตรหัสโดยอำเภอใจเป็นไปไม่ได้ แต่การโหลดการกำหนดค่าจากไฟล์การเปลี่ยนแปลงและการบันทึกกลับเป็น โดยทั่วไปถ้าคุณทำสคริปต์บางอย่างในไฟล์กำหนดค่าที่ไม่ได้เป็นแบบอ่านอย่างเดียวคุณจะจบลงด้วยรายการset name valueคำสั่งที่เทียบเท่ากันเมื่อมีการบันทึก คำใบ้ที่ดีว่าสิ่งนี้จะเกิดขึ้นคือความคิดเห็น "ห้ามแก้ไข" ที่จุดเริ่มต้นของไฟล์

สิ่งหนึ่งที่ควรพิจารณาคือไฟล์กำหนดค่าของคุณจะไม่สามารถอ่านได้อย่างน่าเชื่อถือด้วยเครื่องมือที่ใช้ regex อย่างง่ายเช่นsedแต่เท่าที่ฉันเข้าใจว่านี่ไม่ใช่กรณีของไฟล์ JSON ปัจจุบันของคุณดังนั้นจึงไม่มีอะไรเสีย

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


1
"ซอฟต์แวร์" เป็นคำนามนับไม่ได้ดังนั้นจึงควรจะเป็น " บางซอฟแวร์ที่รู้จักกันดี."
jpmc26

1

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

  1. การตั้งค่าภายในไฟล์ต้นฉบับของ Python นั้นเป็นส่วนหนึ่งของซอร์สโค้ดที่สามารถใช้งานได้แทนที่จะเป็นไฟล์ข้อมูลแบบอ่านอย่างเดียว ถ้าคุณไปเส้นทางนี้โดยทั่วไปแล้วคุณจะทำimport configเพราะ "ความสะดวกสบาย" นั้นน่าจะเป็นหนึ่งในสาเหตุหลักที่ผู้คนเริ่มต้นด้วยการใช้ไฟล์ Python เป็น config ในตอนแรก ตอนนี้คุณมีแนวโน้มที่จะยอมรับว่า config.py ใน repo ของคุณมิฉะนั้นผู้ใช้ของคุณจะพบกับ ImportError ที่สับสนเมื่อพวกเขาพยายามเรียกใช้โปรแกรมของคุณเป็นครั้งแรก

  2. สมมติว่าคุณยอมรับว่า config.py ใน repo ของคุณตอนนี้สมาชิกในทีมของคุณอาจมีการตั้งค่าที่แตกต่างกันในสภาพแวดล้อมที่แตกต่างกัน ลองนึกภาพวันหนึ่งสมาชิกบางคนตั้งใจส่งไฟล์การกำหนดค่าท้องถิ่นของเขา / เธอไปที่ repo โดยไม่ตั้งใจ

  3. สุดท้าย แต่ไม่ใช่อย่างน้อยโครงการของคุณอาจมีรหัสผ่านในไฟล์กำหนดค่า (นี่เป็นวิธีปฏิบัติที่ถกเถียงกันในตัวมันเอง แต่มันเกิดขึ้นต่อไป) และหากไฟล์การกำหนดค่าของคุณมีอยู่ใน repo คุณมีความเสี่ยงที่จะยอมรับข้อมูลประจำตัวของคุณใน repo สาธารณะ

ในตอนนี้การใช้ไฟล์กำหนดค่าข้อมูลอย่างเดียวเช่นรูปแบบ JSON สากลสามารถหลีกเลี่ยงปัญหาทั้งสามข้อด้านบนได้เนื่องจากคุณสามารถขอให้ผู้ใช้สร้าง config.json ของตนเองและป้อนเข้าโปรแกรมของคุณ

PS: มันเป็นความจริงที่ JSON มีข้อ จำกัด มากมาย 2 ข้อ จำกัด ที่กล่าวถึงโดย OP สามารถแก้ไขได้ด้วยความคิดสร้างสรรค์

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