programing

Python에서 IoC/DI가 일반적이지 않은 이유는 무엇입니까?

copysource 2022. 10. 1. 15:10
반응형

Python에서 IoC/DI가 일반적이지 않은 이유는 무엇입니까?

Java IoC/DI는 웹 애플리케이션, 사용 가능한 거의 모든 프레임워크 및 Java EE에서 광범위하게 사용되는 매우 일반적인 방법입니다.한편, Python Web 어플리케이션도 많이 있습니다만, Zope 이외에는 IoC가 Python 세계에서는 그다지 흔하지 않은 것 같습니다(제가 틀렸다고 생각되면 예를 들어주세요).

물론 Python에서는 springpython과 같은 인기 Java IoC 프레임워크의 클론이 몇 개 있습니다.하지만 그 중 어느 것도 실제로 이용되지 않는 것 같다.적어도 나는 장고나 sqalchemy+를 밟은 적이 없다.<insert your favorite wsgi toolkit here>그런 걸 사용하는 웹 어플리케이션을 기반으로 합니다.

예를 들어 IoC는 django-default-user-model을 대체하기 쉽다고 생각합니다만, Python에서의 인터페이스 클래스나 IoC의 광범위한 사용은, 「피토닉」이 아니고, 조금 이상하다고 생각됩니다.하지만 왜 IoC가 Python에서 널리 사용되지 않는지에 대한 더 나은 설명이 있을 것이다.

사실 Python에서는 DI/IoC가 그렇게 흔하지 않다고 생각합니다., DI/IoC 프레임워크/컨테이너는 흔치 않습니다.

생각해 보세요. DI 컨테이너의 역할은 무엇입니까?이 기능을 통해

  1. 독립된 컴포넌트를 배선하여 완전한 어플리케이션으로...
  2. ...실행시.

「함께 배선」과 「실행시에」의 이름이 있습니다.

  1. 스크립트 작성
  2. 역학

따라서 DI 컨테이너는 동적 스크립트 언어의 인터프리터에 불과합니다.다른 말로 하자면 전형적인 Java/입니다.NET DI 컨테이너는 매우 불량한 동적 스크립트 언어의 형편없는 인터프리터이며, 경우에 따라서는 XML 기반의 구문을 사용하는 경우도 있습니다.

Python으로 프로그램 할 때 아름답고 훌륭한 스크립트 언어가 있는데 왜 추하고 나쁜 스크립트 언어를 사용하려고 합니까?사실, 이것은 보다 일반적인 질문입니다.대부분의 언어로 프로그램 할 때 Jython과 IronPython을 마음대로 사용할 수 있는데 왜 추하고 나쁜 스크립트 언어를 사용하려고 합니까?

요약하자면 DI/IoC의 실행은 Java에서와 마찬가지로 Python에서도 중요합니다.같은 이유에서입니다.그러나, DI/IoC 의 실장은 언어에 짜넣어져 있어, 많은 경우, 매우 가벼워서, 완전하게 없어집니다.

(여기 유추할 수 있는 간단한 정보가 있습니다.어셈블리에서는 서브루틴 콜은 매우 중요한 거래입니다.로컬 변수와 레지스터를 메모리에 저장하고, 반환 주소를 어딘가에 저장하고, 호출하고 있는 서브루틴으로 명령 포인터를 변경하고, 그것이 종료되면 서브루틴으로 돌아가도록 조정해야 합니다.발신자가 찾을 수 있는 장소 등입니다.IOW: 어셈블리에서 "서브루틴 호출"은 설계 패턴이며, 서브루틴 호출을 내장한 Fortran과 같은 언어가 존재하기 전에는 사람들은 자신만의 "서브루틴 프레임워크"를 구축하고 있었습니다.서브루틴 프레임워크를 사용하지 않는다고 해서 Python에서 서브루틴 호출이 "비공통"이라고 생각하십니까?

BTW: DI를 논리적인 결론에 이르게 하는 방법의 예로서 Gilad Bracha의 Newspeak Programming Language와 그 주제에 관한 그의 글을 살펴보십시오.

IoC와 DI는 성숙한 Python 코드에서 매우 일반적입니다.duck 타이핑으로 인해 DI를 구현하기 위한 프레임워크가 필요하지 않습니다.

입니다.장고 어플리케이션은 장고 어플리케이션을 사용하는 것입니다.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

(출처)를 다시 한 번 알려드리겠습니다.

'의존성 주입'은 5센트 개념을 나타내는 25달러짜리 용어입니다.[...]의존성 주입은 개체에 인스턴스 변수를 제공하는 것을 의미합니다.[...]

일부는 Python에서 모듈 시스템이 작동하는 방식입니다.모듈에서 가져오는 것만으로, 일종의 「싱글톤」을 무료로 얻을 수 있습니다.모듈에서 객체의 실제 인스턴스를 정의하면 클라이언트 코드가 해당 인스턴스를 Import할 수 있으며 실제로 동작하고 완전히 구성되거나 채워진 객체를 가져옵니다.

이는 개체의 실제 인스턴스를 가져오지 않는 Java와 대조적입니다.즉, 항상 직접 인스턴스화하거나 IOC/DI 스타일의 접근 방식을 사용해야 합니다.정적 팩토리 방식(또는 실제 팩토리 클래스)을 사용하면 모든 것을 직접 인스턴스화해야 하는 번거로움을 줄일 수 있지만, 그때마다 실제로 새로운 팩토리 방식을 작성해야 하는 리소스 오버헤드가 발생합니다.

장고는 통제의 반전을 잘 이용한다.예를 들어 구성 파일에서 데이터베이스 서버를 선택한 후 프레임워크는 데이터베이스 클라이언트에 적절한 데이터베이스 래퍼 인스턴스를 제공합니다.

차이점은 Python은 퍼스트 클래스 타입을 가지고 있다는 것입니다.클래스를 포함한 데이터 유형 자체가 개체입니다.특정 클래스를 사용하려면 클래스의 이름을 지정하기만 하면 됩니다.예를 들어 다음과 같습니다.

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은 한두 줄의 일반 코드를 사용합니다.이것이 기능적 프로그래밍과 필수적 프로그래밍의 강점입니다.

사람들은 의존성 주입과 통제의 반전이 의미하는 바를 더 이상 이해하지 못하는 것 같습니다.

제어의 역전을 사용하는 방법은 다른 클래스나 함수에 의존하는 클래스 또는 함수를 갖는 것이지만 클래스 또는 함수 코드에 인스턴스를 만드는 대신 이러한 인스턴스를 매개 변수로 수신하는 것이 더 낫기 때문에 느슨한 결합을 달성할 수 있습니다.그것은 더 많은 테스트 가능성과 리스코프 대체 원칙을 달성할 수 있는 많은 이점을 가지고 있다.

인터페이스와 주입을 사용하면 동작을 쉽게 변경할 수 있기 때문에 코드의 유지보수가 용이해집니다.클래스가 대기하고 있는 인터페이스를 실장하는 클래스는 다양하기 때문에 동작을 변경하기 위해 코드의 한 줄(DI 설정상의 한두 줄)을 다시 쓸 필요가 없기 때문입니다.독립적으로 액세스 할 수 있습니다.코드를 분리하여 유지보수가 용이한 상태로 유지하는 가장 좋은 전략 중 하나는 적어도 하나의 책임, 대체 및 의존성 반전 원칙을 따르는 것입니다.

패키지 내에서 객체를 인스턴스화하고 Import하여 직접 주입할 수 있는 경우 DI 라이브러리는 어떤 용도로 유용합니까?java에는 절차 섹션(클래스 외 코드)이 없기 때문에 지루한 구성 xml에 들어가는 모든 것이 있기 때문에 느린 부하 패션에 의존을 인스턴스화하고 주입할 필요가 있습니다.그 때문에, python에서는, 「프로시저」(code outside code)로 주입을 코드화할 뿐입니다.lases) 섹션이 표시됩니다.

Python은 몇 년 동안 사용하지 않았지만, 저는 Python이 역동적으로 입력된 언어라는 것이 무엇보다 중요하다고 생각합니다.예를 들어 Java에서 어떤 것이 적절하게 표준이 되도록 쓰였는지를 테스트하고 싶다면 DI를 사용하여 PrintStream을 통해 쓰이고 있는 텍스트를 캡처하여 확인할 수 있습니다.다만, Ruby 로 작업하고 있는 경우는, STDOUT 의 「puts」메서드를 동적으로 대체해 검증할 수 있기 때문에, DI 는 그림에서 완전히 제외됩니다.추상화를 작성하는 유일한 이유가 그 추상화를 사용하는 클래스를 테스트하기 위해서라면(파일 시스템 조작이나 Java의 클럭이라고 생각) DI/IoC는 솔루션에 불필요한 복잡성을 일으킵니다.

실제로 DI로 충분히 깨끗하고 콤팩트한 코드를 쓰는 것은 매우 간단합니다(그때는 피토닉이 될까요?) 예를 들어, 저는 실제로 다음과 같은 코딩 방법을 참조합니다.

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의 기본 내장 배터리로도 충분합니다.

P.S. Python의 간단한 부울 로직 동적 평가에서 이 순진한 접근법의 더 큰 예를 게시했습니다.

IoC/DI는 설계 개념이지만 안타깝게도 특정 언어(또는 타이핑 시스템)에 적용되는 개념으로 받아들여지는 경우가 많습니다.Python에서 의존성 주입 컨테이너가 훨씬 더 인기 있는 것을 보고 싶습니다.Spring이 있지만, 그것은 슈퍼프레임워크이며, "The Python Way"에 대한 큰 고려 없이 Java 개념의 직접 포트인 것처럼 보인다.

Python 3의 Annotations에 따라 완전한 기능을 갖춘 간단한 의존성 주입 컨테이너(https://github.com/zsims/dic)에서 크랙을 만들기로 결정했습니다.의 개념에 기초하고 있습니다.NET 의존성 주입 컨테이너(IMO는 이 공간에서 플레이하는 경우 매우 훌륭합니다)는 Python 개념으로 변환됩니다.

Python의 동적 특성 때문에 사람들은 다른 동적 프레임워크의 필요성을 잘 느끼지 못한다고 생각합니다.클래스가 새로운 스타일의 '개체'에서 상속되면 동적으로 새 변수를 만들 수 있습니다(https://wiki.python.org/moin/NewClassVsClassicClass)).

즉, 일반 비단뱀의 경우:

#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을 참조해 주십시오.이것이 당신이 찾고 있는 것일지도 모릅니다.

즉, piioc에서

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

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

모두 DI(소스) 기반 pytest 고정 장치

나는 "Jörg W Mittag"의 답변을 지지한다: "DI/IoC의 Python 구현은 매우 가볍기 때문에 완전히 사라진다."

이 스테이트먼트를 백업하려면 Java에서 Python으로 포팅된 유명한 Martin Fowler의 예를 참조하십시오.Python:Design_Patterns:Inversion_of_Control

위 링크에서 볼 수 있듯이 Python의 "Container"는 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

FastAPI를 확인해 보십시오. 종속성 주입 기능이 내장되어 있습니다.예를 들어 다음과 같습니다.

from fastapi import Depends, FastAPI

async def get_db():
    db = DBSession()
    try:
        yield db
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()

app = FastAPI()

@app.get("/items")
def get_items(db=Depends(get_db)):
    return db.get_items()

나의 2가지 점은 대부분의 Python 어플리케이션에서는 그것이 필요하지 않다는 것이다.그리고 비록 그것이 필요하더라도 많은 Java 악플러들(그리고 개발자로 믿는 무능한 fiddler들)은 단지 Java에서 인기가 있다는 이유만으로 그것을 나쁜 것으로 간주할 가능성이 높다.

IoC 시스템은 복잡한 객체 네트워크가 있는 경우 실제로 유용합니다.각 객체는 다른 여러 객체에 대한 종속성이며, 그 자체도 다른 객체에 대한 종속성이 될 수 있습니다.이 경우 이러한 모든 개체를 한 번 정의하고 가능한 많은 암묵적 규칙에 따라 자동으로 결합하는 메커니즘을 갖출 수 있습니다.애플리케이션 유저/관리자에 의해서 간단하게 정의할 수 있는 구성도 있는 경우는, 심플한 XML 파일(구성등)로부터 컴포넌트를 읽어낼 수 있는 IOC 시스템을 필요로 하는 또 다른 이유가 됩니다.

일반적인 Python 애플리케이션은 이렇게 복잡한 아키텍처가 없는 단순한 스크립트 집합입니다.개인적으로 IoC가 실제로 무엇인지 알고 있으며(여기서 특정 답변을 작성한 사용자와는 대조적으로) 제한된 Python 경험에서 IoC의 필요성을 느낀 적이 없습니다(또한 스프링을 사용하는 장점이 개발 오버헤드를 정당화하지 못할 때도 아닙니다).

하지만 실제로 IoC 접근법이 유용한 Python 상황도 있고, 실제로 여기에서 Django가 IoC를 사용한다고 읽었습니다.

AOP가 실제로 가치가 있는 경우의 수가 훨씬 더 제한적이라는 차이와 함께 위의 같은 논리가 Java 세계의 Aspect Oriented Programming에도 적용될 수 있습니다.

Python을 사용하여 종속성 주입을 수동으로 수행할 수 있지만 수동 방식에는 다음과 같은 단점이 있습니다.

  • 배선할 수 있는 보일러 플레이트 코드가 많아Python의 동적 기능을 사용하여 주입할 수 있지만 IDE 지원(예: PyCharm의 Ctrl+Space)이 손실되어 코드를 이해하고 디버깅하기 어렵게 됩니다.
  • 표준 없음: 모든 프로그래머는 동일한 문제를 해결하기 위한 자신만의 방법을 가지고 있으며, 이로 인해 바퀴의 재창조, 서로의 코드를 이해하는 것이 곧 골칫거리가 될 수 있습니다.의존성 주입 라이브러리로 플러그인에 대한 간단한 프레임워크 제공

모든 것을 갖추기 위해서는 의존성 주입 프레임워크가 필요합니다.예를 들어 이 https://python-dependency-injector.ets-labs.org/index.html은 Python을 위한 가장 성숙한 DI 프레임워크인 것 같습니다.

더 작은 앱의 경우 DI 컨테이너가 필요하지 않으며, 코드가 수백 줄 이상인 경우 DI 컨테이너는 코드를 유지 보수하기 위해 반드시 필요합니다.

Python에서는 DI/IoC가 가능하고 쉽고 아름다운 점에서는 @Jorg에 동의합니다.이를 뒷받침하는 프레임워크가 부족하지만 몇 가지 예외가 있습니다.몇 가지 예를 들자면 다음과 같습니다.

  • Django 코멘트를 사용하면 커스텀 로직과 폼을 사용하여 자신의 코멘트 클래스를 배선할 수 있습니다.[상세정보]

  • Django를 사용하면 커스텀프로파일 오브젝트를 사용하여 사용자 모델에 부가할 수 있습니다.이것은 완전한 IOC는 아니지만 좋은 접근법입니다.개인적으로 코멘트 프레임워크와 같이 홀 사용자 모델을 교체하고 싶습니다.[상세정보]

IOC 컨테이너는 대부분 **kwargs를 사용하여 "모방"됩니다.

class A:
    def __init__(self, **kwargs):
        print(kwargs)

Class B:
    pass

Class C:
    pass

Ainstance = A(b=B, c=C)

내 생각에 의존성 주입 같은 것은 경직되고 지나치게 복잡한 프레임워크의 증상이다.코드의 본체가 너무 무거워 쉽게 변경할 수 없게 되면 코드의 작은 부분을 선택하고, 그 일부를 위한 인터페이스를 정의하고, 그 인터페이스에 접속하는 오브젝트를 통해 동작을 변경할 수 있게 됩니다.그것도 좋지만, 애초에 그런 복잡함은 피하는 것이 좋습니다.

정적으로 입력된 언어의 증상이기도 합니다.추상화를 표현해야 하는 유일한 도구가 상속일 경우, 그것은 거의 모든 곳에서 사용되는 것입니다.하지만 C++는 거의 비슷하지만 Java 개발자들이 그랬던 것처럼 빌더와 인터페이스에 매료된 적은 없다.너무 많은 범용 코드를 작성해도 실질적인 이점은 거의 없지만 유연하고 확장성이 뛰어나다는 꿈에 부풀어 오르기 쉽습니다.문화적인 문제인 것 같아요.

일반적으로 Python 사람들은 어떤 것이든 할 수 있지만 가능한 구성 배열의 혼란스러운 배열을 제공하는 One True Tool(With A Thousand Possible Plugins)이 아닌 일관성 있고 단순한 전체인 작업에 적합한 도구를 선택하는 데 익숙하다고 생각합니다.필요한 경우 교환 가능한 부분이 있지만, 덕 타이핑의 유연성과 언어의 비교적 단순성으로 인해 고정 인터페이스를 정의하는 큰 형식주의가 필요하지 않습니다.

Java의 강력한 유형 특성과는 다릅니다.Python의 오리 타이핑 동작은 물체를 쉽게 전달할 수 있게 합니다.

자바 개발자들은 클래스 스트럭처 구축과 오브젝트 간의 관계에 초점을 맞추면서 사물의 유연성을 유지하고 있다.IoC는 이를 실현하기 위해 매우 중요합니다.

Python 개발자들은 그 일을 완수하는데 집중하고 있다.그들은 필요할 때 전선을 쳐서 수업을 듣습니다.그들은 심지어 수업의 종류에 대해 걱정할 필요도 없다.꽥꽥거릴 수 있는 한 그건 오리야!이 특성으로 인해 IOC에 여유가 없습니다.

언급URL : https://stackoverflow.com/questions/2461702/why-is-ioc-di-not-common-in-python

반응형