absl

About_work·2023년 4월 18일
1

absl

목록 보기
1/1

설명

  • ABSL은 "Abseil Standard Library"의 약자로, Google에서 개발한 C++ 코드 라이브러리의 Python 버전
  • 다양한 유틸리티 함수, 데코레이터 및 모듈을 제공

사용 목적

  • 코드의 가독성 향상
    • ABSL은 Python 코드를 작성할 때 일반적으로 필요한 반복적인 작업을 줄여줌
    • 코드의 가독성이 향상되고, 더 나은 유지 보수가 가능해집니다.
  • 테스트 가능성
    • ABSL은 유닛 테스트를 쉽게 작성하고 실행할 수 있도록 다양한 기능을 제공
    • 이를 통해 코드의 안정성과 신뢰성을 높일 수 있습니다.
  • 성능 개선
    • ABSL은 Python 코드의 성능을 개선하는 다양한 기능을 제공
    • 예를 들어,
      • 컬렉션을 처리할 때 최적화된 함수를 제공하거나,
      • 비동기 프로그래밍을 쉽게 작성할 수 있는 기능을 제공

absl.flag VS argparse

  • absl.flag의 장점

    • 복잡한 cli parsing 생략 (개인적으로 제일 중요)
    • flag 추가를 각 모듈에서 추가
      • (중복 이름에 대해 import 레벨에서 에러 raise)
    • 추후 파일 지원 시, 파일 < cli 설정 값 < 외부 서비스 입력 값 을 판단할 때, 이게 cli 입력 값인지 flag 기본값인지 구분이 필요 (present 기능)
  • argparse 처럼 유연하지는 않습니다. (거의 raw level api라서 argparse만큼 유연한 물건은 없습니다)

    • 자주 사용하는 패턴 및 parsing을 쉽게 제공하는 wrapper 정도로 생각해 두시면 됩니다.
    • 런 타임에 바꾸는 목적으로 사용하지는 않습니다.
  • import 레벨에서만 원하는대로 동작 합니다. (우회 가능은 하나, 그 방법이 나름 복잡하여)

    • 함수나 메소드를 통해 dyn 추가 / 변경하기 위해서는 app.run 호출 이전에 해야만 합니다.
    • flag 추가는 불가하나, 값 변경은 아무 때나 가능합니다. (단 mp 일때는 조심 필요, 아래 참고)
  • multi-processing의 경우, python mp 특성에 의해 부모거를 fork 해서 사용합니다.

    • 부모 프로세스에 parsing된 값을 그대로 읽음
    • 부모에서 mp create 이후, 수정한 값에 대해서는 동기화 안됨
  • rpc 는 안 될듯 합니다.

    • pickle serialization 미지원.
    • command cli 값을 mp / remote에서 그대로 읽는 경우가 있을까? 라는 의문은 있습니다.

단점

  • 다른 라이브러리와 충돌할 가능성이 있습니다.
  • 일부 기능이 Python의 기본 라이브러리와 중복됩니다.

사용법

pip install absl-py

logging

  • ABSL의 logging 모듈은 Python 기본 라이브러리의 logging 모듈보다 더욱 직관적이고 편리한 로깅 기능을 제공
from absl import logging

logging.info('This is an informational log.')
logging.warning('This is a warning log.')
logging.error('This is an error log.')

Flags

  • absl.flags는 커맨드 라인 인자를 처리하기 위한 라이브러리
  • ABSL의 flags 모듈은 Python 코드의 실행 시점에 옵션(option)을 제공합니다.
  • flags 모듈을 사용하면 코드를 작성할 때
    • 실행 시점에 필요한 값을 하드코딩할 필요 없이, 옵션으로 전달할 수 있습니다.
from absl import flags

FLAGS = flags.FLAGS

# flags.DEFINE_integer:
# Python 스크립트에서 정수형 값을 명령행 인자나 환경 변수로부터 가져올 때 사용됩니다.
flags.DEFINE_integer('num_epochs', 10, 'Number of epochs for training.')
flags.DEFINE_float('learning_rate', 0.01, 'Learning rate for training.')

print(FLAGS.num_epochs)
print(FLAGS.learning_rate)
DEFINE_enum
  • 기존의 enum 타입을 사용할 때 사용

  • DEFINE_enum 함수는 기존의 enum 타입을 사용하는 경우에 사용됩니다.

  • 이를 통해 absl.flags는 해당 enum 타입의 인스턴스를 생성하고, 해당 인스턴스를 사용하여 커맨드 라인에서 받은 값을 enum 타입으로 변환합니다.

  • 예를 들어, 다음은 Color라는 enum 타입을 DEFINE_enum 함수를 사용하여 정의하는 예제 코드입니다.

from absl import flags

FLAGS = flags.FLAGS

# Color enum 정의
class Color(enum.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

# Color enum 인자 등록
flags.DEFINE_enum(
    name='color', default='RED', enum_values=['RED', 'GREEN', 'BLUE'],
    help='The color to use.')
  • name: 커맨드 라인 인자의 이름을 지정하는 문자열입니다. 이 이름은 커맨드 라인에서 인자를 지정할 때 사용됩니다.
  • default: 커맨드 라인 인자의 기본값으로 사용되는 enum 타입의 인스턴스입니다.
  • enum_values: enum 타입에서 사용 가능한 값들을 나열하는 문자열 리스트입니다.
  • help: 인자에 대한 도움말 메시지입니다.
DEFINE_enum_class
  • 새로운 enum 타입을 정의할 때 사용
  • DEFINE_enum_class 함수는 새로운 enum 타입을 정의하고,
  • 해당 타입에 정의된 값의 이름과 값에 대한 설명을 나열하는 문자열 리스트를 받아들입니다.
  • 이를 통해 absl.flags는 해당 enum 타입의 인스턴스를 생성하고, 해당 인스턴스를 사용하여 커맨드 라인에서 받은 값을 enum 타입으로 변환합니다.
  • 예를 들어, 다음은 Color라는 enum 타입을 DEFINE_enum_class 함수를 사용하여 정의하는 예제 코드입니다.
from absl import flags

FLAGS = flags.FLAGS

# Color enum class 정의
class Color(flags.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

# Color enum 인자 등록
flags.DEFINE_enum_class(
    name='color', default=Color.RED, enum_class=Color,
    help='The color to use.')
  • name: 커맨드 라인 인자의 이름을 지정하는 문자열입니다. 이 이름은 커맨드 라인에서 인자를 지정할 때 사용됩니다.
  • default: 커맨드 라인 인자의 기본값으로 사용되는 enum 타입의 인스턴스입니다.
  • enum_class: 새로운 enum 타입을 정의하는 데 사용되는 enum.Enum의 하위 클래스입니다.
  • help: 인자에 대한 도움말 메시지입니다.

Testing

from absl.testing import absltest

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

class AddTest(absltest.TestCase):

    def test_add(self):
        self.assertEqual(add(1, 2), 3)
        self.assertEqual(add(2, 3), 5)

if __name__ == '__main__':
    absltest.main()
  • flagsaver
    • 플래그(flag)를 저장하고, 테스트 후에 다시 복원하는 기능을 제공합니다.
    • 이를 통해, 테스트 중에 변경된 플래그 값을 -> 다시 원래 값으로 복원하여 다른 테스트에 영향을 미치지 않도록 할 수 있습니다.
from absl.testing import absltest, flagsaver

FLAGS = flags.FLAGS

class MyTest(absltest.TestCase):

    def test_func1(self):
        FLAGS.my_flag = True
        self.assertTrue(FLAGS.my_flag)

    def test_func2(self):
        self.assertFalse(FLAGS.my_flag)
from absl.testing import absltest, flagsaver

FLAGS = flags.FLAGS

class MyTest(absltest.TestCase):

    @flagsaver.flagsaver
    def test_func1(self):
        FLAGS.my_flag = True
        self.assertTrue(FLAGS.my_flag)

    @flagsaver.flagsaver
    def test_func2(self):
        self.assertFalse(FLAGS.my_flag)

flagsaver.as_parsed, flagsaver.flagsaver

  • flagsaver.as_parsed
    • 현재 플래그 값을 파싱하고, 그 값을 argparse.Namespace 형식으로 반환
    • 이 방법은 현재 설정된 플래그 값이 무엇인지 확인하고자 할 때 사용
    • 이 메소드는 명령행 인자나 환경 변수를 사용하여 설정된 현재 플래그 값을 파싱하여 다른 함수나 모듈에서 사용하기 쉽게 만들어 줍니다.
    • argparse.Namespace
      • argparse 모듈에서 사용되는 간단한 클래스
      • 이 클래스는 인스턴스의 attribute을 사용하여 값을 저장하고, 이를 손쉽게 검색하고 수정할 수 있도록 합니다.
      • argparse.Namespace 클래스는 일반적으로 명령행 인자를 파싱하여 얻은 인자들을 저장하는 데 사용됩니다.
      • 예를 들어, 다음과 같이 인자를 파싱하면 argparse.Namespace 형식으로 반환됩니다.
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--num_iterations', type=int, default=10, help='number of iterations')
args = parser.parse_args() # args: argparse.Namespace 인스턴스

print(args.num_iterations)
  • flagsaver.flagsaver
    • 현재 플래그 값을 저장하고, 특정 플래그 값을 새로운 값으로 설정한 뒤 함수가 끝나면 이전 값으로 복원
from absl import flags
from absl.flags import FLAGS
from absl.flags import argparse_flags
from absl.flags import flagsaver

FLAGS = flags.FLAGS

def main(argv):
    # `num_iterations` 값을 100으로 설정하고, 이전 값을 저장함
    with flagsaver.flagsaver():
        FLAGS.num_iterations = 100

    # 현재 플래그 값을 파싱하여 `argparse.Namespace` 형식으로 반환함
    parsed_flags = flagsaver.as_parsed()

    # `num_iterations` 값을 출력함
    print(parsed_flags.num_iterations)

if __name__ == '__main__':
    app.run(main)

App

  • Python 코드를 실행할 때 필요한 기능을 제공
from absl import app

def main(argv):
    print('Hello, world!')

if __name__ == '__main__':
    app.run(main)

flags.FLAGS

  • absl.flags는 커맨드 라인 인자를 처리하기 위한 라이브러리
  • absl.flags.FLAGS = absl.flags 모듈에서 정의된 전역 변수(global variable)
  • 아래의 값을 저장하는 전역 변수 객체
    • 프로그램 실행 시점에 사용자가 정의한 명령행 인자(command line arguments)
    • 프로그램 내부에서 사용되는 옵션(option)의 값
from absl import app, flags

FLAGS = flags.FLAGS

flags.DEFINE_string('input_file', None, 'Input file path')
flags.DEFINE_string('output_file', None, 'Output file path')

def main(argv):
    with open(FLAGS.input_file, 'r') as f:
        content = f.read()
    with open(FLAGS.output_file, 'w') as f:
        f.write(content)

if __name__ == '__main__':
    app.run(main)
python example.py --input_file=input.txt --output_file=output.txt

flags.FlagValues

  • flags.FLAGS 객체 = flags.FlagValues 클래스의 인스턴스
  • flags.FlagValues 클래스
    • 옵션(option)의 정의와 등록
    • 옵션 값의 저장과 복원
    • 옵션 값의 파싱
  • 즉, flags.FlagValues 클래스는 flags.FLAGS 객체가 사용하는 옵션(option)을 관리하는 데 사용되며,
    • 이를 통해 프로그램 실행 시점에, 명령행 인자나 프로그램 내부에서 사용되는 옵션 값을 읽어올 수 있습니다.
from absl import flags

flags_obj = flags.FlagValues()

flags_obj.DEFINE_string('input_file', None, 'Input file path')
flags_obj.DEFINE_string('output_file', None, 'Output file path')

flags_obj.FLAGS.input_file = 'input.txt'
flags_obj.FLAGS.output_file = 'output.txt'
profile
새로운 것이 들어오면 이미 있는 것과 충돌을 시도하라.

0개의 댓글