เหตุใด IoC / DI จึงไม่ธรรมดาใน Python


312

ใน Java IoC / DIเป็นวิธีปฏิบัติทั่วไปที่ใช้กันอย่างแพร่หลายในเว็บแอปพลิเคชันเกือบทุกเฟรมเวิร์กที่มีอยู่และ Java EE ในทางกลับกันมีเว็บแอพพลิเคชั่น Python ขนาดใหญ่จำนวนมาก แต่นอกเหนือจาก Zope (ซึ่งฉันได้ยินมาว่าน่ากลัวรหัส) IoC ดูเหมือนจะไม่ธรรมดาในโลก Python (โปรดระบุชื่อตัวอย่างถ้าคุณคิดว่าฉันผิด)

มีแน่นอนหลายโคลนนิ่งนิยม Java IoC กรอบพร้อมใช้งานสำหรับหลามspringpythonตัวอย่างเช่น แต่ดูเหมือนว่าจะไม่มีใครใช้มันได้เลย อย่างน้อยฉันไม่เคยเหยียบย่ำแอปพลิเคชันบนเว็บDjangoหรือsqlalchemy + <insert your favorite wsgi toolkit here>ซึ่งใช้อะไรแบบนั้น

ในความคิดของฉัน IoC มีข้อได้เปรียบที่สมเหตุสมผลและจะทำให้ง่ายต่อการแทนที่ django-default-user-model ตัวอย่างเช่น แต่การใช้อินเตอร์เฟซคลาสที่กว้างขวางและ IoC ใน Python นั้นค่อนข้างแปลกและไม่ใช่ "pythonic « แต่บางคนอาจมีคำอธิบายที่ดีกว่าทำไม IoC ไม่ได้ใช้อย่างกว้างขวางใน Python


2
ฉันเดาด้วยเหตุผลเดียวกันว่ามันเป็นที่นิยมน้อยลงใน Ruby, มิกซินในตัวและคลาสเปิด
Sam Saffron

3
คุณเคยลอง springpython ไหม? มันไม่ทำงานตามที่โฆษณาไว้ อย่างน้อยในส่วน aop ทุกอย่างในนั้นไม่มีประโยชน์เว้นแต่คุณจะมาจากจาวาและต้องการความสะดวกสบายในระดับหนึ่งในช่วงการเปลี่ยนภาพ
Tom Willis

6
โปรดใช้ความระมัดระวังในการแยกแยะระหว่างการใช้ DI และการใช้ IOC framework อดีตเป็นรูปแบบการออกแบบหลังเป็นกรอบเพื่อช่วยในการใช้งานอัตโนมัติของอดีต
Doug

ดั๊กฉันเชื่อว่าคุณตั้งใจจะพูดว่า DI เป็นคุณสมบัติสร้างสรรค์ที่ได้มาจากการใช้รูปแบบมัณฑนากร
njappboy

4
ฉันชอบที่จะเห็นคำตอบที่ตอบปัญหาของโลกแห่งความเป็นจริงที่ DI แก้: การจัดการตลอดชีวิตการทดสอบการขัดถูเป็นต้นหากมีวิธี Pythonic มากขึ้นในการจัดการปัญหาเหล่านี้ฉันทุกคนหู
Josh Noe

คำตอบ:


197

ฉันไม่คิดว่าจริง DI / IoC เป็นที่ผิดปกติในหลาม อะไรเป็นเรื่องผิดปกติ แต่มี DI / IoC กรอบ / ภาชนะบรรจุกรอบ

ลองคิดดู: ภาชนะ DI ทำอะไร? จะช่วยให้คุณ

  1. รวมส่วนประกอบอิสระเข้าด้วยกันเป็นแอปพลิเคชันที่สมบูรณ์ ...
  2. ... ที่รันไทม์

เรามีชื่อสำหรับ "เดินสายเข้าด้วยกัน" และ "ที่รันไทม์":

  1. สคริปต์
  2. พลวัต

ดังนั้นคอนเทนเนอร์ DI ไม่มีอะไรเลยนอกจากเป็นล่ามสำหรับภาษาสคริปต์แบบไดนามิก ที่จริงฉันขอใช้ถ้อยคำใหม่ว่า: คอนเทนเนอร์ Java / .NET DI ทั่วไปไม่มีอะไรนอกจากล่ามเส็งเคร็งสำหรับภาษาสคริปต์แบบไดนามิกที่ไม่ดีจริงๆพร้อมกับน่าเกลียดบางครั้งใช้ไวยากรณ์ XML

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

ดังนั้นการสรุป: การฝึกฝน DI / IoC นั้นสำคัญกับ Python เหมือนกับใน Java ด้วยเหตุผลเดียวกันทั้งหมด การดำเนินการ DI / IoC มาใช้นั้นถูกสร้างขึ้นเป็นภาษาและมีน้ำหนักเบาจนหายไปอย่างสมบูรณ์

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

BTW: สำหรับตัวอย่างของสิ่งที่ดูเหมือนว่าจะนำ DI ไปสู่ข้อสรุปเชิงตรรกะลองดูที่ภาษาโปรแกรมของNewspeakของGilad Brachaและงานเขียนของเขาในหัวข้อ:


58
ในขณะที่ฉันเห็นด้วย ความคิดเห็น XML ไม่ถูกต้อง คอนเทนเนอร์ IOC จำนวนมาก (อย่างน้อยทันสมัย) ใช้หลักการ (รหัส) เหนือการกำหนดค่า (XML)
Finglas

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

133
"การนำ DI / IoC ไปใช้งานนั้นถูกสร้างขึ้นเป็นภาษาและบ่อยครั้งที่มันจางหายไปอย่างสิ้นเชิง" ลงคะแนนเพราะนี่ไม่เป็นความจริงอย่างเด็ดขาด DI เป็นรูปแบบที่อินเตอร์เฟสถูกส่งผ่านไปยังตัวสร้าง มันไม่ได้มีอยู่แล้วในหลาม
Doug

146
downvote การเดินสายเข้าด้วยกันไม่เกี่ยวข้องกับการเขียนสคริปต์ DI เป็นรูปแบบและไม่เทียบเท่ากับการเขียนสคริปต์
Luxspes

38
ฉันไม่เห็นด้วยกับสิ่งนี้ DI ไม่ได้แก้ปัญหาการเขียนสคริปต์แบบไดนามิกในภาษาคงที่ มันมีกรอบสำหรับการกำหนดค่าและการเขียนส่วนของแอปพลิเคชันของคุณ ฉันเคยได้ยิน Ruby dev พูดว่า DI ไม่จำเป็นในภาษาแบบไดนามิก แต่เขาใช้ Rails ... Rails เป็นเพียงตู้คอนเทนเนอร์ขนาดใหญ่ DI ซึ่งใช้หลักการประชุมเพื่อกำหนดว่าส่วนใดที่ควรกำหนดค่าเมื่อ เขาไม่ต้องการ DI เพราะ Rails แก้ไขปัญหาในการค้นหาชิ้นส่วนสำหรับเขา
Brian Genisio

51

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

ตรงกันข้ามกับ Java ซึ่งคุณไม่ได้นำเข้าอินสแตนซ์ของวัตถุที่แท้จริง ซึ่งหมายความว่าคุณจะต้องยกตัวอย่างพวกเขาด้วยตัวเองเสมอ (หรือใช้แนวทางสไตล์ IoC / DI บางประเภท) คุณสามารถลดความยุ่งยากในการสร้างอินสแตนซ์ทุกอย่างด้วยตนเองโดยใช้วิธีการแบบคงที่จากโรงงาน (หรือคลาสโรงงานจริง) แต่จากนั้นคุณยังคงต้องใช้ทรัพยากรในการสร้างสิ่งใหม่ในแต่ละครั้ง


2
นั่นทำให้รู้สึก ถ้าฉันต้องการเปลี่ยนการใช้งานใน Python ฉันเพียงนำเข้าจากที่อื่นโดยใช้ชื่อเดียวกัน แต่ตอนนี้ฉันกำลังคิดว่ามันเป็นไปได้ในทางกลับกันโดยการกำหนดMyClassInstancesคลาสให้กับแต่ละคลาสMyClassใน Java ซึ่งมีอินสแตนซ์คงที่เท่านั้นและเริ่มต้นได้อย่างสมบูรณ์ นั่นจะเป็นสาย: D
tux21b

2
และแนวคิดอื่น: การให้วิธีการเปลี่ยนการนำเข้าเช่นในงูหลามจะทำให้สามารถแทนที่การนำไปใช้งานได้ง่ายโดยไม่ต้องแตะไฟล์หลามทั้งหมด แทนที่จะfrom framework.auth.user import User เป็นการดีกว่าที่จะเขียนUser = lookup('UserImplentation', 'framework.auth.user.User')(พารามิเตอร์ตัวที่ 2 อาจเป็นค่าเริ่มต้น) ภายในกรอบงาน จากนั้นผู้ใช้เฟรมเวิร์กจะสามารถแทนที่ / ชำนาญการUserใช้งานโดยไม่ต้องสัมผัสเฟรมเวิร์ก
tux21b

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

3
จริงๆแล้ว DI นั้นเกี่ยวกับความสามารถในการทดสอบและแยกการพึ่งพารหัส คุณลักษณะการนำเข้านั้นคล้ายกับการนำเข้าแบบคงที่ใน Java ซึ่งให้ฉันนำเข้าอินสแตนซ์เดียวของวัตถุ
Richard Warburton

1
"คุณสามารถรับ" ซิงเกิลตัน "ได้ฟรีเพียงแค่นำเข้าจากโมดูล" สามารถทำได้อย่างง่ายดายใน Java โดยการประกาศฟิลด์อินสแตนซ์แบบคงที่และตั้งค่าเป็นค่า นี่ไม่ใช่โซล
ggranum

45

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

ตัวอย่างที่ดีที่สุดคือวิธีการตั้งค่าแอปพลิเคชัน Django โดยใช้settings.py:

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URL + '/1',
    },
    'local': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'snowflake',
    }
}

Django Rest Framework ใช้ DI อย่างหนัก:

class FooView(APIView):
    # The "injected" dependencies:
    permission_classes = (IsAuthenticated, )
    throttle_classes = (ScopedRateThrottle, )
    parser_classes = (parsers.FormParser, parsers.JSONParser, parsers.MultiPartParser)
    renderer_classes = (renderers.JSONRenderer,)

    def get(self, request, *args, **kwargs):
        pass

    def post(self, request, *args, **kwargs):
        pass

ให้ฉันเตือน (ที่มา ):

"การพึ่งพาการฉีด" เป็นคำที่ 25 ดอลลาร์สำหรับแนวคิด 5 เซ็นต์ [... ] การฉีดพึ่งพาหมายถึงการให้วัตถุตัวแปรอินสแตนซ์ของมัน [ ... ]


8
+1 ใส่กัน การเป็นโปรแกรมเมอร์ Python ฉันรู้สึกงุนงงกับการนำเสนอการสัมภาษณ์ทั้งหมดในกรอบ DI ใน C # ใช้เวลาสักครู่ในการตระหนักว่าฉันได้ทำมันตลอดเวลาในแอพ Flask โดยไม่ต้องคิดอะไรเพราะคุณไม่ต้องการกรอบ สำหรับคนที่ไม่รู้อะไรเลยนอกจาก C # / Java คำถามนี้สมเหตุสมผล สำหรับนักเขียนโปรแกรมภาษาที่พิมพ์เป็ดมันเป็นเรื่องธรรมดาและอย่างที่คุณพูด "คำศัพท์ 25 ดอลลาร์สำหรับแนวคิด 5 สตางค์"
ซามูเอลฮาร์เมอร์

5
เอ่อ ... นี่ไม่ใช่การฉีดขึ้นอยู่กับอินสแตนซ์ ( IsAuthenticated, ScopedRateThrottle) ถูกสร้างโดยอินสแตนซ์ พวกมันจะไม่ถูกส่งเข้าไปในตัวสร้าง
dopatraman

5
IsAuthenticatedและScopedRateThrottleไม่ใช่อินสแตนซ์เหล่านี้เป็นคลาส พวกมันจะถูกสร้างขึ้นทันทีเมื่อสร้าง FooView (จริง ๆ แล้วเมื่อ FooView ประมวลผลคำขอ) อย่างไรก็ตามนี่เป็นเพียงรายละเอียดการดำเนินการ IsAuthenticatedและScopedRateThrottleเป็นการพึ่งพา; FooViewพวกเขาจะถูกฉีดเข้าไปใน มันไม่สำคัญว่าจะทำเมื่อไหร่หรืออย่างไร Python ไม่ใช่ Java ดังนั้นจึงมีวิธีการใช้งานที่แตกต่างกัน
Max Malysh

3
@ MaxMalysh ฉันเห็นด้วยกับ dopatraman ในอันนี้ นี่ไม่ใช่แม้แต่ IoC เนื่องจากคลาสเองมีการพึ่งพา "hardcoded" กับคลาสเฉพาะ ใน IoC การส่งผ่านการพึ่งพาจะถูกจัดเตรียมแทนการเข้ารหัส ยิ่งไปกว่านั้นในการพึ่งพาการฉีดคุณจะมีนิติบุคคลที่รับผิดชอบในการจัดการวงจรชีวิตของแต่ละบริการและฉีดพวกเขาเมื่อเป็นกรณี การแก้ปัญหาไม่ได้มีให้
Ricardo Alves

3
@alex ไม่คุณไม่จำเป็นต้องเปลี่ยนรหัสของคุณเพื่อใช้โหมดแสดงภาพอื่น renderer_classes = (JSONRenderer, BrowsableAPIRenderer, XMLRenderer)คุณยังสามารถใช้โหมดแสดงภาพหลายคนพร้อมกัน: @unittest.patch('myapp.views.FooView.permission_classes')เยาะเย้ยเป็นง่ายๆเป็น ความต้องการที่สิ้นหวังที่จะ "ส่งบางสิ่งบางอย่าง" เป็นผลมาจาก "วิธีการทำสิ่งต่าง ๆ ของ Java" เนื่องจาก Java เป็นภาษาที่รวบรวมและพิมพ์แบบสแตติก
Max Malysh

35

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

ความแตกต่างคืองูใหญ่มีประเภทชั้นหนึ่ง ชนิดข้อมูลรวมถึงคลาสเป็นวัตถุของตัวเอง หากคุณต้องการบางสิ่งบางอย่างในการใช้คลาสเฉพาะให้ตั้งชื่อคลาสนั้น ตัวอย่างเช่น:

if config_dbms_name == 'postgresql':
    import psycopg
    self.database_interface = psycopg
elif config_dbms_name == 'mysql':
    ...

รหัสหลังจากนั้นสามารถสร้างส่วนต่อประสานฐานข้อมูลโดยการเขียน:

my_db_connection = self.database_interface()
# Do stuff with database.

แทนที่จะเป็นฟังก์ชั่นจากโรงงานสำเร็จรูปที่ Java และ C ++ ต้องการ Python ใช้รหัสธรรมดาหนึ่งหรือสองบรรทัด นี่คือจุดแข็งของการทำงานกับการเขียนโปรแกรมที่จำเป็น


4
สิ่งที่คุณเรียกรหัสเป็นจริงส่วนสายไฟ นั่นจะเป็น XML ของกรอบงาน ioc ของคุณ import psycopg2 as database_interfaceมันจริงสามารถเขียนเป็นเพียง ใส่บรรทัดนั้นในinjections.pyet voilà
สเปกตรัม

29
เอ่อ สิ่งที่คุณกำลังทำอยู่คือแดเนียลตำราเรียนที่จำเป็นมาก
เชน

มันเป็นรหัสที่จำเป็นอย่างแน่นอน แต่มันเป็นฟังก์ชั่นที่ใช้งานได้เพราะมันใช้ค่าที่เรียกได้ว่าเป็นค่า
Jeremy

5
ไม่ใช่แค่ฟังก์ชั่นชั้นหนึ่งใช่มั้ย en.wikipedia.org/wiki/First-class_functionเพียงเพราะคุณมีและใช้มันไม่ได้ทำให้โค้ดของคุณใช้งานได้ มีผลข้างเคียงค่อนข้างน้อยที่เกิดขึ้นที่นี่ (เช่นการเปลี่ยนแปลงself.database_interface) ซึ่งกรีดร้องจำเป็น
hjc1710

15

มันเห็นว่าผู้คนไม่ได้รับสิ่งที่พึ่งพาการฉีดและการผกผันของการควบคุมหมายถึงอีกต่อไป

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

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

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


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

@zakmck: ส่วน "ขั้นตอน" ของ Python ที่นี่ไม่ได้เกี่ยวกับการเขียนรหัสขั้นตอน สิ่งที่ทำให้ส่วน "โพรซีเดอร์" ของ Python แตกต่างจากภาษาสแตติกคือความสามารถในการใส่โค้ดโพรซีเดอร์ในคลาสเนื้อหาซึ่งทำงานในช่วงเวลาของคำจำกัดความของคลาสและใส่คำสั่งการนำเข้าภายใน if-statement และสร้างคลาสโรงงาน ภายในวิธีโรงงาน สิ่งเหล่านี้เป็นสิ่งที่คุณไม่สามารถทำได้ในภาษาแบบสแตติกและแก้ปัญหาส่วนใหญ่ที่ IOC / DI พยายามแก้ไข Metaprogramming ใน Python มักจะดูเหมือนรหัส Python ปกติ
Lie Ryan

@LieRyan คุณสามารถทำสิ่งนั้นได้ด้วยการไตร่ตรองหรือถ้าคุณต้องการมันบ่อยๆหรือที่ runtime คุณสามารถเรียกภาษาคงที่จากภาษาอื่นเช่น Groovy (ซึ่งออกแบบมาเพื่อเล่นกับ Java) หรือแม้แต่ Python เอง แต่นั่นก็มีส่วนเกี่ยวข้องกับกรอบ IoC / DI เพียงเล็กน้อยเพื่อจุดประสงค์ของพวกเขาคือทำการเดินสายวัตถุส่วนใหญ่สำหรับคุณโดยอัตโนมัติโดยใช้ประโยชน์จากคำจำกัดความเท่านั้น น่าเศร้าที่คำตอบส่วนใหญ่ในที่นี้พลาดจุดนี้
zakmck

12

ไม่ได้ใช้ Python มาหลายปีแล้ว แต่ฉันจะบอกว่ามันเกี่ยวข้องกับการเป็นภาษาที่พิมพ์แบบไดนามิกมากกว่าสิ่งอื่นใด ตัวอย่างง่ายๆใน Java ถ้าฉันต้องการทดสอบว่าสิ่งที่เขียนถึงมาตรฐานอย่างเหมาะสมฉันสามารถใช้ DI และส่งผ่านใน PrintStream ใด ๆ เพื่อจับภาพข้อความที่เขียนและตรวจสอบ เมื่อฉันทำงานใน Ruby แต่ฉันสามารถแทนที่วิธี 'puts' บน STDOUT แบบไดนามิกเพื่อทำการตรวจสอบได้โดยปล่อย DI ออกจากภาพโดยสมบูรณ์ หากเหตุผลเดียวที่ฉันสร้างนามธรรมคือการทดสอบคลาสที่ใช้ (คิดว่าการทำงานของระบบไฟล์หรือนาฬิกาใน Java) ดังนั้น DI / IoC จะสร้างความซับซ้อนที่ไม่จำเป็นในการแก้ปัญหา


3
ไม่เคยทำให้ฉันประหลาดใจเลยว่าผู้คนยินดีที่จะเปลี่ยนวิธีการทำงานของระบบเพื่อทดสอบว่ามันทำงานอย่างไร ตอนนี้คุณต้องทดสอบว่าการทดสอบของคุณไม่ทำให้เกิดผลข้างเคียง
พื้นฐาน

2
เขาพูดเกี่ยวกับการเปลี่ยนแปลงทำให้วิธีการเฉพาะในขอบเขตการทดสอบก็เหมือนวิธีการเยาะเย้ยของวัตถุที่ฉีด
dpa

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

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

10

ที่จริงแล้วมันค่อนข้างง่ายที่จะเขียนโค้ดที่สะอาดและมีขนาดกะทัดรัดด้วย DI (ฉันสงสัยว่ามันจะเป็นแบบpythonic หรือเปล่าแต่อย่างไรก็ตาม :)) ตัวอย่างเช่นฉันเขียนรหัสด้วยวิธีนี้:

def polite(name_str):
    return "dear " + name_str

def rude(name_str):
    return name_str + ", you, moron"

def greet(name_str, call=polite):
    print "Hello, " + call(name_str) + "!"

_

>>greet("Peter")
Hello, dear Peter!
>>greet("Jack", rude)
Hello, Jack, you, moron!

ใช่สิ่งนี้สามารถดูได้ในรูปแบบง่ายๆของฟังก์ชั่นการกำหนดพารามิเตอร์ / คลาส แต่ทำงานได้ ดังนั้นบางทีแบตเตอรี่ที่รวมของ Python ก็เพียงพอแล้วเช่นกัน

ป.ล. ผมได้โพสต์ยังเป็นตัวอย่างที่มีขนาดใหญ่ของวิธีการที่ไร้เดียงสานี้ในแบบไดนามิกประเมินตรรกะบูลีนที่เรียบง่ายในหลาม


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

1
@ tux21b เอ่อมี "ความซับซ้อนที่สำคัญ" ที่ผู้ใช้ต้องการให้แอพพลิเคชั่นมีโซลูชั่นสถาปัตยกรรม (บางอันไม่ได้เลวร้ายไปกว่าส่วนที่เหลือของพวกเขาในแง่ของการพัฒนาและเวลาในการบำรุงรักษาความเร็วในการทำงาน ฯลฯ ) ) และมีความสามารถของมนุษย์ในการทำความเข้าใจ API และสถาปัตยกรรมซอฟต์แวร์ หากไม่มีวิธีแก้ปัญหาที่มนุษย์เข้าใจได้ (ไม่ใช่แค่ในรูปแบบใด ๆ ของ DI) ... ดีใครบอกว่าปัญหาทั้งหมดนั้นแก้ไขได้? และการมีพารามิเตอร์ที่กำหนดค่าเริ่มต้นจำนวนมาก (แต่สามารถเลือกเปลี่ยนได้โดยผู้ใช้) อาจพอเพียงบ่อยครั้ง
mlvljr

9

IoC / DI เป็นแนวคิดการออกแบบ แต่น่าเสียดายที่มันมักจะนำมาเป็นแนวคิดที่ใช้กับบางภาษา (หรือระบบการพิมพ์) ฉันชอบที่จะเห็นภาชนะฉีดขึ้นต่อเนื่องเป็นที่นิยมมากใน Python มีฤดูใบไม้ผลิ แต่นั่นเป็นโครงสร้างที่ยอดเยี่ยมและดูเหมือนจะเป็นพอร์ตโดยตรงของแนวคิดของ Java โดยไม่คำนึงถึง "The Python Way" มากนัก

ป.ร. ให้คำอธิบายประกอบในหลาม 3 ผมตัดสินใจที่จะมีรอยแตกที่เต็มรูปแบบที่โดดเด่น แต่ง่ายภาชนะฉีดพึ่งพา: https://github.com/zsims/dic มันขึ้นอยู่กับแนวคิดบางอย่างจาก. NET container injection (ซึ่ง IMO นั้นยอดเยี่ยมถ้าคุณเคยเล่นในพื้นที่นั้น) แต่กลายพันธุ์ด้วยแนวคิด Python


6

ฉันคิดว่าเนื่องจากลักษณะแบบไดนามิกของคนงูใหญ่มักไม่เห็นความต้องการกรอบการทำงานแบบไดนามิกอื่น เมื่อคลาสสืบทอดจาก 'object' สไตล์ใหม่คุณสามารถสร้างตัวแปรใหม่แบบไดนามิก ( https://wiki.python.org/moin/NewClassVsClassicClass )

ie ในหลามธรรมดา:

#application.py
class Application(object):
    def __init__(self):
        pass

#main.py
Application.postgres_connection = PostgresConnection()

#other.py
postgres_connection = Application.postgres_connection
db_data = postgres_connection.fetchone()

อย่างไรก็ตามดูที่https://github.com/noodleflake/pyiocนี่อาจเป็นสิ่งที่คุณกำลังมองหา

เช่นใน pyioc

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

#other.py
postgres_connection = ServiceLocator.resolve(PostgresConnection)
db_data = postgres_connection.fetchone()

2
ข้อเท็จจริงทั้งสองเวอร์ชันใช้โค้ดในปริมาณเท่ากันจะอธิบายได้ว่าทำไมการใช้เฟรมเวิร์กจึงไม่เป็นที่นิยม
สเปกตรัม

ในother.pyบรรทัดที่ 1 มีการแก้ปัญหาการพึ่งพาอัตโนมัติ แต่จะไม่นับว่าเป็นการฉีดการพึ่งพา
andho

ตัวระบุตำแหน่งบริการมักเป็นรูปแบบต่อต้านเพียงแค่พูด
PmanAce

6

ฉันกลับคำตอบ "Jörg W Mittag": "การใช้งาน Python ของ DI / IoC นั้นมีน้ำหนักเบาจนหายไปอย่างสมบูรณ์"

หากต้องการสำรองข้อความนี้ลองดูตัวอย่างที่มีชื่อเสียงของ Martin Fowler ซึ่งย้ายจาก Java ไปเป็น Python: Python: Design_Patterns: Inversion_of_Control

ดังที่คุณเห็นจากลิงก์ด้านบน "คอนเทนเนอร์" ใน Python สามารถเขียนได้ในรหัส 8 บรรทัด:

class Container:
    def __init__(self, system_data):
        for component_name, component_class, component_args in system_data:
            if type(component_class) == types.ClassType:
                args = [self.__dict__[arg] for arg in component_args]
                self.__dict__[component_name] = component_class(*args)
            else:
                self.__dict__[component_name] = component_class

42
สิ่งนี้อยู่ไกลจากภาชนะ DI ที่อ่อนแอที่สุด การจัดการอายุการใช้งานการแก้ปัญหาการอ้างอิงซ้ำความสามารถในการจำลองหรือ - การกำหนดค่าทั้งหมดนั้นล้มเหลว นี่ไม่ใช่อะไรมากไปกว่าการค้นหาประเภทและแคชที่ไม่เหมือนกับ IoC
พื้นฐาน

2
หลายปีก่อนฉันเขียนกรอบ DI ขนาดเล็กที่ใช้ metaclasses เป็นแบบฝึกหัด สิ่งทั้งหมดเป็นไฟล์เดียวที่มีการนำเข้าและการสอนเป็นศูนย์ซึ่งทำให้สามารถอธิบายตนเองได้ มันแสดงให้เห็นว่าคุณสมบัติพื้นฐานนั้นไม่ยากที่จะนำไปใช้ในลักษณะที่เป็น "pythonic" แต่ฉันคิดอย่างจริงใจว่ามันน่าเศร้าที่ไม่มีวิธีแก้ปัญหาที่สมบูรณ์ได้รับแรงฉุดใหญ่เช่นสปริงใน Java และทุกคนกำลังทำสถาปัตยกรรมปลั๊กอินแบบกำหนดเอง
Andrea Ratto

2

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

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

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

ที่กล่าวว่ามีสถานการณ์ Python ที่แนวทาง IoC มีประโยชน์จริง ๆ และที่จริงฉันอ่านที่ Django ใช้มัน

เหตุผลเดียวกันข้างต้นสามารถนำไปใช้กับการเขียนโปรแกรม Aspect Oriented ในโลก Java ด้วยความแตกต่างที่จำนวนกรณีที่ AOP คุ้มค่าจริง ๆ มี จำกัด มากขึ้น


มี URL อ้างอิงไปยังแหล่งข้อมูลที่ django ใช้ IoC หรือไม่
Sajuuk

@Sajuuk ฉันได้เรียนรู้เกี่ยวกับ Django ในหัวข้อคำถามนี้ดังนั้นฉันไม่รู้คุณควรถามผู้เขียนคนอื่น ๆ
zakmck

คำตอบแรกของคำตอบนี้จะเพิ่มมูลค่า 0 ในความคิดของฉัน ... ฉันคิดว่าฉันสามารถตัดสินใจได้ว่ารหัสไพ ธ อนของฉันจะได้รับประโยชน์จาก IoC อย่างไรและฉันไม่สนใจว่านักพัฒนาคิดอย่างไรกับสิ่งที่ไม่ดี ฉันให้ความสำคัญกับการปฏิบัติมากกว่าความคิดเห็นที่ไม่ได้ตั้งใจ
Mike de Klerk

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

The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.- ค่อนข้างเป็นข้อสันนิษฐาน
hyankov


-1

ฉันเห็นด้วยกับ @Jorg ในจุดที่ DI / IoC เป็นไปได้ง่ายขึ้นและสวยงามยิ่งขึ้นใน Python สิ่งที่ขาดหายไปคือเฟรมเวิร์กที่สนับสนุน แต่มีข้อยกเว้นเล็กน้อย วิธีชี้ตัวอย่างสองสามอย่างที่อยู่ในใจของฉัน:

  • ความคิดเห็น Django ช่วยให้คุณสามารถโยงคลาสความคิดเห็นของคุณเองด้วยตรรกะและรูปแบบที่กำหนดเองของคุณ [ข้อมูลเพิ่มเติม]

  • Django ให้คุณใช้วัตถุโปรไฟล์แบบกำหนดเองเพื่อแนบกับโมเดลผู้ใช้ของคุณ นี่ไม่ใช่ IoC ที่สมบูรณ์ แต่เป็นวิธีการที่ดี โดยส่วนตัวแล้วฉันต้องการแทนที่โมเดลหลุมของผู้ใช้ตามกรอบความคิดเห็น [ข้อมูลเพิ่มเติม]


-3

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

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

โดยทั่วไปแล้วฉันคิดว่าคน Python คุ้นเคยกับการเลือกเครื่องมือที่เหมาะสมสำหรับงานซึ่งเป็นสิ่งที่สอดคล้องกันและเรียบง่ายมากกว่า One True Tool (ด้วย A Thousand Possible Plugins) ที่สามารถทำสิ่งใดก็ได้ . ยังคงมีชิ้นส่วนที่ใช้แทนกันได้ตามความจำเป็น แต่ไม่จำเป็นต้องมีพิธีการใหญ่ในการกำหนดอินเทอร์เฟซคงที่เนื่องจากความยืดหยุ่นของการพิมพ์เป็ดและความเรียบง่ายของภาษา


4
มันไม่ได้เป็นกรอบเท่าที่ภาษาเอง เพื่อสร้างความยืดหยุ่นที่ภาษาที่ใช้พิมพ์แบบเป็ด ๆ ภาษาที่พิมพ์แบบคงที่จำเป็นต้องมีกรอบและกฎที่ซับซ้อนมาก DI เป็นหนึ่งในกฎเหล่านั้น งูหลามคนไม่คิดสองครั้ง คน Java ต้องทำงานจริง ๆ
S.Lott

6
@ S.Lott - ฉันเห็นด้วยกับคุณโดยสิ้นเชิงยกเว้นคน C ++ ที่ดูเหมือนจะผ่านพ้นไปโดยไม่มีการระเบิดของการออกแบบและรูปแบบสถาปัตยกรรมแม้จะทำงานกับข้อ จำกัด ที่คล้ายกันกับ Java ผมคิดว่าหมายถึงความแตกต่างทางวัฒนธรรมที่เมื่อถูกต้องเผชิญกับ 2 วิธีที่เป็นไปได้ที่จะทำบางสิ่งบางอย่างคน Java ต้องการที่จะดึงอินเตอร์เฟซที่อื่นเพื่ออำนวยความสะดวกรูปแบบกลยุทธ์ในขณะที่ C ++ คนจุ่มขวาในและเพิ่มบูลและถ้างบ ...
Kylotan

3
@Finglas ดังนั้นถ้าฉันมีคลาสทั้งหมดที่ใช้ของฉันEmailSenderและตัดสินใจที่จะแทนที่ด้วย a DesktopNotifierฉันต้องไปและแก้ไข 12 คลาสด้วยมือ และคุณคิดว่ามันง่ายและสะอาดกว่าที่เพิ่งเขียนไปยังINotifierอินเทอร์เฟซเพื่อให้รายละเอียดของคอนเทนเนอร์เป็นไปได้หรือไม่
พื้นฐาน

1
น่าเสียดายที่ความซับซ้อนในระดับหนึ่งคือความจริงที่ผู้พัฒนาซอฟต์แวร์มืออาชีพต้องเผชิญ ฉันเห็นคำวิจารณ์ แต่ไม่มีคำตอบในคำตอบนี้ อะไรคือวิธีการแก้ปัญหา "pythonic" สำหรับปัญหานี้: ฉันกำลังเขียนห้องสมุดและฉันต้องการที่จะให้เบ็ดสำหรับการเข้าสู่ระบบ (บางอย่างเช่น PSR-3 LoggerInterface ของ PHP) ฉันรู้วิธีใช้ระดับการบันทึก แต่ฉันไม่สนใจว่าโปรแกรมจะรายงานระดับนั้นอย่างไร วิธีที่สะอาดในการอนุญาตให้แอปไคลเอนต์เป็นอย่างไรฉีดรายละเอียดการใช้งานนั้น หมายเหตุ: ส่วนอื่น ๆ ของแอปพลิเคชันอาจมีการใช้งานที่แตกต่างกันของอินเตอร์เฟซนี้
Rob

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

-5

ไม่เหมือนธรรมชาติที่แข็งแกร่งใน Java พฤติกรรมการพิมพ์เป็ดของงูใหญ่ทำให้ง่ายต่อการส่งผ่านวัตถุไปรอบ ๆ

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

นักพัฒนา Python มุ่งเน้นไปที่การทำให้งานสำเร็จ พวกเขาเพียงวางสายชั้นเมื่อพวกเขาต้องการ พวกเขาไม่ต้องกังวลเกี่ยวกับประเภทของชั้นเรียน ตราบใดที่มันสามารถต้มตุ๋นมันเป็นเป็ด! ลักษณะนี้ทำให้ไม่มีที่ว่างสำหรับ IoC


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