sourcetip

Python __call__ 특수 메서드 실용적인 예

fileupload 2023. 6. 27. 22:30
반응형

Python __call__ 특수 메서드 실용적인 예

나는 그것을 알고 있습니다.__call__클래스의 인스턴스가 호출될 때 클래스의 메서드가 트리거됩니다. 특별한 방법을 할 수 있을지 은 단순히 새로운 을 할 수 입니다. 왜냐하면 새로운 방법을 만들고 다음에서 수행한 것과 같은 작업을 수행할 수 있기 때문입니다.__call__메소드를 호출하는 대신 메소드를 호출할 수 있습니다.

누군가 이 특별한 방법을 실용적으로 사용해 주시면 정말 감사하겠습니다.

이 예제에서는 기본적으로 값을 테이블(이 경우 사전)에 저장하는 메모화를 사용하여 값을 다시 계산하는 대신 나중에 조회할 수 있습니다.

▁a▁▁class▁simple다▁a가 있는 간단한 수업을 합니다.__call__정적 변수를 포함하는 요인 함수 대신 (호출 가능한 개체를 통해) 요인을 계산하는 방법입니다(Python에서는 가능하지 않음).

class Factorial:
    def __init__(self):
        self.cache = {}
    def __call__(self, n):
        if n not in self.cache:
            if n == 0:
                self.cache[n] = 1
            else:
                self.cache[n] = n * self.__call__(n-1)
        return self.cache[n]

fact = Factorial()

당신은 당제신은이가 .fact다른 모든 함수와 마찬가지로 호출 가능한 개체입니다.를 들어, .

for i in xrange(10):                                                             
    print("{}! = {}".format(i, fact(i)))

# output
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880

그리고 그것은 또한 스테이트풀합니다.

은 장사양모용을 사용합니다.__call__양식 유효성 검사를 위한 일관된 API를 구현하는 방법입니다.당신은 장고의 양식에 대한 자신의 검증자를 함수로 작성할 수 있습니다.

def custom_validator(value):
    #your validation logic

Django에는 이메일 유효성 검사기, URL 유효성 검사기 등과 같은 기본적인 일부 유효성 검사기가 내장되어 있으며, 이는 대체로 ReGEx 유효성 검사기의 산하에 있습니다.이러한 것들을 깨끗하게 구현하기 위해 Django는 (함수 대신) 호출 가능한 클래스에 의존합니다.RegexValidator에서 기본 RegexValidation 논리를 구현한 다음 다른 유효성 검사를 위해 이러한 클래스를 확장합니다.

class RegexValidator(object):
    def __call__(self, value):
        # validation logic

class URLValidator(RegexValidator):
    def __call__(self, value):
        super(URLValidator, self).__call__(value)
        #additional logic

class EmailValidator(RegexValidator):
    # some logic

이제 사용자 지정 함수와 기본 제공 Email Validator를 모두 동일한 구문으로 호출할 수 있습니다.

for v in [custom_validator, EmailValidator()]:
    v(value) # <-----

보시다시피, 장고의 이 구현은 다른 사람들이 아래 답변에서 설명한 것과 유사합니다.이것을 다른 방법으로 구현할 수 있습니까?그럴 수도 있지만, IMHO는 장고와 같은 큰 프레임워크에 대해 그렇게 쉽게 읽히거나 확장할 수 없을 것입니다.

사용하기 쉬운 API(특정 인수가 필요한 호출 가능한 개체가 있음)를 만들 수 있고 객체 지향 관행을 사용할 수 있기 때문에 구현하기 쉽기 때문에 유용하다고 생각합니다.

다음은 제가 어제 작성한 버전의 코드입니다.hashlib.foo문자열이 아닌 전체 파일을 해시하는 메서드:

# filehash.py
import hashlib


class Hasher(object):
    """
    A wrapper around the hashlib hash algorithms that allows an entire file to
    be hashed in a chunked manner.
    """
    def __init__(self, algorithm):
        self.algorithm = algorithm

    def __call__(self, file):
        hash = self.algorithm()
        with open(file, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), ''):
                hash.update(chunk)
        return hash.hexdigest()


md5    = Hasher(hashlib.md5)
sha1   = Hasher(hashlib.sha1)
sha224 = Hasher(hashlib.sha224)
sha256 = Hasher(hashlib.sha256)
sha384 = Hasher(hashlib.sha384)
sha512 = Hasher(hashlib.sha512)

이 구현을 통해 다음과 유사한 방식으로 기능을 사용할 수 있습니다.hashlib.foo함수:

from filehash import sha1
print sha1('somefile.txt')

물론 다른 방법으로 구현할 수도 있었지만, 이 경우에는 단순한 접근법처럼 보였습니다.

__call__파이썬에서 데코레이터 클래스를 구현하는 데도 사용됩니다.이 경우 클래스의 인스턴스는 데코레이터가 있는 메서드가 호출될 때 호출됩니다.

class EnterExitParam(object):

    def __init__(self, p1):
        self.p1 = p1

    def __call__(self, f):
        def new_f():
            print("Entering", f.__name__)
            print("p1=", self.p1)
            f()
            print("Leaving", f.__name__)
        return new_f


@EnterExitParam("foo bar")
def hello():
    print("Hello")


if __name__ == "__main__":
    hello()

프로그램 출력:

Entering hello
p1= foo bar
Hello
Leaving hello

예, 객체를 다루는 경우 명시적인 메서드 호출을 사용하는 것이 완벽하게 가능합니다(많은 경우에 따라 완전히 가능합니다.그러나, 때때로 당신은 호출 가능한 객체를 기대하는 코드를 다룬다 - 일반적으로 기능하지만, 덕분에.__call__인스턴스 데이터 및 호출 가능한 반복 작업 등을 위임하는 더 많은 방법을 사용하여 더 복잡한 개체를 만들 수 있습니다.

또한 복잡한 작업(전용 클래스를 작성하는 것이 합리적인 경우)과 간단한 작업(함수에 이미 존재하거나 함수로 더 쉽게 작성됨)에 개체를 모두 사용하는 경우도 있습니다.공통 인터페이스를 사용하려면 함수를 예상 인터페이스로 묶는 작은 클래스를 작성하거나 함수를 유지하고 더 복잡한 개체를 호출할 수 있도록 만들어야 합니다.스레드를 예로 들어 보겠습니다.표준 라이브러리 모듈의 개체는 다음과 같은 호출 가능을 원합니다.target인수(즉, 새 스레드에서 수행할 작업).호출 가능 개체를 사용하면 함수에 제한되지 않고 다른 스레드에서 작업을 가져와 순차적으로 실행하는 비교적 복잡한 작업자와 같은 다른 개체도 전달할 수 있습니다.

class Worker(object):
    def __init__(self, *args, **kwargs):
        self.queue = queue.Queue()
        self.args = args
        self.kwargs = kwargs

    def add_task(self, task):
        self.queue.put(task)

    def __call__(self):
        while True:
            next_action = self.queue.get()
            success = next_action(*self.args, **self.kwargs)
            if not success:
               self.add_task(next_action)

이것은 제 머리 속의 예시일 뿐이지만, 저는 그것이 이미 수업을 보증할 만큼 충분히 복잡하다고 생각합니다.기능만으로 이 작업을 수행하는 것은 어렵습니다. 적어도 두 개의 기능을 반환해야 하기 때문에 점점 복잡해지고 있습니다.이름을 바꿀 수 있습니다.__call__스레드를 생성하는 코드를 약간 덜 명확하게 만들고 값을 추가하지 않습니다.

은 스기반장사용가식클래를 사용합니다.__call__접힌 함수를 참조합니다.예:

class Deco(object):
    def __init__(self,f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print args
        print kwargs
        self.f(*args, **kwargs)

다양한 옵션에 대한 좋은 설명이 여기 Artima.com 에 있습니다.

임호호__call__메서드와 클로저는 Python에서 전략 설계 패턴을 만드는 자연스러운 방법을 제공합니다.알고리즘 제품군을 정의하고, 각 알고리즘을 캡슐화하고, 서로 교환할 수 있도록 하며, 마지막에는 공통 단계 집합을 실행하고, 예를 들어 파일에 대한 해시를 계산할 수 있습니다.

의 사용법을 우연히 발견했습니다.__call__() 하여.__getattr__()제가 생각하기에 아름답습니다.개체 내에서 여러 수준의 JSON/HTTP/(hut_serialized) API를 숨길 수 있습니다.

__getattr__()는 같은한을 더 .part 동 일 클 는 반 반 한 번 하 입 합 니 력 다 속 을 성 의 상 이 나 하 에 여 환 로 적 으 복 한 턴 스 를 래 스 된 스 인 수 정 의 ▁of ▁at ▁part ▁a 다 니 합 ▁in ▁care ▁takes 력 part ▁returning , atively ▁class 는 ▁one▁of다 소진된 에, 면정후소, 가보진된모그든러된후,,__call__()전달한 인수를 대신합니다.

이 모델을 사용하여 예를 들어 다음과 같은 전화를 걸 수 있습니다.api.v2.volumes.ssd.update(size=20) PUT 국 PUT 요다이니집어청결로으다▁which▁to니▁ends집▁a이.https://some.tld/api/v2/volumes/ssd/update.

특정 코드는 OpenStack의 특정 볼륨 백엔드에 대한 블록 스토리지 드라이버이며, 여기에서 확인할 수 있습니다. https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py

편집: 링크가 마스터 버전을 가리키도록 업데이트되었습니다.

나는 호출 가능한 객체를 사용하기에 좋은 장소를 찾는다, 그것들은 정의합니다.__call__()다음과 같은 기능적 프로그래밍 기능을 파이썬에서 사용할 때map(),filter(),reduce().

에 가장 하여 어떤 ▁that▁info▁the▁is▁the▁or▁over▁other▁passed▁the▁is▁when▁not▁in▁to▁or▁a▁best▁uses▁a▁logic▁state▁a▁toable▁object▁use▁function니입해다▁call▁some▁time▁function용야사할일를보▁plain▁lambda때정__call__()기능.

은 호출 다은호가출사여파하용다일이니기코입드파는필하터링름이을음일준로으능장름한을확명체개를▁that▁here▁code▁names▁file▁filters▁some▁and▁based.filter().

호출 가능:

import os

class FileAcceptor(object):
    def __init__(self, accepted_extensions):
        self.accepted_extensions = accepted_extensions

    def __call__(self, filename):
        base, ext = os.path.splitext(filename)
        return ext in self.accepted_extensions

class ImageFileAcceptor(FileAcceptor):
    def __init__(self):
        image_extensions = ('.jpg', '.jpeg', '.gif', '.bmp')
        super(ImageFileAcceptor, self).__init__(image_extensions)

용도:

filenames = [
    'me.jpg',
    'me.txt',
    'friend1.jpg',
    'friend2.bmp',
    'you.jpeg',
    'you.xml']

acceptor = ImageFileAcceptor()
image_filenames = filter(acceptor, filenames)
print image_filenames

출력:

['me.jpg', 'friend1.jpg', 'friend2.bmp', 'you.jpeg']

제 : 저는초자이만지보것, 생은이다: 는갖니렇습.__call__구성을 쉽게 코딩할 수 있습니다.한다면f, g 급의의 입니다.Function그것은 방법이 있습니다.eval(self,x)에 그다에와 함께__call___▁write는▁one를 쓸 수 있었습니다.f(g(x))와는반과 f.eval(g.eval(x)).

뉴럴 네트워크는 더 작은 뉴럴 네트워크로 구성될 수 있고, 우리는 파이토치에서__call__모듈 클래스:

다음은 어디에 대한 예시입니다.__call__는 실제에서 사용됩니다: 파이토치에서, 신경망을 정의할 때 (그것이라고 부릅니다).class MyNN(nn.Module)예를 들어) 횃불의 하위 클래스로 지정합니다.모일듈모(모듈의 정의)를 합니다.forward할 때 합니다.x를 들어model=MyNN()우리는 그냥 씁니다.model(x)와는반과 model.forward(x)하지만 둘 다 같은 대답을 합니다.Torch.n.module 소스를 파고들면,모듈 여기

https://pytorch.org/docs/stable/_modules/torch/nn/modules/module.html#Module

.__call__사람들은 결국 - 적어도 어떤 경우에는 - 에 대한 전화로 그것을 추적할 수 있습니다.self.forward

import torch.nn as nn
import torch.nn.functional as F

class MyNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1 = nn.Linear(784, 200)



    def forward(self, x):
        return F.ReLU(self.layer1(x))

x=torch.rand(10,784)
model=MyNN()
print(model(x))
print(model.forward(x))

한 값을 두 로 출력합니다.__call___그래서 그것이 파이썬이 볼 때 의지하는 것이라고 믿습니다.model(x) 리고그고.__call__결국에는 전화를 걸게 됩니다.model.forward(x))

을 합니다.__metaclass__그리고 그것을 무시합니다.__call__method,class의 meta class의 method, meta class의 method를 .__new__메소드는 클래스의 인스턴스를 반환합니다. 비올라는 메소드와 "함수"를 가지고 있습니다.

우리는 사용할 수 있습니다.__call__다른 클래스 메소드를 정적 메소드로 사용하는 메소드입니다.

    class _Callable:
        def __init__(self, anycallable):
            self.__call__ = anycallable

    class Model:

        def get_instance(conn, table_name):

            """ do something"""

        get_instance = _Callable(get_instance)

    provs_fac = Model.get_instance(connection, "users")             

한 가지 일반적인 예는 다음과 같습니다.__call__functools.partial다음은 단순화된 버전입니다(Python > = 3.5 사용).

class partial:
    """New function with partial application of the given arguments and keywords."""

    def __new__(cls, func, *args, **kwargs):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        self = super().__new__(cls)

        self.func = func
        self.args = args
        self.kwargs = kwargs
        return self

    def __call__(self, *args, **kwargs):
        return self.func(*self.args, *args, **self.kwargs, **kwargs)

용도:

def add(x, y):
    return x + y

inc = partial(add, y=1)
print(inc(41))  # 42

이것은 너무 늦었지만 저는 예를 들고 있습니다.당신이 가지고 있다고 상상해보세요.Vector과 a 래스와aPoint수업. 둘다 수강x, y'▁to▁▁you벡터에 넣을 점을 이동하는 함수를 만들고 싶다고 가정해 보겠습니다.

4가지 솔루션

  • put_point_on_vec(point, vec)

  • 벡터 클래스의 메소드로 만듭니다.예를 들면 my_vec.put_point(point)

  • 에서 메소드로 만듭니다.Point학급.my_point.put_on_vec(vec)
  • Vector__call__ 이게사용됩면니다시하렇됩니▁it처럼 사용할 수 .my_vec_instance(point)

이것은 사실 제가 연구하고 있는 몇 가지 예시의 일부입니다. 제가 조만간 발표할 수학과 함께 설명된 바보 같은 방법에 대한 가이드입니다.

이것은 이 질문에 대한 것이 아니기 때문에 포인트 자체를 이동하는 논리를 남겼습니다.

함수 호출 연산자입니다.

class Foo:
    def __call__(self, a, b, c):
        # do something

x = Foo()
x(1, 2, 3)

__call__ 메서드를 사용하여 동일한 개체를 다시 정의/재초기화할 수 있습니다.또한 개체에 인수를 전달하여 클래스의 인스턴스/개체를 함수로 쉽게 사용할 수 있습니다.

import random


class Bingo:

def __init__(self,items):
    self._items=list(items)
    random.shuffle(self._items,random=None)


def pick(self):
    try:
        return self._items.pop()
    except IndexError:
        raise LookupError('It is empty now!')

def __call__(self):
    return self.pick()

b= Bingo(range(3))
print(b.pick())
print(b())
print(callable(b))

이제 출력은 다음과 같습니다.(처음 두 개의 답이 [0,3] 사이에서 계속 섞이면서)

2

1

진실의


클래스 빙고가 _call_ 메서드를 구현하는 것을 볼 수 있습니다. _call_ 메서드는 빙고의 나머지 항목과 같이 호출 간에 유지되어야 하는 내부 상태를 가진 객체와 같은 함수를 만드는 쉬운 방법입니다._call_의 또 다른 유용한 사용 사례는 데코레이터입니다.장식가는 호출 가능해야 하며 때때로 장식가의 호출 사이에 무언가를 "기억"하는 것이 편리합니다. (즉, 메모화 - 나중에 사용하기 위해 값비싼 계산 결과를 캐싱)

언급URL : https://stackoverflow.com/questions/5824881/python-call-special-method-practical-example

반응형