functools
— Higher-order functions and operations on callable objects¶
소스 코드: Lib/functools.py
functools
모듈은 고차 함수를 위한 것입니다: 다른 함수에 작용하거나 다른 함수를 반환하는 함수. 일반적으로, 모든 콜러블 객체는 이 모듈의 목적상 함수로 취급될 수 있습니다.
functools
모듈은 다음 함수를 정의합니다:
- @functools.cache(user_function)¶
단순하고 가벼운 무제한 함수 캐시. 때때로 “memoize”라고도 합니다.
Returns the same as
lru_cache(maxsize=None)
, creating a thin wrapper around a dictionary lookup for the function arguments. Because it never needs to evict old values, this is smaller and faster thanlru_cache()
with a size limit.예를 들면:
@cache def factorial(n): return n * factorial(n-1) if n else 1 >>> factorial(10) # no previously cached result, makes 11 recursive calls 3628800 >>> factorial(5) # just looks up cached value result 120 >>> factorial(12) # makes two new recursive calls, the other 10 are cached 479001600
The cache is threadsafe so that the wrapped function can be used in multiple threads. This means that the underlying data structure will remain coherent during concurrent updates.
It is possible for the wrapped function to be called more than once if another thread makes an additional call before the initial call has been completed and cached.
Added in version 3.9.
- @functools.cached_property(func)¶
클래스의 메서드를 값이 한 번 계산된 다음 인스턴스 수명 동안 일반 어트리뷰트로 캐시 되는 프로퍼티로 변환합니다.
property()
와 유사하고, 캐싱이 추가되었습니다. 비싸게 계산되고 그 외에는 사실상 불변인 인스턴스의 프로퍼티에 유용합니다.예:
class DataSet: def __init__(self, sequence_of_numbers): self._data = tuple(sequence_of_numbers) @cached_property def stdev(self): return statistics.stdev(self._data)
cached_property()
의 메커니즘은property()
와 다소 다릅니다. 일반 프로퍼티는 setter가 정의되지 않은 경우 어트리뷰트 쓰기를 차단합니다. 이와는 달리, cached_property는 쓰기를 허용합니다.cached_property 데코레이터는 조회 시에만, 같은 이름의 어트리뷰트가 존재하지 않을 때만 실행됩니다. 실행되면, cached_property는 같은 이름의 어트리뷰트에 기록합니다. 후속 어트리뷰트 읽기와 쓰기는 cached_property 메서드보다 우선하며 일반 어트리뷰트처럼 작동합니다.
캐시 된 값은 어트리뷰트를 삭제하여 지울 수 있습니다. 이렇게 하면 cached_property 메서드가 다시 실행됩니다.
The cached_property does not prevent a possible race condition in multi-threaded usage. The getter function could run more than once on the same instance, with the latest run setting the cached value. If the cached property is idempotent or otherwise not harmful to run more than once on an instance, this is fine. If synchronization is needed, implement the necessary locking inside the decorated getter function or around the cached property access.
이 데코레이터는 PEP 412 키 공유 딕셔너리의 작동을 방해함에 유의하십시오. 이는 인스턴스 딕셔너리가 평소보다 더 많은 공간을 차지할 수 있음을 의미합니다.
또한, 이 데코레이터는 각 인스턴스의
__dict__
어트리뷰트가 가변 매핑일 것을 요구합니다. 이는 메타 클래스(형 인스턴스의__dict__
어트리뷰트가 클래스 이름 공간에 대한 읽기 전용 프락시이기 때문에)와__dict__
를 정의된 슬롯 중 하나로 포함하지 않고__slots__
를 지정하는 것(이러한 클래스는__dict__
어트리뷰트를 전혀 제공하지 않기 때문에)과 같은 일부 형에서 작동하지 않음을 의미합니다.If a mutable mapping is not available or if space-efficient key sharing is desired, an effect similar to
cached_property()
can also be achieved by stackingproperty()
on top oflru_cache()
. See How do I cache method calls? for more details on how this differs fromcached_property()
.Added in version 3.8.
버전 3.12에서 변경: Prior to Python 3.12,
cached_property
included an undocumented lock to ensure that in multi-threaded usage the getter function was guaranteed to run only once per instance. However, the lock was per-property, not per-instance, which could result in unacceptably high lock contention. In Python 3.12+ this locking is removed.
- functools.cmp_to_key(func)¶
구식 비교 함수를 키 함수로 변환합니다. (
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
와 같은) 키 함수를 받아들이는 도구와 함께 사용됩니다. 이 함수는 주로 비교 함수 사용을 지원하는 파이썬 2에서 변환되는 프로그램의 전이 도구로 사용됩니다.A comparison function is any callable that accepts two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one argument and returns another value to be used as the sort key.
예:
sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order
정렬 예제와 간략한 정렬 자습서는 Sorting Techniques를 참조하십시오.
Added in version 3.2.
- @functools.lru_cache(user_function)¶
- @functools.lru_cache(maxsize=128, typed=False)
가장 최근의 maxsize 호출까지 저장하는 기억하는(memoizing) 콜러블 함수를 감싸는 데코레이터. 비싸거나 I/O 병목 함수가 같은 인자로 주기적으로 호출될 때 시간을 절약할 수 있습니다.
The cache is threadsafe so that the wrapped function can be used in multiple threads. This means that the underlying data structure will remain coherent during concurrent updates.
It is possible for the wrapped function to be called more than once if another thread makes an additional call before the initial call has been completed and cached.
Since a dictionary is used to cache results, the positional and keyword arguments to the function must be hashable.
Distinct argument patterns may be considered to be distinct calls with separate cache entries. For example,
f(a=1, b=2)
andf(b=2, a=1)
differ in their keyword argument order and may have two separate cache entries.user_function이 지정되면, 콜러블이어야 합니다. 이는 lru_cache 데코레이터를 사용자 함수에 직접 적용 할 수 있도록 하며, maxsize를 기본값 128로 유지합니다:
@lru_cache def count_vowels(sentence): return sum(sentence.count(vowel) for vowel in 'AEIOUaeiou')
maxsize가
None
으로 설정되면, LRU 기능이 비활성화되고 캐시가 제한 없이 커질 수 있습니다.If typed is set to true, function arguments of different types will be cached separately. If typed is false, the implementation will usually regard them as equivalent calls and only cache a single result. (Some types such as str and int may be cached separately even when typed is false.)
Note, type specificity applies only to the function’s immediate arguments rather than their contents. The scalar arguments,
Decimal(42)
andFraction(42)
are be treated as distinct calls with distinct results. In contrast, the tuple arguments('answer', Decimal(42))
and('answer', Fraction(42))
are treated as equivalent.The wrapped function is instrumented with a
cache_parameters()
function that returns a newdict
showing the values for maxsize and typed. This is for information purposes only. Mutating the values has no effect.To help measure the effectiveness of the cache and tune the maxsize parameter, the wrapped function is instrumented with a
cache_info()
function that returns a named tuple showing hits, misses, maxsize and currsize.데코레이터는 캐시를 지우거나 무효로 하기 위한
cache_clear()
함수도 제공합니다.원래의 하부 함수는
__wrapped__
어트리뷰트를 통해 액세스 할 수 있습니다. 이것은 인트로스펙션, 캐시 우회 또는 다른 캐시로 함수를 다시 래핑하는 데 유용합니다.The cache keeps references to the arguments and return values until they age out of the cache or until the cache is cleared.
If a method is cached, the
self
instance argument is included in the cache. See How do I cache method calls?An LRU (least recently used) cache works best when the most recent calls are the best predictors of upcoming calls (for example, the most popular articles on a news server tend to change each day). The cache’s size limit assures that the cache does not grow without bound on long-running processes such as web servers.
In general, the LRU cache should only be used when you want to reuse previously computed values. Accordingly, it doesn’t make sense to cache functions with side-effects, functions that need to create distinct mutable objects on each call (such as generators and async functions), or impure functions such as time() or random().
정적 웹 콘텐츠를 위한 LRU 캐시의 예:
@lru_cache(maxsize=32) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = f'https://peps.python.org/pep-{num:04d}' try: with urllib.request.urlopen(resource) as s: return s.read() except urllib.error.HTTPError: return 'Not Found' >>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991: ... pep = get_pep(n) ... print(n, len(pep)) >>> get_pep.cache_info() CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
동적 프로그래밍(dynamic programming) 기법을 구현하기 위해 캐시를 사용하여 피보나치 수를 효율적으로 계산하는 예:
@lru_cache(maxsize=None) def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) >>> [fib(n) for n in range(16)] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] >>> fib.cache_info() CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
Added in version 3.2.
버전 3.3에서 변경: typed 옵션을 추가했습니다.
버전 3.8에서 변경: user_function 옵션을 추가했습니다.
버전 3.9에서 변경: Added the function
cache_parameters()
- @functools.total_ordering¶
하나 이상의 풍부한 비교(rich comparison) 순서 메서드를 정의하는 클래스를 주면, 이 클래스 데코레이터가 나머지를 제공합니다. 가능한 모든 풍부한 비교 연산을 지정하는 데 드는 노력이 단순화됩니다:
클래스는
__lt__()
,__le__()
,__gt__()
또는__ge__()
중 하나를 정의해야 합니다. 또한, 클래스는__eq__()
메서드를 제공해야 합니다.예를 들면:
@total_ordering class Student: def _is_valid_operand(self, other): return (hasattr(other, "lastname") and hasattr(other, "firstname")) def __eq__(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower())) def __lt__(self, other): if not self._is_valid_operand(other): return NotImplemented return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))
참고
이 데코레이터를 사용하면 올바르게 동작하는 전 순서(totally ordered) 형을 쉽게 만들 수 있지만, 파생된 비교 메서드에서 실행 속도가 느려지고 스택 트레이스가 더 복잡해지는 대가를 지불합니다. 성능 벤치마킹이 이것이 특정 응용 프로그램의 병목임을 가리키면, 6가지의 풍부한 비교 메서드를 모두 구현하여 속도를 쉽게 높일 수 있습니다.
참고
This decorator makes no attempt to override methods that have been declared in the class or its superclasses. Meaning that if a superclass defines a comparison operator, total_ordering will not implement it again, even if the original method is abstract.
Added in version 3.2.
버전 3.4에서 변경: Returning
NotImplemented
from the underlying comparison function for unrecognised types is now supported.
- functools.partial(func, /, *args, **keywords)¶
호출될 때 위치 인자 args와 키워드 인자 keywords로 호출된 func처럼 동작하는 새 partial 객체를 반환합니다. 더 많은 인자가 호출에 제공되면, args에 추가됩니다. 추가 키워드 인자가 제공되면, keywords를 확장하고 대체합니다. 대략 다음과 동등합니다:
def partial(func, /, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = {**keywords, **fkeywords} return func(*args, *fargs, **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc
partial()
은 함수의 인자 및/또는 키워드의 일부를 “고정”하여 서명이 단순화된 새 객체를 생성하는 부분 함수 응용에 사용됩니다. 예를 들어,partial()
을 사용하여 base 인자의 기본값이 2이면서int()
함수 같은 동작을 하는 콜러블을 만들 수 있습니다:>>> from functools import partial >>> basetwo = partial(int, base=2) >>> basetwo.__doc__ = 'Convert base 2 string to an int.' >>> basetwo('10010') 18
- class functools.partialmethod(func, /, *args, **keywords)¶
직접 호출하기보다는 메서드 정의로 사용되도록 설계된 것을 제외하고는
partial
과 같이 동작하는 새partialmethod
디스크립터를 반환합니다.func는 디스크립터나 콜러블이어야 합니다 (일반 함수처럼 둘 모두인 객체는 디스크립터로 처리됩니다).
func가 디스크립터(가령 일반 파이썬 함수,
classmethod()
,staticmethod()
,abstractmethod()
또는partialmethod
의 다른 인스턴스)이면,__get__
에 대한 호출은 하부 디스크립터에 위임되고, 적절한 partial 객체가 결과로 반환됩니다.func가 디스크립터가 아닌 콜러블이면, 적절한 연결된 메서드가 동적으로 만들어집니다. 이것은 메서드로 사용될 때 일반 파이썬 함수처럼 작동합니다:
partialmethod
생성자에 제공된 args와 keywords보다도 전에 self 인자가 첫 번째 위치 인자로 삽입됩니다.예:
>>> class Cell: ... def __init__(self): ... self._alive = False ... @property ... def alive(self): ... return self._alive ... def set_state(self, state): ... self._alive = bool(state) ... set_alive = partialmethod(set_state, True) ... set_dead = partialmethod(set_state, False) ... >>> c = Cell() >>> c.alive False >>> c.set_alive() >>> c.alive True
Added in version 3.4.
- functools.reduce(function, iterable[, initializer])¶
두 인자의 function을 왼쪽에서 오른쪽으로 iterable의 항목에 누적적으로 적용해서, 이터러블을 단일 값으로 줄입니다. 예를 들어,
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
는((((1+2)+3)+4)+5)
를 계산합니다. 왼쪽 인자 x는 누적값이고 오른쪽 인자 y는 iterable에서 온 갱신 값입니다. 선택적 initializer가 있으면, 계산에서 이터러블의 항목 앞에 배치되고, 이터러블이 비어있을 때 기본값의 역할을 합니다. initializer가 제공되지 않고 iterable에 하나의 항목만 포함되면, 첫 번째 항목이 반환됩니다.대략 다음과 동등합니다:
def reduce(function, iterable, initializer=None): it = iter(iterable) if initializer is None: value = next(it) else: value = initializer for element in it: value = function(value, element) return value
모든 중간값을 산출하는 이터레이터는
itertools.accumulate()
를 참조하십시오.
- @functools.singledispatch¶
-
To define a generic function, decorate it with the
@singledispatch
decorator. When defining a function using@singledispatch
, note that the dispatch happens on the type of the first argument:>>> from functools import singledispatch >>> @singledispatch ... def fun(arg, verbose=False): ... if verbose: ... print("Let me just say,", end=" ") ... print(arg)
To add overloaded implementations to the function, use the
register()
attribute of the generic function, which can be used as a decorator. For functions annotated with types, the decorator will infer the type of the first argument automatically:>>> @fun.register ... def _(arg: int, verbose=False): ... if verbose: ... print("Strength in numbers, eh?", end=" ") ... print(arg) ... >>> @fun.register ... def _(arg: list, verbose=False): ... if verbose: ... print("Enumerate this:") ... for i, elem in enumerate(arg): ... print(i, elem)
types.UnionType
andtyping.Union
can also be used:>>> @fun.register ... def _(arg: int | float, verbose=False): ... if verbose: ... print("Strength in numbers, eh?", end=" ") ... print(arg) ... >>> from typing import Union >>> @fun.register ... def _(arg: Union[list, set], verbose=False): ... if verbose: ... print("Enumerate this:") ... for i, elem in enumerate(arg): ... print(i, elem) ...
형 어노테이션을 사용하지 않는 코드의 경우, 적절한 형 인자를 데코레이터 자체에 명시적으로 전달할 수 있습니다:
>>> @fun.register(complex) ... def _(arg, verbose=False): ... if verbose: ... print("Better than complicated.", end=" ") ... print(arg.real, arg.imag) ...
For code that dispatches on a collections type (e.g.,
list
), but wants to typehint the items of the collection (e.g.,list[int]
), the dispatch type should be passed explicitly to the decorator itself with the typehint going into the function definition:>>> @fun.register(list) ... def _(arg: list[int], verbose=False): ... if verbose: ... print("Enumerate this:") ... for i, elem in enumerate(arg): ... print(i, elem)
참고
At runtime the function will dispatch on an instance of a list regardless of the type contained within the list i.e.
[1,2,3]
will be dispatched the same as["foo", "bar", "baz"]
. The annotation provided in this example is for static type checkers only and has no runtime impact.To enable registering lambdas and pre-existing functions, the
register()
attribute can also be used in a functional form:>>> def nothing(arg, verbose=False): ... print("Nothing.") ... >>> fun.register(type(None), nothing)
The
register()
attribute returns the undecorated function. This enables decorator stacking,pickling
, and the creation of unit tests for each variant independently:>>> @fun.register(float) ... @fun.register(Decimal) ... def fun_num(arg, verbose=False): ... if verbose: ... print("Half of your number:", end=" ") ... print(arg / 2) ... >>> fun_num is fun False
호출되면, 제네릭 함수는 첫 번째 인자의 형에 따라 디스패치 합니다:
>>> fun("Hello, world.") Hello, world. >>> fun("test.", verbose=True) Let me just say, test. >>> fun(42, verbose=True) Strength in numbers, eh? 42 >>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True) Enumerate this: 0 spam 1 spam 2 eggs 3 spam >>> fun(None) Nothing. >>> fun(1.23) 0.615
Where there is no registered implementation for a specific type, its method resolution order is used to find a more generic implementation. The original function decorated with
@singledispatch
is registered for the baseobject
type, which means it is used if no better implementation is found.If an implementation is registered to an abstract base class, virtual subclasses of the base class will be dispatched to that implementation:
>>> from collections.abc import Mapping >>> @fun.register ... def _(arg: Mapping, verbose=False): ... if verbose: ... print("Keys & Values") ... for key, value in arg.items(): ... print(key, "=>", value) ... >>> fun({"a": "b"}) a => b
To check which implementation the generic function will choose for a given type, use the
dispatch()
attribute:>>> fun.dispatch(float) <function fun_num at 0x1035a2840> >>> fun.dispatch(dict) # note: default implementation <function fun at 0x103fe0000>
등록된 모든 구현에 액세스하려면, 읽기 전용
registry
어트리뷰트를 사용하십시오:>>> fun.registry.keys() dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>, <class 'decimal.Decimal'>, <class 'list'>, <class 'float'>]) >>> fun.registry[float] <function fun_num at 0x1035a2840> >>> fun.registry[object] <function fun at 0x103fe0000>
Added in version 3.4.
버전 3.7에서 변경: The
register()
attribute now supports using type annotations.버전 3.11에서 변경: The
register()
attribute now supportstypes.UnionType
andtyping.Union
as type annotations.
- class functools.singledispatchmethod(func)¶
-
To define a generic method, decorate it with the
@singledispatchmethod
decorator. When defining a function using@singledispatchmethod
, note that the dispatch happens on the type of the first non-self or non-cls argument:class Negator: @singledispatchmethod def neg(self, arg): raise NotImplementedError("Cannot negate a") @neg.register def _(self, arg: int): return -arg @neg.register def _(self, arg: bool): return not arg
@singledispatchmethod
supports nesting with other decorators such as@classmethod
. Note that to allow fordispatcher.register
,singledispatchmethod
must be the outer most decorator. Here is theNegator
class with theneg
methods bound to the class, rather than an instance of the class:class Negator: @singledispatchmethod @classmethod def neg(cls, arg): raise NotImplementedError("Cannot negate a") @neg.register @classmethod def _(cls, arg: int): return -arg @neg.register @classmethod def _(cls, arg: bool): return not arg
The same pattern can be used for other similar decorators:
@staticmethod
,@abstractmethod
, and others.Added in version 3.8.
- functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)¶
Update a wrapper function to look like the wrapped function. The optional arguments are tuples to specify which attributes of the original function are assigned directly to the matching attributes on the wrapper function and which attributes of the wrapper function are updated with the corresponding attributes from the original function. The default values for these arguments are the module level constants
WRAPPER_ASSIGNMENTS
(which assigns to the wrapper function’s__module__
,__name__
,__qualname__
,__annotations__
,__type_params__
, and__doc__
, the documentation string) andWRAPPER_UPDATES
(which updates the wrapper function’s__dict__
, i.e. the instance dictionary).내부 검사와 기타 목적(예를 들어
lru_cache()
와 같은 캐싱 데코레이터 우회)을 위해 원래 함수에 액세스 할 수 있도록, 이 함수는 래핑 되는 함수를 가리키는__wrapped__
어트리뷰트를 wrapper에 자동으로 추가합니다.이 함수의 주요 용도는 데코레이트 된 함수를 래핑하고 wrapper를 반환하는 데코레이터 함수에서 사용하는 것입니다. wrapper 함수가 갱신되지 않으면, 반환된 함수의 메타 데이터는 원래 함수 정의가 아닌 wrapper 정의를 반영하게 되어 일반적으로 도움이 되지 않습니다.
update_wrapper()
는 함수 이외의 콜러블과 함께 사용할 수 있습니다. 래핑 되는 객체에서 누락된 assigned나 updated로 이름 지정된 어트리뷰트는 무시됩니다 (즉, 이 함수는 wrapper 함수에서 그 어트리뷰트를 설정하려고 시도하지 않습니다). wrapper 함수 자체에 updated에 이름 지정된 어트리뷰트가 없으면 여전히AttributeError
가 발생합니다.버전 3.2에서 변경: The
__wrapped__
attribute is now automatically added. The__annotations__
attribute is now copied by default. Missing attributes no longer trigger anAttributeError
.버전 3.4에서 변경:
__wrapped__
어트리뷰트는 이제 해당 함수가__wrapped__
어트리뷰트를 정의한 경우에도 항상 래핑 된 함수를 참조합니다. (bpo-17482를 참조하십시오)버전 3.12에서 변경: The
__type_params__
attribute is now copied by default.
- @functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)¶
래퍼 함수를 정의할 때 함수 데코레이터로
update_wrapper()
를 호출하기 위한 편의 함수입니다.partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)
와 동등합니다. 예를 들면:>>> from functools import wraps >>> def my_decorator(f): ... @wraps(f) ... def wrapper(*args, **kwds): ... print('Calling decorated function') ... return f(*args, **kwds) ... return wrapper ... >>> @my_decorator ... def example(): ... """Docstring""" ... print('Called example function') ... >>> example() Calling decorated function Called example function >>> example.__name__ 'example' >>> example.__doc__ 'Docstring'
이 데코레이터 팩토리를 사용하지 않으면, example 함수의 이름은
'wrapper'
가 되고, 원래example()
의 독스트링은 잃어버리게 됩니다.
partial
객체¶
partial
객체는 partial()
이 만든 콜러블 객체입니다. 세 가지 읽기 전용 어트리뷰트가 있습니다:
partial
objects are like function objects
in that they are callable, weak referenceable, and can have attributes.
There are some important differences. For instance, the
__name__
and function.__doc__
attributes
are not created automatically. Also, partial
objects defined in
classes behave like static methods and do not transform into bound methods
during instance attribute look-up.