programing tip

기능 A가 기능 B에만 필요한 경우 A를 B 내부에 정의해야합니까?

itbloger 2020. 6. 22. 08:03
반응형

기능 A가 기능 B에만 필요한 경우 A를 B 내부에 정의해야합니까?


간단한 예입니다. 하나는 다른 것에서 호출되는 두 가지 방법 :

def method_a(arg):
    some_data = method_b(arg)

def method_b(arg):
    return some_data

파이썬에서 우리는 def다른 것을 선언 할 수 있습니다 def. 따라서에 method_b필요하고 from 만 호출하는 경우 inside method_a선언해야 합니까? 이처럼 :method_bmethod_a

def method_a(arg):

    def method_b(arg):
        return some_data

    some_data = method_b

아니면 이것을 피해야합니까?


>>> def sum(x, y):
...     def do_it():
...             return x + y
...     return do_it
... 
>>> a = sum(1, 3)
>>> a
<function do_it at 0xb772b304>
>>> a()
4

이것이 당신이 찾고 있었던 것입니까? 이를 클로저 라고합니다 .


실제로 이렇게하면 많은 것을 얻지 못합니다. 실제로 method_a호출 될 때마다 다른 함수를 정의하고 다시 컴파일하기 때문에 속도가 느려집니다 . 따라서 함수 이름 앞에 밑줄을 붙여서 개인 메서드임을 나타내는 것이 _method_b좋습니다.

중첩 된 함수의 정의가 어떤 이유로 매번 바뀌면이 작업을 수행하려고하지만 디자인의 결함을 나타낼 있다고 가정합니다 . 즉이 말했다 이다 중첩 함수가 외부 함수에 전달하지만, 명시 적으로 예를 들어, 함수 장식을 작성할 때 종종 발생하는 그들에게 전달되지 않은 인수를 사용할 수 있도록이 작업을 수행 할 수있는 타당한 이유가. 데코레이터를 정의하거나 사용하지 않아도 허용되는 답변에 표시되는 내용입니다.

최신 정보:

이 사소한 경우는별로 인정하지 않지만 중첩하는 것이 느리다는 증거가 있습니다 (Python 3.6.1 사용).

setup = """
class Test(object):
    def separate(self, arg):
        some_data = self._method_b(arg)

    def _method_b(self, arg):
        return arg+1

    def nested(self, arg):

        def method_b2(self, arg):
            return arg+1

        some_data = method_b2(self, arg)

obj = Test()
"""
from timeit import Timer
print(min(Timer(stmt='obj.separate(42)', setup=setup).repeat()))  # -> 0.24479823284461724
print(min(Timer(stmt='obj.nested(42)', setup=setup).repeat()))    # -> 0.26553459700452575

참고 나는 self실제 함수와 비슷하게 만들기 위해 샘플 함수 에 몇 가지 인수를 추가했습니다 ( method_b2아직 기술적으로 Test클래스 의 메소드는 아니지만 ). 또한 중첩 함수는 실제로는 해당 버전에서 호출되지 않습니다.


함수 내부의 함수는 일반적으로 클로저에 사용됩니다 .

( 클로저를 정확하게 클로저로 만드는 것에 대한 많은 논쟁있습니다.)

다음은 내장을 사용하는 예입니다 sum(). start한 번 정의 하고 그때부터 사용합니다.

def sum_partial(start):
    def sum_start(iterable):
        return sum(iterable, start)
    return sum_start

사용:

>>> sum_with_1 = sum_partial(1)
>>> sum_with_3 = sum_partial(3)
>>> 
>>> sum_with_1
<function sum_start at 0x7f3726e70b90>
>>> sum_with_3
<function sum_start at 0x7f3726e70c08>
>>> sum_with_1((1,2,3))
7
>>> sum_with_3((1,2,3))
9

내장 파이썬 폐쇄

functools.partial 폐쇄의 예입니다.

python docs 에서 대략 다음과 같습니다.

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

(아래 답변을 보려면 @ user225312에게 문의하십시오.이 예제를 이해하기가 더 쉬우 며 @mango의 의견에 답변하는 데 도움이 되길 바랍니다.)


일반적으로 아니요, 함수 내부에 함수를 정의하지 마십시오.

당신이 정말로 좋은 이유가 없다면 당신은하지 않습니다.

왜 안돼?

함수 내에서 함수를 정의해야하는 가장 좋은 이유 무엇입니까 ?

당신이 실제로 원하는 것은 딩당 폐쇄 입니다.


실제로 하나의 함수를 다른 함수 안에 선언하는 것이 좋습니다. 데코레이터를 만드는 데 특히 유용합니다.

그러나 일반적으로 함수가 복잡한 경우 (10 줄 이상) 모듈 수준에서 선언하는 것이 좋습니다.


중첩 된 함수를 사용하는 경우 성능에 미치는 영향에 대한 질문을하고 싶기 때문에이 질문을 찾았습니다. 쿼드 코어 2.5GHz Intel i5-2530M 프로세서가 장착 된 Windows 노트북에서 Python 3.2.5를 사용하여 다음 기능에 대한 테스트를 실행했습니다.

def square0(x):
    return x*x

def square1(x):
    def dummy(y):
        return y*y
    return x*x

def square2(x):
    def dummy1(y):
        return y*y
    def dummy2(y):
        return y*y
    return x*x

def square5(x):
    def dummy1(y):
        return y*y
    def dummy2(y):
        return y*y
    def dummy3(y):
        return y*y
    def dummy4(y):
        return y*y
    def dummy5(y):
        return y*y
    return x*x

I measured the following 20 times, also for square1, square2, and square5:

s=0
for i in range(10**6):
    s+=square0(i)

and got the following results

>>> 
m = mean, s = standard deviation, m0 = mean of first testcase
[m-3s,m+3s] is a 0.997 confidence interval if normal distributed

square? m     s       m/m0  [m-3s ,m+3s ]
square0 0.387 0.01515 1.000 [0.342,0.433]
square1 0.460 0.01422 1.188 [0.417,0.503]
square2 0.552 0.01803 1.425 [0.498,0.606]
square5 0.766 0.01654 1.979 [0.717,0.816]
>>> 

square0 has no nested function, square1 has one nested function, square2 has two nested functions and square5 has five nested functions. The nested functions are only declared but not called.

So if you have defined 5 nested funtions in a function that you don't call then the execution time of the function is twice of the function without a nested function. I think should be cautious when using nested functions.

The Python file for the whole test that generates this output can be found at ideone.


It's just a principle about exposure APIs.

Using python, It's a good idea to avoid exposure API in outer space(module or class), function is a good encapsulation place.

It could be a good idea. when you ensure

  1. inner function is ONLY used by outer function.
  2. insider function has a good name to explain its purpose because the code talks.
  3. code cannot directly understand by your colleagues(or other code-reader).

Even though, Abuse this technique may cause problems and implies a design flaw.

Just from my exp, Maybe misunderstand your question.


So in the end it is largely a question about how smart the python implementation is or is not, particularly in the case of the inner function not being a closure but simply an in function needed helper only.

In clean understandable design having functions only where they are needed and not exposed elsewhere is good design whether they be embedded in a module, a class as a method, or inside another function or method. When done well they really improve the clarity of the code.

And when the inner function is a closure that can also help with clarity quite a bit even if that function is not returned out of the containing function for use elsewhere.

So I would say generally do use them but be aware of the possible performance hit when you actually are concerned about performance and only remove them if you do actual profiling that shows they best be removed.

Do not do premature optimization of just using "inner functions BAD" throughout all python code you write. Please.


It's perfectly OK doing it that way, but unless you need to use a closure or return the function I'd probably put in the module level. I imagine in the second code example you mean:

...
some_data = method_b() # not some_data = method_b

otherwise, some_data will be the function.

Having it at the module level will allow other functions to use method_b() and if you're using something like Sphinx (and autodoc) for documentation, it will allow you to document method_b as well.

You also may want to consider just putting the functionality in two methods in a class if you're doing something that can be representable by an object. This contains logic well too if that's all you're looking for.


mdlp's answer didn't work for me.

This did:

def some_function():
    return some_other_function()
def some_other_function():
    return 42

print some_function()

Do something like:

def some_function():
    some_other_function()
def some_other_function():
    return 42 

if you were to run some_function() it would then run some_other_function() and returns 42.

EDIT: I originally stated that you shouldn't define a function inside of another but it was pointed out that it is practical to do this sometimes.


You can use it to avoid defining global variables. This gives you an alternative for other designs. 3 designs presenting a solution to a problem.

A) Using functions without globals

def calculate_salary(employee, list_with_all_employees):
    x = _calculate_tax(list_with_all_employees)

    # some other calculations done to x
    pass

    y = # something 

    return y

def _calculate_tax(list_with_all_employees):
    return 1.23456 # return something

B) Using functions with globals

_list_with_all_employees = None

def calculate_salary(employee, list_with_all_employees):

    global _list_with_all_employees
    _list_with_all_employees = list_with_all_employees

    x = _calculate_tax()

    # some other calculations done to x
    pass

    y = # something

    return y

def _calculate_tax():
    return 1.23456 # return something based on the _list_with_all_employees var

C) Using functions inside another function

def calculate_salary(employee, list_with_all_employees):

    def _calculate_tax():
        return 1.23456 # return something based on the list_with_a--Lemployees var

    x = _calculate_tax()

    # some other calculations done to x
    pass
    y = # something 

    return y

Solution C) allows to use variables in the scope of the outer function without having the need to declare them in the inner function. Might be useful in some situations.


Function In function python

def Greater(a,b):
    if a>b:
        return a
    return b

def Greater_new(a,b,c,d):
    return Greater(Greater(a,b),Greater(c,d))

print("Greater Number is :-",Greater_new(212,33,11,999))

참고URL : https://stackoverflow.com/questions/4831680/if-function-a-is-required-only-by-function-b-should-a-be-defined-inside-b

반응형