programing

Python의 함수 체인

yellowcard 2023. 5. 15. 21:26
반응형

Python의 함수 체인

Codewars.com 에서 다음 작업을 수행했습니다.

생성하기add연속적으로 호출될 때 숫자를 함께 추가합니다.그렇게add(1)해야 합니다.1,add(1)(2)해야 합니다.1+2, ...

파이썬의 기본은 익히 알고 있지만, 이렇게 연속적으로 호출할 수 있는 함수, 즉 함수를 접해본 적이 없습니다.f(x)은 고라할 할 수 .f(x)(y)(z)...지금까지, 저는 이 표기법을 어떻게 해석해야 할지조차 잘 모르겠습니다.

수학자로서, 저는 의심합니다.f(x)(y)는 모든 에하는함다에 입니다.x 수함g_{x} 리고돌아니다옵그다니▁and옵▁then돌을 반환합니다.g_{x}(y)로 리고마찬로지가그로▁for.f(x)(y)(z).

만약 이 해석이 맞다면, 파이썬은 제가 매우 흥미롭게 보이는 기능들을 동적으로 만들 수 있게 해줄 것입니다.저는 지난 한 시간 동안 웹을 검색했지만 올바른 방향으로 단서를 찾지 못했습니다.하지만 이 프로그래밍 개념이 어떻게 불리는지 모르기 때문에, 이것은 그리 놀라운 일이 아닐 수도 있습니다.

이 개념을 어떻게 부르고 어디서 더 자세히 읽을 수 있습니까?

이것이 호출 가능한 체인만큼 함수 체인인지는 모르겠지만, 함수는 호출 가능하기 때문에 해를 끼치지 않을 것 같습니다.어느 쪽이든, 제가 생각할 수 있는 두 가지 방법이 있습니다.

위류분int그리고 정의합니다.__call__:

첫 번째 방법은 관습을 따르는 것입니다.int업데이트된 값으로 자신의 새 인스턴스를 반환하는 하위 클래스:

class CustomInt(int):
    def __call__(self, v):
        return CustomInt(self + v)

기.add 이를반도정수있의다니습할을 할 수 .CustomInt인스턴스는 자체의 업데이트된 값을 반환하는 호출 가능으로 연속적으로 호출될 수 있습니다.

>>> def add(v):
...    return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44)  # and so on..
50

게가로 으서, 로다.int은 하클래스, 반된값다유지다니합을을 유지합니다.__repr__그리고.__str__int그러나 보다 복잡한 작업의 경우 다른 실수를 적절하게 정의해야 합니다.

@Caridorc가 논평에서 언급했듯이,add간단히 다음과 같이 쓸 수도 있습니다.

add = CustomInt 

을 " 스이다변경로음으을름클래addCustomInt또한 유사하게 작동합니다.


마감을 정의합니다. 가치를 창출하기 위해 추가 통화가 필요합니다.

제가 생각할 수 있는 유일한 방법은 결과를 반환하기 위해 빈 인수 호출이 추가로 필요한 중첩 함수입니다.사용하지 않습니다.nonlocal그리고 Pythons 간에 이동할 수 있도록 함수 객체에 속성을 연결하는 것을 선택합니다.

def add(v):
    def _inner_adder(val=None):  
        """ 
        if val is None we return _inner_adder.v 
        else we increment and return ourselves
        """
        if val is None:    
            return _inner_adder.v
        _inner_adder.v += val
        return _inner_adder
    _inner_adder.v = v  # save value
    return _inner_adder 

반환합니다._inner_adder) 만약 그렇다면,val급공, 증가)_inner_adder += val및 않은 반환합니다 및 그렇지 않은 경우 값을 그대로 반환합니다.제가 말씀드린 것처럼, 그것은 추가적으로 필요합니다.()증분 값을 반환하려면 다음을 호출합니다.

>>> add(1)(2)()
3
>>> add(1)(2)(3)()  # and so on..
6

당신은 나를 미워할 수 있지만, 여기 원라이너가 있습니다 :)

add = lambda v: type("", (int,), {"__call__": lambda self, v: self.__class__(self + v)})(v)

편집: 자, 어떻게 작동합니까?코드는 @Jim의 답변과 동일하지만, 모든 것은 한 줄에서 발생합니다.

  1. type유형을 하는 데 할 수 .type(name, bases, dict) -> a new type.위해서name이 경우 이름이 필요하지 않으므로 빈 문자열을 제공합니다.위해서bases우리는 제공합니다.(int,) 것과 .int.dict으로, 우스는여첨부기다니합에며를 .__call__람다의
  2. self.__class__(self + v)는 와동합다니와 동일합니다.return CustomInt(self + v)
  3. 새 유형이 생성되어 외부 람다 내에서 반환됩니다.

번 하려면 먼저 함수를 매번 . 그렇지 를▁a▁if▁by▁▁object▁your▁own▁each▁you▁to매)다합▁otherwise▁function▁have▁create니▁a▁to)를 정의하여 자신의 개체를 만들어야 합니다. 그렇지 않으면 다음을 정의하여 자체 개체를 생성해야 합니다.__call__호출 가능한 속성입니다.

다음은 모든 인수를 보존해야 한다는 것입니다. 이 경우 코루틴 또는 재귀 함수를 사용할 수 있습니다.그러나 코루틴은 특히 이러한 작업에 대해 재귀 함수보다 훨씬 더 최적화/유연합니다.

다음은 최신 상태를 보존하는 코루틴을 사용한 샘플 함수입니다.반환 값이 다음과 같으므로 여러 번 호출할 수 없습니다.integer호출할 수는 없지만, 이것을 예상 개체로 바꾸는 것을 생각할 수 있습니다 ;-).).

def add():
    current = yield
    while True:
        value = yield current
        current = value + current


it = add()
next(it)
print(it.send(10))
print(it.send(2))
print(it.send(4))

10
12
16

단순:

class add(int):
   def __call__(self, n):
      return add(self + n)

이 추가로 할 의사가 ,()결과를 검색하기 위해 사용할 수 있습니다.

from functools import partial

def add(*args, result=0):
    return partial(add, result=sum(args)+result) if args else result

예:

>>> add(1)
functools.partial(<function add at 0x7ffbcf3ff430>, result=1)
>>> add(1)(2)
functools.partial(<function add at 0x7ffbcf3ff430>, result=3)
>>> add(1)(2)()
3

이를 통해 한 번에 여러 개의 숫자를 지정할 수도 마찬가지입니다.

>>> add(1, 2, 3)(4, 5)(6)()
21

단일 숫자로 제한하려는 경우 다음을 수행할 수:

def add(x=None, *, result=0):
    return partial(add, result=x+result) if x is not None else result

네가 원한다면add(x)(y)(z)결과를 즉시 반환하고 하위 분류보다 추가로 호출할 수 있습니다.int가는 길입니다.

이를 위한 파이썬적 방법은 동적 인수를 사용하는 것입니다.

def add(*args):
    return sum(args)

이것은 여러분이 찾고 있는 답이 아닙니다. 여러분도 아실지도 모르지만, 저는 어쨌든 누군가가 호기심 때문이 아니라 일을 위해 이것을 하는 것에 대해 궁금해한다면 그것을 줄 것이라고 생각했습니다.그들은 아마도 "올바른 일"이라는 답을 가져야 할 것입니다.

언급URL : https://stackoverflow.com/questions/39038358/function-chaining-in-python

반응형