블로그 이미지
Peter Note
AI & Web FullStacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2024. 8. 25. 19:55 LLM FullStacker/Python

with get_openai_callback() as cb:는 Python의 컨텍스트 관리자(context manager)를 사용하여 get_openai_callback 함수가 반환하는 객체(cb)를 생성하고, 그 객체를 사용하는 블록을 정의하는 구문입니다. 이 구문을 이해하기 위해서는 Python의 컨텍스트 관리자가 어떻게 작동하는지와 get_openai_callback이 어떤 역할을 하는지를 아는 것이 중요합니다.

 

1. 컨텍스트 관리자 (Context Manager)

 

컨텍스트 관리자는 with 블록의 시작과 종료 시 특정 코드를 자동으로 실행하게 해줍니다. 일반적으로, 컨텍스트 관리자는 자원(resource)을 할당하고 해제하는 작업에 사용됩니다. 예를 들어, 파일을 열고 작업을 한 후 자동으로 파일을 닫는 데 사용할 수 있습니다.

 

__enter__(): with 블록이 시작될 때 호출됩니다. 이 메서드는 일반적으로 어떤 자원을 할당하거나 초기화합니다.

__exit__(): with 블록이 끝날 때 호출됩니다. 이 메서드는 자원을 해제하거나, 예외가 발생했을 때 이를 처리합니다.

 

2. get_openai_callback의 역할

 

get_openai_callback은 OpenAI API 호출과 관련된 메트릭을 수집하는 콜백 객체를 반환합니다. 이 콜백 객체는 컨텍스트 관리자에서 사용될 때 API 호출 동안의 토큰 사용량, 비용 등을 추적합니다.

 

3. with get_openai_callback() as cb:의 의미

 

get_openai_callback()은 컨텍스트 관리자 역할을 하는 객체를 반환합니다.

with 블록이 시작되면, cb 변수에 이 객체가 할당됩니다.

with 블록 내에서 OpenAI API 호출이 이루어지면, cb 객체는 API 호출 관련 데이터를 수집합니다.

with 블록이 종료되면, cb 객체는 수집한 데이터를 자동으로 정리하고, 필요한 경우 자원을 해제합니다.

 

예시 코드 분석

from langchain.llms import OpenAI
from langchain.callbacks import get_openai_callback

llm = OpenAI(model="text-davinci-003")

with get_openai_callback() as cb:
    response = llm("What is the capital of France?")
    print(response)
    print(f"Total Tokens: {cb.total_tokens}")
    print(f"Total Cost: {cb.total_cost}")

get_openai_callback(): 콜백 객체를 생성하여 반환합니다.

with ... as cb:: cb 변수에 콜백 객체를 할당하고, with 블록 내에서 이 객체를 사용합니다.

cb.total_tokens, cb.total_cost: with 블록이 끝난 후, API 호출 동안 사용된 총 토큰 수와 총 비용을 출력합니다.

 

이 구문을 사용함으로써 개발자는 OpenAI API 호출의 성능을 모니터링하고 리소스 사용량을 효율적으로 관리할 수 있습니다.

 

get_openai_callback

소스: langchain_community/callbacks/manager.py

from contextlib import contextmanager

@contextmanager
def get_openai_callback() -> Generator[OpenAICallbackHandler, None, None]:
    """Get the OpenAI callback handler in a context manager.
    which conveniently exposes token and cost information.

    Returns:
        OpenAICallbackHandler: The OpenAI callback handler.

    Example:
        >>> with get_openai_callback() as cb:
        ...     # Use the OpenAI callback handler
    """
    cb = OpenAICallbackHandler()
    openai_callback_var.set(cb)
    yield cb
    openai_callback_var.set(None)
posted by Peter Note
2024. 8. 14. 17:07 LLM FullStacker/Python

Pydantic은 Python에서 데이터 유효성 검사 및 설정 관리를 위한 라이브러리입니다. 주로 FastAPI와 같은 웹 프레임워크와 함께 사용되며, 데이터를 구조화하고 검증하는 데 유용합니다. BaseModel은 Pydantic의 핵심 클래스 중 하나로, 데이터 모델을 정의하는 데 사용됩니다.

 

Pydantic의 주요 기능

 

1. 유효성 검사 및 변환: 필드에 대해 타입을 지정하면, 입력 데이터가 자동으로 그 타입으로 변환되며, 유효성 검사가 수행됩니다.

2. 자동 완성 및 타입 힌팅 지원: IDE의 자동 완성과 타입 힌팅을 통해 개발 생산성을 높입니다.

3. 데이터 직렬화 및 역직렬화: 모델 인스턴스를 JSON으로 직렬화하거나 JSON으로부터 역직렬화할 수 있습니다.

4. 데이터 검증 오류 관리: 잘못된 데이터를 입력하면, Pydantic이 자동으로 유효성 검사 오류를 생성합니다.

 

BaseModel 사용 예시

 

다음은 PydanticBaseModel을 사용하여 간단한 사용자 데이터를 관리하는 예제입니다.

from pydantic import BaseModel, EmailStr, Field
from typing import Optional

class User(BaseModel):
    id: int
    name: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    age: Optional[int] = Field(None, ge=18)
    is_active: bool = True

# Example usage
user_data = {
    "id": 1,
    "name": "John Doe",
    "email": "johndoe@example.com",
    "age": 25,
}

user = User(**user_data)
print(user)
print(user.dict())

 

코드 설명

 

1. 필드 정의:

id: 정수형 필드.

name: 길이가 3에서 50 사이인 문자열 필드.

email: 이메일 형식의 문자열을 요구하는 필드. EmailStr 타입은 이메일 주소가 올바른 형식인지 검증합니다.

age: 선택적 필드로, 값이 주어지면 18 이상이어야 합니다.

is_active: 기본값이 True인 불리언 필드.

2. 필드 유효성 검사:

Field를 사용하여 각 필드에 대한 추가적인 제약 조건을 지정합니다.

3. 데이터 생성 및 출력:

user_data 딕셔너리를 통해 User 객체를 생성합니다. 생성된 객체를 출력하거나, .dict() 메서드를 사용하여 객체를 딕셔너리 형태로 변환할 수 있습니다.

 

이와 같이 Pydantic을 사용하면 데이터 모델을 간단하고 명확하게 정의할 수 있으며, 자동으로 타입 변환과 유효성 검사를 수행할 수 있습니다. 이를 통해 데이터 처리의 신뢰성과 안정성을 높일 수 있습니다.

 

 

 

BaseModel은 자동으로 __init__ 을 실행

Pydantic의 BaseModel을 사용하면 클래스 수준에서 필드를 정의할 수 있으며, 이러한 필드는 마치 __init__ 메서드에서 self.name과 같이 인스턴스 변수로 설정된 것처럼 동작합니다. Pydantic은 이러한 필드를 기반으로 자동으로 __init__ 메서드를 생성하고, 필드에 대한 타입 검사를 수행합니다.

 

이 방식은 일반적인 Python 클래스에서의 인스턴스 변수 설정과는 약간 다릅니다. 일반 Python 클래스에서는 인스턴스 변수를 __init__ 메서드 내에서 self를 통해 설정해야 하지만, Pydantic의 BaseModel을 사용하면 클래스 정의 시 필드의 타입과 기본값을 지정하여 더 간결하고 명확하게 모델을 정의할 수 있습니다.

 

예시 비교

 

일반 Python 클래스

class User:
    def __init__(self, id: int, name: str, email: str, age: int, is_active: bool = True):
        self.id = id
        self.name = name
        self.email = email
        self.age = age
        self.is_active = is_active

 

Pydantic BaseModel

from pydantic import BaseModel, EmailStr, Field
from typing import Optional

class User(BaseModel):
    id: int
    name: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    age: Optional[int] = Field(None, ge=18)
    is_active: bool = True

 

차이점 설명

 

일반 클래스에서는 __init__ 메서드 내에서 self를 사용하여 인스턴스 변수를 직접 설정합니다.

Pydantic BaseModel에서는 클래스 정의 시 필드를 직접 설정하고, Pydantic이 자동으로 __init__ 메서드를 생성하여 필드 초기화, 타입 검사, 유효성 검사를 수행합니다.

 

이렇게 Pydantic의 BaseModel을 사용하면 코드가 더 간결해지며, 데이터 유효성 검사가 자동으로 처리되므로 안전하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

posted by Peter Note
2024. 8. 11. 15:48 LLM FullStacker/Python

Python에서 패키지(package)와 모듈(module)은 모두 코드를 조직화하고 재사용성을 높이기 위해 사용되는 구조적 요소입니다. 이 둘은 Python 코드베이스를 더 잘 구조화하고 관리하기 위한 단위이지만, 각각 다른 개념을 나타냅니다.

 

모듈 (Module)

 

모듈은 Python 코드의 파일로, 함수, 클래스, 변수, 또는 다른 코드 블록들이 포함된 단위입니다.

각 모듈은 .py 확장자를 가진 파일로 저장되며, 이 파일의 이름이 모듈의 이름이 됩니다.

모듈은 다른 모듈에서 import 문을 사용하여 불러올 수 있습니다.

 

예시

# my_module.py
def greet(name):
    return f"Hello, {name}!"

# 다른 파일에서 모듈을 불러오기
import my_module

print(my_module.greet("Alice"))  # 출력: Hello, Alice!

위의 예에서 my_module.py 파일이 모듈입니다. 이 모듈은 greet라는 함수를 포함하고 있으며, 다른 Python 파일에서 import를 통해 이 함수를 사용할 수 있습니다.

 

패키지 (Package)

 

패키지는 여러 모듈을 포함할 수 있는 디렉토리로, Python에서는 __init__.py 파일을 포함한 디렉토리를 패키지로 인식합니다.

패키지는 서브 모듈을 계층적으로 조직할 수 있게 해줍니다. 즉, 패키지 안에 또 다른 패키지를 포함하여 하위 모듈을 관리할 수 있습니다.

__init__.py 파일은 해당 디렉토리를 패키지로 인식하게 합니다. Python 3.3 이후로는 이 파일이 없어도 패키지로 인식되지만, 여전히 패키지 초기화 작업을 위해 종종 사용됩니다.

 

예시

my_package/
    __init__.py
    module1.py
    module2.py
    sub_package/
        __init__.py
        module3.py

위의 구조에서 my_package는 패키지입니다. 이 패키지에는 module1.pymodule2.py라는 두 개의 모듈과, sub_package라는 하위 패키지가 포함되어 있습니다. 하위 패키지 sub_package에는 module3.py라는 모듈이 포함되어 있습니다.

 

이러한 구조에서는 다음과 같이 모듈을 가져올 수 있습니다:

from my_package import module1
from my_package.sub_package import module3

 

패키지와 모듈의 차이점

 

구조:

    • 모듈은 단일 .py 파일로 구성됩니다.

    • 패키지는 여러 모듈(그리고 하위 패키지)을 포함할 수 있는 디렉토리입니다.

범위:

    • 모듈은 단일 파일에 포함된 코드 단위입니다.

    • 패키지는 모듈과 하위 패키지를 조직화하는 더 큰 단위입니다.

내포 관계:

    • 모듈은 패키지 안에 포함될 수 있습니다.

    • 패키지는 모듈들을 그룹화하는 역할을 하며, 패키지 내에 또 다른 패키지를 포함할 수도 있습니다.

 

 

요약

 

모듈: Python 코드가 담긴 단일 .py 파일. 모듈은 함수, 클래스, 변수 등의 코드를 포함할 수 있으며, 다른 Python 코드에서 import를 통해 재사용할 수 있습니다.

패키지: 모듈들을 조직화하는 디렉토리 구조. 패키지는 모듈과 다른 하위 패키지를 포함할 수 있으며, 패키지로 인식되기 위해서는 일반적으로 __init__.py 파일이 필요합니다.

posted by Peter Note
2024. 8. 11. 15:13 LLM FullStacker/Python

LangChain의 ChatPromptTemplate의 __init__ 인수에 대한 부분을 보다 * 가 중간에 오길래 무언가 궁금해졌다. 

class ChatPromptTemplate(BaseChatPromptTemplate):
    def __init__(
        self,
        messages: Sequence[MessageLikeRepresentation],
        *,
        template_format: Literal["f-string", "mustache", "jinja2"] = "f-string",
        **kwargs: Any,
    ) -> None:

이 코드 스니펫은 Python에서 클래스의 생성자 메소드인 __init__ 메소드를 정의하는 부분입니다. 이 메소드는 객체가 생성될 때 호출되며, 객체를 초기화하는 역할을 합니다. 각 매개변수의 의미를 살펴보면 다음과 같습니다.

 

파라미터 설명

 

1. self:

모든 인스턴스 메소드에서 첫 번째 인수로 self가 사용됩니다. 이는 객체 자신을 참조하며, 생성된 인스턴스에 접근할 수 있게 합니다.

__init__ 메소드 내에서 self를 통해 객체의 속성을 설정할 수 있습니다.

2. messages: Sequence[MessageLikeRepresentation]:

messages는 생성자에 전달되는 첫 번째 인수이며, Sequence 타입으로, MessageLikeRepresentation 타입의 객체들로 이루어진 순차적 자료형입니다.

Sequence는 리스트, 튜플과 같은 순차적 데이터 구조를 포함하는 추상화된 타입입니다. 이 타입 힌트는 messages가 리스트나 튜플과 같은 자료형일 것이라는 것을 의미합니다.

MessageLikeRepresentation은 사용자 정의 클래스이거나, 메시지를 표현하는 타입일 가능성이 있습니다.

3. template_format: Literal["f-string", "mustache", "jinja2"] = "f-string":

template_format는 키워드 인수로, 세 가지 문자열 값 중 하나를 가질 수 있습니다: "f-string", "mustache", "jinja2".

Literal은 Python의 typing 모듈에서 제공하는 기능으로, 특정 값의 집합 중 하나를 선택하도록 제한합니다.

이 인수는 기본값으로 "f-string"을 가지며, 따라서 사용자가 특별히 지정하지 않으면 "f-string"이 사용됩니다.

이 매개변수는 아마도 템플릿을 처리하는 방식을 지정하는 데 사용될 것입니다.

4. **kwargs: Any:

**kwargs는 임의의 추가적인 키워드 인수들을 받아들이는 데 사용됩니다.

kwargs는 딕셔너리 형태로 전달되며, 키는 문자열이고 값은 임의의 타입을 가질 수 있습니다(Any).

**kwargs는 종종 유연성을 제공하여 함수나 메소드가 예상치 못한 추가 인수를 받아들일 수 있게 합니다.

5. -> None:

이 부분은 함수의 반환 타입 힌트를 나타내며, None이 반환됨을 의미합니다.

생성자 메소드인 __init__은 객체를 초기화할 뿐, 별도의 값을 반환하지 않으므로 항상 None을 반환합니다.

 

이 메소드의 역할

 

__init__ 메소드는 객체가 생성될 때 호출되며, messages, template_format, 그리고 추가적인 키워드 인수(kwargs)를 사용하여 객체의 초기 상태를 설정합니다.

messages는 메시지들을 담은 시퀀스 타입의 인수이며, template_format은 메시지를 템플릿으로 처리하는 방식(예: "f-string", "mustache", "jinja2")을 지정합니다.

kwargs는 추가적인 옵션이나 설정을 받아들일 수 있도록 하여 메소드를 유연하게 만듭니다.

 

 

class MyTemplate:
    def __init__(
        self,
        messages: Sequence[str],
        *,
        template_format: Literal["f-string", "mustache", "jinja2"] = "f-string",
        **kwargs: Any,
    ) -> None:
        self.messages = messages
        self.template_format = template_format
        self.options = kwargs

# 사용 예시
template = MyTemplate(
    messages=["Hello, {name}!", "Goodbye, {name}!"],
    template_format="jinja2",
    option1="value1",
    option2="value2"
)

print(template.messages)  # ['Hello, {name}!', 'Goodbye, {name}!']
print(template.template_format)  # 'jinja2'
print(template.options)  # {'option1': 'value1', 'option2': 'value2'}

아래 사용법 3가지 중 마지막번의 사용법임을 알 수 있다. 

 

 

 

* 인수 사용법

함수 정의에서 파라미터 앞에 붙는 *는 여러 가지 의미를 가질 수 있지만, 일반적으로 **위치 인수(variable-length positional arguments)**를 나타내는 데 사용됩니다. 이 기호는 함수가 호출될 때 임의의 개수의 위치 인수를 받아들이도록 하는 역할을 합니다.

 

*의 주요 의미

 

1. 가변 위치 인수 (*args):

함수 정의에서 *args와 같은 형태로 사용되며, 이 함수는 호출 시 여러 개의 위치 인수를 하나의 튜플로 받아들일 수 있습니다.

args는 이름일 뿐이며, 어떤 이름으로도 사용할 수 있습니다.

def example_function(*args):
    print(args)

example_function(1, 2, 3)  # (1, 2, 3)
example_function('a', 'b', 'c')  # ('a', 'b', 'c')

여기서 args는 튜플이며, 함수에 전달된 모든 위치 인수들을 포함합니다.

 

2. 위치 인수 언패킹:

함수 호출 시, 이미 정의된 시퀀스(리스트나 튜플 등)를 개별 위치 인수로 전달할 때 사용됩니다.

def add(a, b, c):
    return a + b + c

numbers = (1, 2, 3)
print(add(*numbers))  # 6

여기서 *numbers는 튜플 numbers를 개별 인수 1, 2, 3으로 언패킹하여 함수에 전달합니다.

 

3. 키워드 전용 인수:

함수 정의에서 *는 특정 위치 이후의 모든 인수들이 키워드 인수로만 전달될 수 있음을 나타냅니다. 즉, 이 인수들은 반드시 키워드=값 형태로 지정해야 합니다.

def example_function(a, b, *, c, d):
    print(a, b, c, d)

example_function(1, 2, c=3, d=4)  # 올바름
# example_function(1, 2, 3, 4)  # 오류: c와 d는 키워드 인수로만 사용 가능

여기서 *cd 인수가 키워드 인수로만 전달되어야 함을 의미합니다.

 

요약

 

*는 함수 정의에서 임의의 개수의 위치 인수를 받아들이거나, 키워드 전용 인수를 지정할 때 사용됩니다.

또한 함수 호출 시 시퀀스를 언패킹하여 개별 위치 인수로 전달할 때도 사용됩니다.

이 기호는 Python의 함수 정의 및 호출에서 매우 유연하고 강력한 기능을 제공합니다.

posted by Peter Note
2024. 8. 11. 14:37 LLM FullStacker/Python

LangChain 소스 코드를 분석하면서 Python도 함께 배우고 있습니다. 이해되지 않는 것으 GPT를 통해 열심히 개념을 알아가고 있습니다.

1. Union에 대한 궁금증

Union은 Python의 타입 힌팅(type hinting)에서 사용되며, 함수의 매개변수나 반환 값이 둘 이상의 서로 다른 타입을 가질 수 있음을 나타낼 때 사용됩니다. Python 3.10 이전에는 typing 모듈의 Union을 사용했으며, Python 3.10부터는 더 간단한 | 연산자를 사용하여 동일한 기능을 제공할 수 있습니다.

 

예시

 

1. Python 3.9 이하에서의 Union 사용:

from typing import Union

def process_value(value: Union[int, float]) -> Union[int, float]:
    return value * 2

이 함수 process_valueintfloat 타입의 값을 받아서 두 배로 증가시킨 후 반환합니다. 반환 값도 intfloat이 될 수 있음을 Union을 통해 명시하고 있습니다.

 

2. Python 3.10 이후에서의 | 연산자 사용:

def process_value(value: int | float) -> int | float:
    return value * 2

 

위와 동일한 기능을 | 연산자를 사용하여 간단히 표현할 수 있습니다.

 

Union 사용이 적합한 경우

 

다양한 타입을 처리할 때: 함수나 메소드가 여러 타입을 받을 수 있고, 그 타입에 따라 다르게 동작할 때 Union을 사용합니다.

점진적 타입 검사를 통해 오류를 줄일 때: 코드에 타입 힌트를 명확히 하여, 코드의 가독성과 안정성을 높이고, 코드 편집기나 정적 분석 도구가 더 나은 오류 검출을 할 수 있도록 도울 수 있습니다.

 

주의사항

 

Union을 사용할 때, 가능한 한 사용 범위를 좁히는 것이 좋습니다. 너무 많은 타입을 허용하면 코드가 복잡해지고 유지보수가 어려워질 수 있습니다.

 

Union은 주로 함수의 입력과 출력에 다양한 타입을 허용할 때 매우 유용한 도구입니다. 필요에 따라 적절히 사용하는 것이 중요합니다.

 


 

2. ininstance 에 대한 궁금증

isinstance는 Python에서 특정 객체가 특정 클래스나 타입의 인스턴스인지 확인할 때 사용되는 내장 함수입니다. 이 함수는 객체와 클래스(또는 클래스의 튜플)를 인수로 받아, 객체가 해당 클래스의 인스턴스이거나 그 클래스의 서브클래스의 인스턴스인 경우 True를 반환하고, 그렇지 않으면 False를 반환합니다.

 

isinstance의 기본 사용법

result = isinstance(object, classinfo)

object: 타입을 확인하려는 객체.

classinfo: 클래스, 클래스의 튜플, 또는 타입들.

 

예시

 

1. 단일 클래스에 대한 검사:

# 객체가 정수형인지 확인
x = 10
print(isinstance(x, int))  # True

 

2. 여러 클래스에 대한 검사:

# 객체가 정수형 또는 실수형인지 확인
x = 10.5
print(isinstance(x, (int, float)))  # True

 

4. 상속 관계에서의 검사:

class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()
print(isinstance(dog, Animal))  # True
print(isinstance(dog, Dog))     # True

이 예제에서 Dog 클래스는 Animal 클래스를 상속받기 때문에, dog 객체는 Animal 클래스의 인스턴스이기도 합니다.

 

isinstance의 주요 용도

 

타입 확인: 함수나 메소드 내부에서 인수의 타입을 확인하여, 타입에 따라 다른 로직을 수행할 때 유용합니다.

상속 관계 검사: 객체가 특정 클래스에서 파생된 클래스의 인스턴스인지 확인할 수 있습니다.

입력 검증: 함수에 전달된 인수의 타입이 예상한 타입과 일치하는지 검증하여, 타입 오류를 미리 방지할 수 있습니다.

 

isinstance와 type의 차이점

 

isinstance는 상속 관계를 고려하는 반면, type 함수는 객체의 정확한 타입을 확인할 때 사용됩니다. 예를 들어, 상속받은 클래스의 인스턴스는 type을 사용하면 부모 클래스와 매칭되지 않습니다.

class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()

# isinstance를 사용하면 True
print(isinstance(dog, Animal))  # True

# type을 사용하면 False
print(type(dog) == Animal)  # False, Dog != Animal

이와 같이, isinstance는 더 유연하게 타입을 확인할 수 있는 반면, type은 정확한 타입 비교에 사용됩니다.

posted by Peter Note
2024. 8. 11. 14:31 LLM FullStacker/Python

 

1. Dictionary 병합

LangChain 소스를 분석하다 이런 코드를 보았다.

class ChatPromptTemplate(BaseChatPromptTemplate):
    def __init__(
        self,
        messages: Sequence[MessageLikeRepresentation],
        *,
        template_format: Literal["f-string", "mustache", "jinja2"] = "f-string",
        **kwargs: Any,
    ) -> None:
        ...
        // 파이썬 초보자가 봤을 때 이게 뭐지?  
        kwargs = {
            **dict(
                input_variables=sorted(input_vars),
                optional_variables=sorted(optional_variables),
                partial_variables=partial_vars,
            ),
            **kwargs,
        }

이 코드에서 kwargs 변수를 정의하는 방식은 Python에서 딕셔너리를 병합하는 기법 중 하나입니다. 이 코드의 주요 목적은 두 개의 딕셔너리를 결합하여 하나의 딕셔너리를 만드는 것입니다. 여기서 kwargs는 일반적으로 함수나 메소드에서 사용되는 키워드 인수들을 담고 있는 딕셔너리입니다.

코드의 의미 분석

kwargs = {
    **dict(
        input_variables=sorted(input_vars),
        optional_variables=sorted(optional_variables),
        partial_variables=partial_vars,
    ),
    **kwargs,
}
  1. dict(...):
    • dict(...) 표현식은 새로운 딕셔너리를 생성합니다.
    • 이 딕셔너리는 세 개의 키-값 쌍을 가지고 있습니다:
      • input_variables: input_vars를 정렬한 리스트.
      • optional_variables: optional_variables를 정렬한 리스트.
      • partial_variables: partial_vars라는 변수에 담긴 값.
  2. sorted(input_vars)sorted(optional_variables):
    • sorted(input_vars)sorted(optional_variables)는 각각 input_varsoptional_variables 리스트를 정렬한 결과를 반환합니다.
    • 이 결과는 새로운 딕셔너리의 값으로 사용됩니다.
  3. **dict(...):
    • ** 연산자는 딕셔너리 언패킹 연산자입니다. 이 연산자를 사용하면 딕셔너리의 키-값 쌍을 다른 딕셔너리로 풀어서 넣을 수 있습니다.
    • **dict(...)input_variables, optional_variables, partial_variables라는 키와 그에 대응하는 값들을 풀어서 {}로 감싸인 새로운 딕셔너리로 만듭니다.
  4. **kwargs:
    • 기존의 kwargs 딕셔너리도 **kwargs로 언패킹되어 추가됩니다.
    • 이때, 만약 kwargs 딕셔너리에 input_variables, optional_variables, partial_variables와 동일한 키가 존재하면, kwargs 딕셔너리의 값이 우선하여 기존 값을 덮어씁니다.
  5. 최종 kwargs 딕셔너리:
    • 최종적으로, 첫 번째 dict(...)로 생성된 딕셔너리와 기존의 kwargs 딕셔너리가 병합된 새로운 kwargs 딕셔너리가 만들어집니다.
    • 이 딕셔너리는 함수나 메소드에 전달될 키워드 인수들로 사용될 수 있습니다.

예시

input_vars = ['var3', 'var1', 'var2']
optional_variables = ['opt3', 'opt1', 'opt2']
partial_vars = {'part1': 'value1'}

kwargs = {'input_variables': ['override_var'], 'new_key': 'new_value'}

kwargs = {
    **dict(
        input_variables=sorted(input_vars),
        optional_variables=sorted(optional_variables),
        partial_variables=partial_vars,
    ),
    **kwargs,
}

print(kwargs)

위 코드를 실행하면, 최종 kwargs 딕셔너리는 다음과 같이 출력됩니다:

{
    'input_variables': ['override_var'],  # kwargs에서 덮어씌워짐
    'optional_variables': ['opt1', 'opt2', 'opt3'],
    'partial_variables': {'part1': 'value1'},
    'new_key': 'new_value'
}

요약

  • 이 코드는 dict(...)로 만든 딕셔너리와 기존 kwargs 딕셔너리를 병합하여 새로운 kwargs 딕셔너리를 생성합니다.
  • **dict(...)**kwargs를 사용하여 두 딕셔너리를 결합합니다. 중복되는 키가 있을 경우, kwargs에 있는 값이 우선합니다.
  • 이 기법은 키워드 인수를 동적으로 처리할 때 유용합니다.

2. sorted 용법에 대한 궁금증

sorted는 Python의 내장 함수 중 하나로, 주어진 iterable(리스트, 튜플, 문자열 등)의 요소들을 정렬하여 새로운 리스트로 반환하는 함수입니다. sorted는 원본 데이터를 변경하지 않고, 정렬된 새로운 리스트를 반환합니다.

 

sorted 함수의 기본 사용법

sorted(iterable, key=None, reverse=False)

iterable: 정렬할 대상이 되는 iterable 객체(예: 리스트, 튜플, 문자열 등).

key: 정렬 기준을 지정하는 함수. 각 요소에 대해 이 함수가 호출된 결과를 기준으로 정렬합니다.

reverse: True로 설정하면 내림차순으로 정렬하고, 기본값인 False는 오름차순으로 정렬합니다.

 

예시

 

1. 리스트 정렬:

numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
sorted_numbers = sorted(numbers)
print(sorted_numbers)  # [1, 1, 2, 3, 4, 5, 5, 6, 9]

 

2. 문자열 정렬:

word = "python"
sorted_letters = sorted(word)
print(sorted_letters)  # ['h', 'n', 'o', 'p', 't', 'y']

 

3. 튜플 정렬:

tuples = [(1, 'b'), (3, 'a'), (2, 'c')]
sorted_tuples = sorted(tuples)
print(sorted_tuples)  # [(1, 'b'), (2, 'c'), (3, 'a')]

 

4. key 매개변수 사용:

key 매개변수는 정렬 기준을 정의하는 함수입니다. 각 요소에 대해 이 함수가 호출된 결과를 기준으로 정렬됩니다.

words = ["apple", "banana", "cherry", "date"]
sorted_words = sorted(words, key=len)
print(sorted_words)  # ['date', 'apple', 'banana', 'cherry']

 

5. reverse=True 사용:

정렬 결과를 내림차순으로 반환합니다.

numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
sorted_numbers_desc = sorted(numbers, reverse=True)
print(sorted_numbers_desc)  # [9, 6, 5, 5, 4, 3, 2, 1, 1]

 

요약

 

sorted 함수는 iterable의 요소를 정렬하여 새로운 리스트로 반환합니다.

key 매개변수를 사용하여 정렬 기준을 설정할 수 있으며, reverse 매개변수를 사용하여 정렬 방향(오름차순/내림차순)을 설정할 수 있습니다.

원본 데이터는 변경되지 않으며, 정렬된 새로운 리스트가 반환됩니다.


3. cast 에 대한 궁금증

cast는 Python의 타입 힌팅(type hinting)과 관련된 기능 중 하나로, typing 모듈에서 제공하는 함수입니다. cast는 특정 값을 지정된 타입으로 “캐스팅”한다고 표시하는 역할을 합니다. 그러나 실제로 값을 변환하거나 변경하지는 않으며, 주로 타입 힌팅을 통해 코드의 가독성을 높이고, 정적 분석 도구들이 올바른 타입을 추론하도록 돕기 위한 목적으로 사용됩니다.

 

cast의 기본 사용법

from typing import cast

cast(typ, val)

typ: 캐스팅할 타입. Python의 타입(예: int, str, List[int] 등)이나 사용자 정의 클래스 등을 지정할 수 있습니다.

val: 실제 값. typ로 캐스팅할 값입니다.

 

cast의 역할

 

정적 분석 지원: cast는 Python 코드에서 변수나 표현식의 타입을 명시적으로 지정하는 데 사용됩니다. 정적 분석 도구나 IDE에서 코드의 타입을 더 잘 이해하고, 타입 관련 경고나 오류를 감지하는 데 도움이 됩니다.

런타임에는 아무 영향 없음: cast는 런타임에 아무런 영향을 미치지 않습니다. 즉, cast를 사용해도 실제로 값의 타입이 변경되거나 변환되지 않습니다.

 

예시

 

1. 기본 사용법:

from typing import cast, List

def get_items() -> List[str]:
    return ["apple", "banana", "cherry"]

items = cast(List[str], get_items())
print(items)  # ['apple', 'banana', 'cherry']

여기서 cast(List[str], get_items())get_items()의 반환값이 List[str] 타입임을 명시적으로 지정합니다.

 

2. 변수 타입 힌트:

from typing import cast

value: int = cast(int, "42")  # 정적 분석 도구에게 value가 int임을 알려줌
print(value)  # "42", 실제로는 str 타입임

이 예시에서 cast(int, "42")"42"int 타입이라고 명시하지만, 실제로는 str 타입입니다. 이 코드에서 cast는 단지 정적 타입 힌팅을 위한 것이며, value의 타입이 실제로 int로 변환되지 않습니다.

 

3. 사용자 정의 클래스:

from typing import cast

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"

def get_animal() -> Animal:
    return Dog()

animal = cast(Dog, get_animal())
print(animal.speak())  # "Woof!", 정적 분석 도구는 animal을 Dog로 간주함

여기서 cast(Dog, get_animal())get_animal()이 반환하는 객체가 Dog 타입임을 명시적으로 지정하여, animal 변수가 Dog로 간주되도록 합니다. 실제로는 get_animal()이 반환하는 객체가 Dog이기 때문에 문제가 없지만, 정적 분석 도구에 명시적으로 알려주기 위해 사용됩니다.

 

요약

 

cast는 Python에서 타입 힌팅을 명시적으로 지정하기 위한 도구로, 런타임에는 영향을 미치지 않습니다.

주로 정적 분석 도구나 IDE에서 타입 추론을 돕기 위해 사용됩니다.

cast는 값의 실제 타입을 변경하지 않으며, 코드의 가독성과 안전성을 높이는 역할을 합니다.

posted by Peter Note
2024. 8. 11. 14:26 LLM FullStacker/Python

return cls(messages, template_format=template_format)는 Python에서 클래스 메소드나 다른 클래스 내부 메소드에서 새로운 클래스 인스턴스를 생성하여 반환할 때 사용되는 패턴입니다. 이 문장에서 cls는 현재 클래스 자체를 가리키고, messagestemplate_format은 그 클래스의 생성자 __init__ 메소드에 전달되는 인수입니다.

이 코드의 의미

  1. cls:
    • cls는 클래스 메소드 또는 클래스 내부의 다른 메소드에서 해당 클래스 자체를 참조하는 키워드입니다. cls를 사용하면 현재 클래스의 인스턴스를 생성할 수 있습니다.
    • 일반적으로 @classmethod 데코레이터가 붙은 메소드 내에서 사용되며, 이 메소드가 호출될 때 해당 클래스 자체가 첫 번째 인수로 cls에 전달됩니다.
  2. cls(messages, template_format=template_format):
    • 이 구문은 현재 클래스의 인스턴스를 생성하는 표현입니다.
    • messagestemplate_format=template_format은 생성자에 전달되는 인수입니다. 여기서 messages는 위치 인수로, template_format은 키워드 인수로 전달됩니다.
    • 이는 클래스의 __init__ 메소드가 messagestemplate_format이라는 두 개의 인수를 받을 것으로 예상된다는 것을 의미합니다.
  3. return:
    • 새로 생성된 클래스 인스턴스를 반환합니다. 이 반환된 객체는 이 메소드를 호출한 코드에서 사용할 수 있게 됩니다.

예시 코드

아래는 이 패턴이 어떻게 사용되는지에 대한 예시입니다:

class PromptTemplate:
    def __init__(self, messages, template_format=None):
        self.messages = messages
        self.template_format = template_format

    @classmethod
    def from_messages(cls, messages, template_format="default"):
        # 새로운 PromptTemplate 인스턴스를 생성하여 반환
        return cls(messages, template_format=template_format)

# 사용 예시
messages = ["Hello, World!", "How are you?"]
template = PromptTemplate.from_messages(messages, template_format="custom")
print(template.messages)  # ['Hello, World!', 'How are you?']
print(template.template_format)  # 'custom'

요약

  • return cls(messages, template_format=template_format)는 현재 클래스의 인스턴스를 생성하여 반환하는 코드입니다.
  • cls는 해당 클래스 자체를 참조하며, 이 코드 구문은 클래스 메소드 또는 클래스 내부의 다른 메소드에서 새로운 인스턴스를 생성하기 위해 사용됩니다.
  • 이 패턴은 클래스의 __init__ 메소드가 해당 인수들을 받아들일 것으로 예상합니다. 따라서 이 코드가 사용되는 클래스는 __init__ 메소드가 messagestemplate_format을 인수로 받아야 합니다.
posted by Peter Note
2024. 8. 9. 13:25 LLM FullStacker/Python

importfrom 키워드는 파이썬에서 모듈과 그 모듈 내의 특정 항목을 가져오는 데 사용됩니다. 각각의 기능과 사용할 수 있는 것들을 정리하면 다음과 같습니다:

import 키워드

import는 전체 모듈을 가져옵니다. 가져온 모듈의 이름을 통해 해당 모듈에 정의된 함수, 클래스, 변수 등을 사용할 수 있습니다.

import module_name

import로 가져올 수 있는 것들:

  • 파이썬 표준 라이브러리 모듈: 예를 들어, import os, import sys, import math 등.
  • 사용자 정의 모듈: 사용자가 만든 .py 파일을 가져올 수 있습니다. 예를 들어, import my_module.
  • 서드 파티 라이브러리 모듈: 설치된 서드 파티 패키지를 가져올 수 있습니다. 예를 들어, import numpy, import pandas.

from 키워드

from은 모듈 내의 특정 항목을 직접 가져올 때 사용됩니다. 이를 통해 모듈 이름 없이도 해당 항목을 직접 사용할 수 있습니다.

from module_name import specific_item

from으로 정의할 수 있는 것들:

  • 모듈 내의 특정 함수: 예를 들어, from math import sqrtsqrt 함수를 직접 사용할 수 있게 합니다.
  • 모듈 내의 특정 클래스: 예를 들어, from datetime import datetimedatetime 클래스를 직접 사용할 수 있게 합니다.
  • 모듈 내의 특정 변수: 예를 들어, from config import config_valueconfig_value라는 변수를 가져올 수 있게 합니다.
  • 모듈 내의 모든 항목: from module_name import *를 사용하면 모듈 내의 모든 공개된 항목을 가져올 수 있습니다. 하지만, 이 방식은 권장되지 않습니다.

예시

import math  # math 모듈을 가져옴
print(math.sqrt(16))  # math 모듈을 통해 sqrt 함수 호출

from math import sqrt  # math 모듈에서 sqrt 함수만 가져옴
print(sqrt(16))  # 모듈 이름 없이 sqrt 함수 호출

from my_module import my_function  # my_module 모듈에서 my_function 함수만 가져옴
my_function()  # 직접 함수 호출

importfrom 키워드를 적절히 사용하면 코드의 가독성과 효율성을 높일 수 있습니다. written by GPT

posted by Peter Note
2024. 8. 6. 23:13 LLM FullStacker/Python

클래스의 속성을 정의하는 여러 가지 방법을 소개해 드리겠습니다. 파이썬에서 클래스의 속성을 정의하는 방법에는 몇 가지가 있습니다. 각 방법은 특정 상황에서 유용할 수 있습니다.

클래스 변수와 속성의미

1. 클래스 변수 (Class Variables)

클래스 변수는 클래스 자체에 속하며, 모든 인스턴스에서 공유됩니다.

   class MyClass:
       class_variable = "I am a class variable"

   print(MyClass.class_variable)
   obj1 = MyClass()
   obj2 = MyClass()
   print(obj1.class_variable)
   print(obj2.class_variable)

2. 인스턴스 변수 (Instance Variables)

인스턴스 변수는 각 객체마다 개별적으로 유지되며, __init__ 메서드에서 초기화됩니다.

   class MyClass:
       def __init__(self, value):
           self.instance_variable = value

   obj1 = MyClass(1)
   obj2 = MyClass(2)
   print(obj1.instance_variable)  # 1
   print(obj2.instance_variable)  # 2

3. 프로퍼티 (Properties)

프로퍼티는 getter와 setter 메서드를 사용하여 속성의 접근 및 수정 방법을 제어할 수 있습니다.

   class MyClass:
       def __init__(self, value):
           self._value = value

       @property
       def value(self):
           return self._value

       @value.setter
       def value(self, new_value):
           if new_value < 0:
               raise ValueError("Value cannot be negative")
           self._value = new_value

   obj = MyClass(10)
   print(obj.value)  # 10
   obj.value = 20
   print(obj.value)  # 20
   # obj.value = -10  # ValueError 발생

4. 데코레이터를 사용한 클래스 속성 정의

@classmethod@staticmethod 데코레이터를 사용하여 클래스 메서드 및 정적 메서드를 정의할 수 있습니다.

   class MyClass:
       class_variable = 0

       @classmethod
       def increment_class_variable(cls):
           cls.class_variable += 1

       @staticmethod
       def static_method():
           print("This is a static method")

   MyClass.increment_class_variable()
   print(MyClass.class_variable)  # 1
   MyClass.static_method()  # This is a static method

5. 데이터 클래스 (Data Classes)

파이썬 3.7부터 도입된 데이터 클래스는 기본적인 속성 및 메서드를 자동으로 생성해줍니다.

   from dataclasses import dataclass

   @dataclass
   class MyClass:
       attribute1: int
       attribute2: str

   obj = MyClass(1, "hello")
   print(obj.attribute1)  # 1
   print(obj.attribute2)  # hello

이와 같은 방법들을 통해 파이썬 클래스의 속성을 정의하고 사용할 수 있습니다. 각 방법은 특정 상황에서 유용하며, 필요에 따라 적절한 방법을 선택하여 사용할 수 있습니다.


인스턴스 변수 와 속성의 차이점

클래스의 인스턴스 변수와 속성은 비슷하지만, 약간의 차이점이 있습니다. 인스턴스 변수는 클래스의 각 인스턴스에서 개별적으로 유지되는 데이터를 의미하며, 속성은 주로 접근 제어 및 추가적인 로직을 포함하는 특수한 메서드를 통해 접근되는 데이터를 의미합니다. 여기서 두 개념의 차이점을 더 자세히 설명하겠습니다.

인스턴스 변수 (Instance Variables)

인스턴스 변수는 클래스의 각 인스턴스마다 독립적으로 존재하는 변수를 의미합니다. 이는 보통 __init__ 메서드 내에서 정의되며, 직접적으로 접근하고 수정할 수 있습니다.

예시:

class MyClass:
    def __init__(self, value):
        self.instance_variable = value  # 인스턴스 변수

obj = MyClass(10)
print(obj.instance_variable)  # 10
obj.instance_variable = 20
print(obj.instance_variable)  # 20

속성 (Properties)

속성은 메서드를 통해 간접적으로 접근하고 수정할 수 있는 인스턴스 변수와 비슷한 개념입니다. 속성은 @property 데코레이터를 사용하여 정의되며, 이로 인해 getter, setter, deleter 메서드를 통해 접근과 수정이 가능합니다. 속성은 접근 제어, 유효성 검사, 추가 로직을 추가하는 데 유용합니다.

예시:

class MyClass:
    def __init__(self, value):
        self._value = value  # 실제 데이터를 저장하는 변수 (보통 이름 앞에 _를 붙임)

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        if new_value < 0:
            raise ValueError("Value cannot be negative")
        self._value = new_value

obj = MyClass(10)
print(obj.value)  # 10
obj.value = 20
print(obj.value)  # 20
# obj.value = -10  # ValueError 발생

주요 차이점

  1. 직접 접근 vs 간접 접근:
    • 인스턴스 변수는 직접 접근하고 수정할 수 있습니다 (obj.instance_variable).
    • 속성은 간접적으로 접근하고 수정할 수 있으며, 접근 메서드를 통해 제어됩니다 (obj.value).
  2. 추가 로직:
    • 인스턴스 변수는 단순히 데이터를 저장합니다.
    • 속성은 getter, setter 메서드를 통해 접근 로직을 추가할 수 있습니다 (예: 유효성 검사, 로그 작성).
  3. 읽기 전용 속성:
    • 인스턴스 변수는 읽기/쓰기가 자유롭습니다.
    • 속성은 @property만 정의하면 읽기 전용으로 만들 수 있습니다. (setter를 정의하지 않음)

결론

인스턴스 변수는 클래스 인스턴스의 데이터를 저장하는 데 사용되며, 속성은 데이터를 보호하고 접근을 제어하기 위해 사용됩니다. 속성은 특히 추가적인 로직이 필요한 경우 유용합니다.

posted by Peter Note
2024. 8. 4. 15:16 LLM FullStacker/Python

1) 클래스내에서 사용하는 경우

__getattr__ 메서드는 Python에서 객체의 속성에 접근할 때 호출되는 특별 메서드입니다. 객체의 속성을 조회할 때 해당 속성이 존재하지 않으면 __getattr__ 메서드가 호출됩니다. 이는 동적 속성 접근을 가능하게 하며, 클래스에서 존재하지 않는 속성에 대한 요청을 처리할 수 있습니다.

__getattr__의 의미와 사용법

  • 의미: __getattr__은 객체에서 속성에 접근할 때 해당 속성이 존재하지 않는 경우 호출됩니다. 이는 객체의 속성을 동적으로 생성하거나 계산된 속성을 반환하는 데 유용합니다.
  • 사용법: __getattr__ 메서드는 클래스 내부에 정의되며, 단 하나의 매개변수를 가집니다. 이 매개변수는 존재하지 않는 속성의 이름을 나타내는 문자열입니다. 이 메서드는 존재하지 않는 속성에 대해 반환할 값을 반환해야 합니다.

예시 코드

아래는 __getattr__ 메서드를 사용하여 동적으로 속성을 생성하는 예시입니다:

from typing import Any

class DynamicAttributes:
    def __init__(self):
        self.existing_attribute = "This attribute exists"

    def __getattr__(self, name: str) -> Any:
        """
        This method is called when an attribute is not found.

        Args:
            name (str): The name of the attribute that is being accessed.

        Returns:
            Any: The value to return for the non-existing attribute.
        """
        return f"The attribute '{name}' does not exist, but here is a default value."

# Example usage:
obj = DynamicAttributes()
print(obj.existing_attribute)  # Output: This attribute exists
print(obj.non_existing_attribute)  # Output: The attribute 'non_existing_attribute' does not exist, but here is a default value.

주요 포인트

  1. 속성이 존재하는 경우: __getattr__는 호출되지 않습니다. 예를 들어, obj.existing_attribute에 접근하면 __getattr__가 호출되지 않고, existing_attribute의 실제 값이 반환됩니다.
  2. 속성이 존재하지 않는 경우: __getattr__가 호출됩니다. 예를 들어, obj.non_existing_attribute에 접근하면, __getattr__가 호출되어 해당 속성의 이름을 인수로 받아 반환값을 제공합니다.
  3. 반환값: __getattr__ 메서드는 호출된 속성에 대해 반환할 값을 반환해야 합니다. 이 값은 문자열, 숫자, 객체 등 어떤 유형도 될 수 있습니다.

요약

__getattr__ 메서드는 Python 객체에서 존재하지 않는 속성에 대한 접근을 처리하기 위한 메서드입니다. 이 메서드를 사용하면 동적 속성 접근, 계산된 속성 반환, 기본값 제공 등의 작업을 수행할 수 있습니다. 이를 통해 객체의 유연성을 높이고, 동적으로 속성을 관리할 수 있습니다.


2) init.py 파일 내에서 사용

__init__.py 파일에 __getattr__ 메서드를 정의하는 것은 패키지 수준에서의 동적 속성 접근을 가능하게 합니다. 이 메서드를 사용하면 모듈 또는 패키지에서 존재하지 않는 속성에 접근할 때 동적 동작을 정의할 수 있습니다.

패키지 수준에서의 __getattr__ 사용 예시

Python 3.7부터 패키지의 __init__.py 파일에 __getattr__를 정의할 수 있습니다. 이를 통해 패키지에서 존재하지 않는 속성에 접근할 때 원하는 동작을 수행할 수 있습니다.

예시: 동적 속성 접근

다음은 mypackage라는 패키지에서 __getattr__를 정의하는 예시입니다:

mypackage/
    __init__.py
    module1.py
    module2.py

__init__.py 파일에서 __getattr__를 정의합니다:

# mypackage/__init__.py

def __getattr__(name):
    if name == "special_attribute":
        return "This is a special attribute"
    raise AttributeError(f"module {__name__} has no attribute {name}")

이제 mypackage 패키지에서 special_attribute에 접근할 수 있습니다:

import mypackage

print(mypackage.special_attribute)  # Output: This is a special attribute
print(mypackage.non_existing_attribute)  # Raises AttributeError

주요 포인트

  1. 동적 속성 접근: 패키지 수준에서 존재하지 않는 속성에 접근할 때 동적 동작을 정의할 수 있습니다. 예를 들어, 특정 속성 이름에 대해 동적으로 값을 반환하거나, 필요한 경우 예외를 발생시킬 수 있습니다.
  2. 패키지 초기화: 패키지를 초기화할 때 __getattr__를 사용하면, 패키지에 포함되지 않은 속성에 대한 접근을 처리할 수 있습니다. 이는 패키지의 유연성을 높이고, 사용자에게 특정 속성 접근을 허용할 수 있습니다.
  3. Python 3.7 이상: 패키지의 __init__.py 파일에 __getattr__를 정의하는 기능은 Python 3.7에서 도입되었습니다. 따라서 이 기능을 사용하려면 Python 3.7 이상 버전이 필요합니다.

예제 코드 설명

  • __getattr__ 메서드는 name 매개변수를 받아, 접근하려는 속성의 이름을 나타냅니다.
  • special_attribute에 접근할 때는 "This is a special attribute"를 반환합니다.
  • special_attribute가 아닌 다른 속성에 접근하려고 하면 AttributeError를 발생시킵니다.

요약

  • __init__.py 파일에 __getattr__를 정의하면 패키지 수준에서 동적 속성 접근을 처리할 수 있습니다.
  • 이는 패키지의 유연성을 높이고, 사용자에게 특정 속성에 대한 동적 접근을 허용하는 데 유용합니다.
  • Python 3.7 이상에서만 사용 가능합니다.
posted by Peter Note
2024. 8. 4. 15:12 LLM FullStacker/Python

Google 스타일 docstring의 전체 포맷을 설명하기 위해, 모든 주요 섹션을 포함한 예시를 제공합니다. 이 예시는 함수와 클래스에 대한 포맷을 모두 다룹니다.

함수의 예시

def embed_query(text, model='default', verbose=False):
    """
    Embed query text using a specified model.

    This function takes a text string and converts it into an embedding
    using the specified model. It supports different models for embedding
    and can provide verbose output.

    Args:
        text (str): The text to embed. This should be a plain string without any special formatting.
        model (str, optional): The model to use for embedding. Defaults to 'default'.
        verbose (bool, optional): If True, the function will print detailed information during execution. Defaults to False.

    Returns:
        list: A list representing the text embedding.

    Raises:
        ValueError: If the text is empty or the model is not supported.
        RuntimeError: If the embedding process fails.

    Examples:
        >>> embed_query("Hello, world!")
        [0.1, 0.3, 0.5, ...]
        >>> embed_query("Hello, world!", model='advanced')
        [0.2, 0.4, 0.6, ...]

    Notes:
        The embedding process can take a significant amount of time
        depending on the length of the text and the complexity of the model.
    """
    if not text:
        raise ValueError("Text cannot be empty.")
    if model not in ['default', 'advanced']:
        raise ValueError("Unsupported model.")
    # Implementation of embedding process...
    embedding = [0.1, 0.3, 0.5]  # Dummy embedding
    if verbose:
        print(f"Embedding for '{text}' generated using model '{model}'.")
    return embedding

클래스의 예시

class EmbeddingModel:
    """
    A model for generating embeddings from text.

    This class provides methods to embed text using various models. It can
    handle different types of text inputs and supports multiple embedding
    techniques.

    Attributes:
        model_name (str): The name of the model.
        version (str): The version of the model.
        is_trained (bool): Indicates whether the model has been trained.

    Methods:
        train(data):
            Trains the model using the provided data.
        embed(text):
            Embeds the given text and returns the embedding.
        save(path):
            Saves the model to the specified path.
    """

    def __init__(self, model_name, version):
        """
        Initializes the EmbeddingModel with a name and version.

        Args:
            model_name (str): The name of the model.
            version (str): The version of the model.
        """
        self.model_name = model_name
        self.version = version
        self.is_trained = False

    def train(self, data):
        """
        Trains the model using the provided data.

        This method takes a dataset and trains the embedding model.
        It updates the is_trained attribute to True upon successful training.

        Args:
            data (list): A list of training data samples.

        Returns:
            None

        Raises:
            ValueError: If the data is empty or not in the expected format.

        Examples:
            >>> model = EmbeddingModel('text_model', '1.0')
            >>> model.train(['sample1', 'sample2'])
        """
        if not data:
            raise ValueError("Training data cannot be empty.")
        # Implementation of training process...
        self.is_trained = True

    def embed(self, text):
        """
        Embeds the given text and returns the embedding.

        Args:
            text (str): The text to embed.

        Returns:
            list: A list representing the text embedding.

        Raises:
            RuntimeError: If the model has not been trained.

        Examples:
            >>> model = EmbeddingModel('text_model', '1.0')
            >>> model.train(['sample1', 'sample2'])
            >>> model.embed('Hello, world!')
            [0.1, 0.3, 0.5, ...]
        """
        if not self.is_trained:
            raise RuntimeError("Model must be trained before embedding.")
        # Implementation of embedding process...
        return [0.1, 0.3, 0.5]  # Dummy embedding

    def save(self, path):
        """
        Saves the model to the specified path.

        Args:
            path (str): The file path to save the model to.

        Returns:
            None

        Examples:
            >>> model = EmbeddingModel('text_model', '1.0')
            >>> model.save('/path/to/save/model')
        """
        # Implementation of save process...
        pass

주요 구성 요소

  1. 요약 설명(Summary):
    • 클래스나 함수의 첫 번째 줄에서 기능을 간략하게 설명합니다.
    • 간결하고 명확하게 작성하며, 마침표로 끝냅니다.
  2. 확장 설명(Extended Description):
    • 요약 설명 이후 빈 줄을 두고, 기능에 대한 상세 설명을 작성합니다.
    • 설명이 길어질 경우 여러 문단으로 나눌 수 있습니다.
  3. Args (인수):
    • Args: 섹션에서 함수나 메소드의 매개변수를 설명합니다.
    • 각 매개변수에 대해 이름, 유형, 설명을 포함합니다.
    • 선택적 매개변수는 (optional)로 표시합니다.
  4. Attributes (속성):
    • 클래스의 속성을 설명합니다.
    • 각 속성의 이름과 설명을 포함합니다.
  5. Methods (메소드):
    • 클래스의 메소드를 설명합니다.
    • 각 메소드의 이름과 기능을 간략하게 설명합니다.
  6. Returns (반환값):
    • 함수나 메소드의 반환값을 설명합니다.
    • 반환값의 유형과 설명을 포함합니다.
    • 반환값이 없으면 생략할 수 있습니다.
  7. Raises (예외):
    • 함수나 메소드가 발생시킬 수 있는 예외를 설명합니다.
    • 예외의 유형과 설명을 포함합니다.
  8. Examples (예제):
    • 함수나 메소드의 사용 예제를 포함합니다.
    • 코드 블록을 사용하여 예제를 보여줍니다.
  9. Notes (참고):
    • 함수나 메소드에 대한 추가적인 참고 사항을 작성합니다.
    • 필요한 경우에만 포함합니다.

이러한 구성 요소들을 사용하면, Google 스타일의 docstring을 통해 코드의 문서화를 일관성 있게 작성할 수 있습니다.

posted by Peter Note
2024. 7. 22. 22:16 LLM FullStacker/Python

튜플 (Tuple)

튜플(tuple)은 파이썬의 내장 데이터 타입 중 하나로, 여러 값을 하나의 순서 있는 집합으로 저장할 수 있는 자료형입니다. 리스트(list)와 유사하지만, 몇 가지 중요한 차이점이 있습니다.

주요 특징

  1. 변경 불가능(Immutable): 한 번 생성된 튜플의 원소는 변경할 수 없습니다. 따라서 튜플의 내용을 수정, 추가, 삭제하는 작업은 불가능합니다.
  2. 순서가 있음(Ordered): 튜플은 순서가 있는 데이터 타입으로, 각 원소는 인덱스를 통해 접근할 수 있습니다.
  3. 중복 허용: 튜플 내에 동일한 값을 여러 번 포함할 수 있습니다.

생성 방법

튜플은 소괄호 ()를 사용하여 생성하며, 각 요소는 쉼표(,)로 구분합니다.

# 튜플 생성 예시
empty_tuple = ()
single_element_tuple = (42,)  # 하나의 요소를 가진 튜플 생성 시 쉼표 필요
multiple_elements_tuple = (1, 2, 3)

튜플은 괄호 없이도 생성할 수 있습니다. 예를 들어:

another_tuple = 1, 2, 3

접근 방법

튜플의 각 요소에 접근하려면 리스트와 마찬가지로 인덱스를 사용합니다.

example_tuple = (10, 20, 30)
print(example_tuple[0])  # 출력: 10
print(example_tuple[1])  # 출력: 20
print(example_tuple[-1])  # 출력: 30 (마지막 요소)

활용 예

튜플은 주로 다음과 같은 상황에서 사용됩니다:

  • 변경 불가능한 데이터 구조가 필요할 때
  • 여러 값을 하나로 묶어 함수의 인수나 반환값으로 사용하고자 할 때
  • 딕셔너리의 키로 사용하고자 할 때 (리스트는 키로 사용할 수 없음)

기타 메서드

튜플은 몇 가지 유용한 메서드를 제공합니다:

example_tuple = (1, 2, 3, 2, 1)

# 특정 값의 개수 세기
print(example_tuple.count(2))  # 출력: 2

# 특정 값의 인덱스 찾기
print(example_tuple.index(3))  # 출력: 2

이와 같이, 튜플은 파이썬에서 매우 유용한 데이터 타입으로, 특정 상황에서 매우 효율적으로 사용될 수 있습니다.


리스트 (List)

리스트는 순서가 있는 변경 가능한(mutable) 데이터 타입으로, 다양한 유형의 값을 포함할 수 있습니다. 리스트는 대괄호 []를 사용하여 생성하며, 각 요소는 쉼표로 구분합니다.

주요 특징

  1. 변경 가능(Mutable): 리스트의 요소를 추가, 수정, 삭제할 수 있습니다.
  2. 순서가 있음(Ordered): 리스트는 순서를 유지하며, 인덱스를 통해 각 요소에 접근할 수 있습니다.
  3. 중복 허용: 리스트는 동일한 값을 여러 번 포함할 수 있습니다.

생성 방법 및 사용 예

# 리스트 생성
empty_list = []
numbers = [1, 2, 3, 4, 5]
mixed_list = [1, "hello", 3.14, True]

# 리스트 요소 접근
print(numbers[0])  # 출력: 1
print(numbers[-1])  # 출력: 5

# 리스트 수정
numbers[0] = 10
print(numbers)  # 출력: [10, 2, 3, 4, 5]

# 리스트 요소 추가
numbers.append(6)
print(numbers)  # 출력: [10, 2, 3, 4, 5, 6]

# 리스트 요소 삭제
numbers.remove(10)
print(numbers)  # 출력: [2, 3, 4, 5, 6]

 

딕셔너리 (Dictionary)

딕셔너리는 키(key)와 값(value) 쌍을 저장하는 변경 가능한(mutable) 데이터 타입입니다. 딕셔너리는 중괄호 {}를 사용하여 생성하며, 각 키-값 쌍은 콜론 :으로 구분합니다.

주요 특징

  1. 변경 가능(Mutable): 딕셔너리의 키-값 쌍을 추가, 수정, 삭제할 수 있습니다.
  2. 순서가 없음(Unordered) (파이썬 3.7 이후로는 삽입 순서 유지)
  3. 고유 키(Unique Key): 딕셔너리의 각 키는 고유해야 하며, 중복된 키를 가질 수 없습니다.

생성 방법 및 사용 예

# 딕셔너리 생성
empty_dict = {}
person = {"name": "Alice", "age": 25, "city": "New York"}

# 딕셔너리 값 접근
print(person["name"])  # 출력: Alice
print(person.get("age"))  # 출력: 25

# 딕셔너리 값 수정
person["age"] = 30
print(person)  # 출력: {'name': 'Alice', 'age': 30, 'city': 'New York'}

# 딕셔너리 키-값 쌍 추가
person["job"] = "Engineer"
print(person)  # 출력: {'name': 'Alice', 'age': 30, 'city': 'New York', 'job': 'Engineer'}

# 딕셔너리 키-값 쌍 삭제
del person["city"]
print(person)  # 출력: {'name': 'Alice', 'age': 30, 'job': 'Engineer'}

리스트와 딕셔너리 비교

특징 리스트 (List) 딕셔너리 (Dictionary)
변경 가능성 변경 가능 변경 가능
순서 순서가 있음 파이썬 3.7 이후로는 삽입 순서 유지, 그 전에는 순서가 없음
중복 요소 중복 허용 키 중복 불가, 값 중복 허용
접근 방법 인덱스를 통해 요소에 접근 (list[0]) 키를 통해 값에 접근 (dict["key"])

 

리스트와 딕셔너리는 각각의 장점이 있으며, 특정 상황에 맞게 선택하여 사용할 수 있습니다. 데이터를 순차적으로 처리해야 할 때는 리스트를, 키-값 쌍으로 데이터를 관리해야 할 때는 딕셔너리를 사용하면 됩니다.

posted by Peter Note
2024. 7. 2. 23:49 LLM FullStacker/Python

pyproject.toml과 requirements.txt는 Python 프로젝트에서 의존성을 관리하는 데 사용되는 파일이지만, 그 목적과 기능은 다릅니다. 두 파일 간의 주요 차이점을 살펴보겠습니다.

pyproject.toml

pyproject.toml은 Python 프로젝트의 메타데이터 및 의존성을 선언하는 데 사용되는 파일입니다. 이 파일은 PEP 518에 정의되어 있으며, 프로젝트 빌드 시스템과 빌드 의존성을 지정하는 데 사용됩니다. Poetry와 같은 현대적인 패키지 관리 도구는 pyproject.toml을 사용하여 프로젝트의 모든 의존성을 관리합니다.

주요 특징

  1. 메타데이터 관리: 프로젝트 이름, 버전, 설명, 저자 등의 메타데이터를 포함합니다.
  2. 의존성 관리: 개발 및 런타임 의존성을 모두 포함할 수 있습니다.
  3. 빌드 시스템 설정: 빌드 백엔드(예: setuptools, poetry 등)를 지정할 수 있습니다.
  4. Poetry 통합: Poetry는 pyproject.toml 파일을 사용하여 패키지 관리와 의존성 설치를 수행합니다.

예시

[tool.poetry] 
name = "my_project" 
version = "0.1.0" 
description = "A sample project" 
authors = ["Your Name <you@example.com>"] 

[tool.poetry.dependencies] 
python = "^3.8" 
requests = "^2.25.1" 

[tool.poetry.dev-dependencies] 
pytest = "^6.2.3" 

[build-system] 
requires = ["poetry-core>=1.0.0"] 
build-backend = "poetry.core.masonry.api"

requirements.txt

requirements.txt는 전통적인 방법으로 Python 프로젝트의 의존성을 관리하는 파일입니다. 주로 pip를 사용하여 의존성을 설치할 때 사용되며, 각 의존성을 별도의 줄에 작성합니다.

주요 특징

  1. 단순성: 각 줄에 하나의 패키지와 선택적인 버전 제한을 작성하여 의존성을 명시합니다.
  2. 의존성 설치: pip install -r requirements.txt 명령어를 사용하여 의존성을 설치합니다.
  3. 개발 및 런타임 의존성 분리 어려움: 개발 및 런타임 의존성을 명확히 분리하기 어렵습니다.

예시

requests==2.25.1 
pytest==6.2.3

비교 및 차이점

특징pyproject.tomlrequirements.txt

목적 프로젝트 메타데이터 및 의존성 관리 의존성 목록 관리
포맷 TOML 단순 텍스트
의존성 종류 분리 개발 및 런타임 의존성 분리 가능 분리하기 어려움
빌드 시스템 통합 빌드 시스템 및 백엔드 지정 가능 해당 없음
사용 도구 Poetry, setuptools 등 pip
기타 설정 빌드 설정, 스크립트 등 다양한 설정 포함 가능 해당 없음

선택 기준

  • 현대적인 프로젝트 관리: Poetry와 같은 도구를 사용하여 의존성을 보다 체계적으로 관리하고 싶다면 pyproject.toml을 사용하는 것이 좋습니다.
  • 전통적인 방법: 간단하게 의존성만 관리하고 싶다면 requirements.txt가 충분할 수 있습니다.

함께 사용하기

Poetry를 사용하면서도 requirements.txt 파일을 생성하여 기존의 워크플로우와 호환성을 유지할 수 있습니다. 다음 명령어를 사용하여 requirements.txt 파일을 생성할 수 있습니다:

poetry export -f requirements.txt --output requirements.txt
 

이렇게 하면, pyproject.toml에서 관리되는 의존성을 requirements.txt 형식으로 내보낼 수 있어 기존 도구들과 호환성을 유지할 수 있습니다.

요약

  • pyproject.toml은 프로젝트 메타데이터, 의존성 및 빌드 설정을 포함하는 현대적인 방식의 관리 파일입니다.
  • requirements.txt는 단순히 의존성을 나열하는 전통적인 텍스트 파일입니다.
  • pyproject.toml은 더 많은 기능과 유연성을 제공하며, 특히 Poetry와 같은 도구와 함께 사용할 때 유용합니다.
  • requirements.txt는 간단하고 널리 사용되지만, 개발 및 런타임 의존성 분리가 어렵고, 빌드 시스템 설정과 같은 고급 기능을 제공하지 않습니다.

 

References

https://teddylee777.github.io/poetry/poetry-tutorial/

 

poetry 의 거의 모든것 (튜토리얼)

poetry 로 가상환경을 구축하는 방법을 단계별로 설명합니다.

teddylee777.github.io

 

posted by Peter Note
2024. 7. 2. 22:27 LLM FullStacker/Python

Python에서 lambda 키워드는 익명 함수(anonymous function)를 생성하는 데 사용됩니다. lambda 함수를 사용하면 이름 없이도 함수 객체를 생성할 수 있습니다. 일반적으로 lambda 함수는 간단한 기능을 수행하는 짧은 함수가 필요할 때 사용됩니다.

lambda 함수의 구문

lambda 키워드를 사용하여 함수를 정의하는 구문은 다음과 같습니다:

lambda arguments: expression
  • arguments: 함수에 전달될 인수들입니다.
  • expression: 함수가 반환할 표현식입니다.

예시

기본 사용 예시

# 일반 함수 정의 
def add(x, y): 
  return x + y 
  
# lambda 함수 정의 
add_lambda = lambda x, y: x + y 

# 함수 호출 
print(add(2, 3)) # 5 
print(add_lambda(2, 3)) # 5

리스트의 각 요소에 함수를 적용하는 예시

# lambda 함수를 사용하여 리스트의 각 요소에 2를 곱함 
numbers = [1, 2, 3, 4, 5] 
doubled = list(map(lambda x: x * 2, numbers)) 
print(doubled) # [2, 4, 6, 8, 10]
 

정렬 시에 키로 사용하는 예시

# lambda 함수를 사용하여 리스트를 정렬 
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] 
# 두 번째 요소(문자열) 기준으로 정렬 
pairs.sort(key=lambda pair: pair[1]) 
print(pairs) # [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

lambda 함수와 일반 함수 비교

lambda 함수는 익명 함수로, 보통 한 줄로 표현되며, 작은 연산이나 함수 객체가 필요한 곳에서 주로 사용됩니다. 일반 함수는 def 키워드를 사용하여 이름이 있는 함수로 정의되며, 여러 줄로 이루어질 수 있고 복잡한 논리를 포함할 수 있습니다.

예시: lambda 함수와 일반 함수의 비교

# lambda 함수 
multiply = lambda x, y: x * y 
print(multiply(2, 3)) # 6 

# 일반 함수 
def multiply_def(x, y): 
  return x * y 
  
print(multiply_def(2, 3)) # 6

사용 시 주의사항

  • 간결성: lambda 함수는 단일 표현식만 포함할 수 있으며, 여러 문장을 포함할 수 없습니다. 따라서 복잡한 로직을 처리하기에는 적합하지 않습니다.
  • 가독성: 짧고 간단한 경우에는 lambda 함수가 유용하지만, 너무 복잡한 경우 가독성을 해칠 수 있으므로 일반 함수를 사용하는 것이 좋습니다.

요약

  • lambda 키워드는 익명 함수를 생성하는 데 사용됩니다.
  • 간단한 함수나 일회성 함수 객체가 필요한 곳에서 유용합니다.
  • 구문은 lambda arguments: expression 형태를 가지며, 단일 표현식만 포함할 수 있습니다.
  • 일반 함수(def 사용)와 비교할 때, 더 간단하고 간결하지만 복잡한 로직에는 적합하지 않습니다.

이를 통해 lambda 키워드의 역할과 사용 방법을 이해할 수 있습니다.

posted by Peter Note
2024. 6. 17. 23:04 LLM FullStacker/Python

Mac 기준으로

 

Python Version Manager 설치

pyenv 설치

brew install pyenv

 

.zshrc 설정 추가

# pyenv setting
eval "$(pyenv init --path)"
eval "$(pyenv init -)"

 

Python Virtual Environment 설치

pyenv-virtualenv 설치

brew install pyenv-virtualenv

 

.zshrc 설정 추가

# pyenv-virtualenv setting
eval "$(pyenv virtualenv-init -)"

 

Python Version 설치

python 버전 목록 확인

pyenv install --list

 

python 특정 버전 설치

pyenv install 3.12.4

 

현재 사용버전

pyenv versions

* system (set by /Users/dowon2yun/.pyenv/version)
  2.7.14
  3.6.2
  3.6.2/envs/mms
  3.12.4
  mms --> /Users/dowon2yun/.pyenv/versions/3.6.2/envs/mms

 

Python Version 적용 

전체 사용 설정

  - pyenv global [version]

pyenv global 3.12.4
pyenv versions
  system
  2.7.14
  3.6.2
  3.6.2/envs/mms
* 3.12.4 (set by /Users/dowon2yun/.pyenv/version)

 

로컬 프로젝트만 사용 설정

  - pyenv local [version]

~ mkdir test
~ cd test
~/test pyenv local 3.6.2
~/test ls -alrt
total 8
drwxr-xr-x    3 dowon2yun  staff    96 Jun 17 23:00 .
-rw-r--r--    1 dowon2yun  staff     6 Jun 17 23:00 .python-version
drwxr-xr-x+ 128 dowon2yun  staff  4096 Jun 17 23:00 ..
~/test cat .python-version
3.6.2

 

현재 shell만 사용 설정

  - pyenv shell [version]

~/test pyenv shell 3.12.4
~/test pyenv version
3.12.4 (set by PYENV_VERSION environment variable)

 

Python Virtual Env 설정

python 패키지의 버전 격리 환경을 만들어 준다. 

 

python 버전과 virtual 환경 생성

  - pyenv virtualenv [version] [virtual-name]

~ mkdir test2
~ cd test2
~/test2 pyenv virtualenv 3.12.4 venv
~/test2 pyenv versions
  system
  2.7.14
  3.6.2
  3.6.2/envs/mms
* 3.12.4 (set by PYENV_VERSION environment variable)
  3.12.4/envs/venv
  mms --> /Users/dowon2yun/.pyenv/versions/3.6.2/envs/mms
  venv --> /Users/dowon2yun/.pyenv/versions/3.12.4/envs/venv

 

Python Virtual Env 활성화/비활성화

  - pyenv activate [virtual-name]

~/test2 pyenv activate venv
(venv) ~/test2 pyenv versions
  system
  2.7.14
  3.6.2
  3.6.2/envs/mms
  3.12.4
  3.12.4/envs/venv
  mms --> /Users/dowon2yun/.pyenv/versions/3.6.2/envs/mms
* venv --> /Users/dowon2yun/.pyenv/versions/3.12.4/envs/venv (set by PYENV_VERSION environment variable)

 

  - pyenv deactivate [virtual-name]

(venv) ~/test2 pyenv deactivate venv
~/test2 pyenv versions
  system
  2.7.14
  3.6.2
  3.6.2/envs/mms
* 3.12.4 (set by /Users/dowon2yun/.pyenv/version)
  3.12.4/envs/venv
  mms --> /Users/dowon2yun/.pyenv/versions/3.6.2/envs/mms
  venv --> /Users/dowon2yun/.pyenv/versions/3.12.4/envs/venv
~/test2

 

 

Poetry 설치

전문적인 의존성 관리 및 패키지 배포관리 툴인 poetry를 설치한다. 

https://python-poetry.org/docs/

 

pipx 를 통해 설치힌다. 

https://pipx.pypa.io/stable/installation/

brew install pipx
pipx ensurepath
sudo pipx ensurepath --global

 

pipx를 통해 poetry를 설치한다. python 3.12.3 을 사용한다는 메세지가 출력된다. 

pipx install poetry

// result message
  installed package poetry 1.8.3, installed using Python 3.12.3
  These apps are now globally available
    - poetry

 

poetry를 실행한다. 

poetry

// result mesage
Poetry (version 1.8.3)

 

Poetry 다음 Tab으로 명령 목록 보기

oh-my-zsh 설정이 .zshrc 에 있음을 가정한다

// .zshrc 에서 ZSH_CUSTOM 주석 풀고 계정 폴더 밑으로 oh-my-zsh 설정
# Would you like to use another custom folder than $ZSH/custom?
ZSH_CUSTOM=/Users/peter/oh-my-zsh

// 저장후 변경 적용
. .zshrc

// 폴더 생성 
mkdir $ZSH_CUSTOM/plugins/poetry

 

oh-my-zsh 의 plugins 에 poetry 추가 

// .zshrc oh-my-zsh의 plugins 에 poetry 추가
plugins=(git poetry)

// .zshrc 변경 적용
. .zshrc

 

다음 명령 수행

poetry completions zsh > $ZSH_CUSTOM/plugins/poetry/_poetry

 

테스트 "peotry in" 까지 입력하고 tab key를 치면 아래와 같이 init, install 등의 poetry 명령 목록이 출력된다.

$ . .zshrc
$ poetry in
init     -- Creates a basic pyproject.toml file in the current directory.
install  -- Installs the project dependencies.

 

 

Poetry 통한  프로젝트, 패키지 추가

[1] Poetry 기반 프로젝트 생성

  - poetry new [project-name]

poetry new ai-agent

 

[2] 프로젝트로 이동해서 가상환경을 프로제트내로 설정한다.

poetry config virtualenvs.in-project true

 

[3] poetry 프로젝트 가상환경으로 변경

poetry shell

 

[4] ai_agent 패키지 폴더에 __main__.py 추가

  -  폴더 지정으로 run 하기 위해 __init__.py 위치에 __main__.py 파일을 추가한다.

  - .env 파일 생성후 KEY 값 설정

  -  명령

     - poetry shell 미수행시 : poetry run python [folder-name] 또는 [file-name]

     - poetry shell 수행시 : python [folder-name]

// .env 파일
OPENAI_API_KEY=sh-proj-xsdhfdrerjelrelreahahhahahaahaha

// __main__.py 내역 
import os
from dotenv import load_dotenv

load_dotenv()

print(f"[API KEY]\n{os.environ['OPENAI_API_KEY']}")

// 실행
poetry run python ai_agent
[API KEY]
sh-proj-xsdhfdrerjelrelreahahhahahaahaha

 

[5] Python version 변경

1) pyenv install [newVersion]

2) poetry env remove [oldVersion]

3) poetry env use [newVersion]

 

References

https://python-poetry.org/docs/

 

Introduction | Documentation | Poetry - Python dependency management and packaging made easy

If you installed using the deprecated get-poetry.py script, you should remove the path it uses manually, e.g. rm -rf "${POETRY_HOME:-~/.poetry}" Also remove ~/.poetry/bin from your $PATH in your shell configuration, if it is present.

python-poetry.org

 

https://blog.flynnpark.dev/15

 

Poetry로 파이썬 의존성 관리하기

Poetry? 파이썬에서 사용하는 의존성 관리자는 몇 가지가 있습니다. 파이썬의 공식 의존성 관리자인 pip, 그리고 pip와 virtualenv를 같이 사용할 수 있는 Pipenv가 있고, 이번에 소개할 Poetry가 있습니다.

blog.flynnpark.dev

https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins

 

Plugins

🙃 A delightful community-driven (with 2,300+ contributors) framework for managing your zsh configuration. Includes 300+ optional plugins (rails, git, macOS, hub, docker, homebrew, node, php, pyth...

github.com

구성파일은 TOML 파일 형식

https://www.itworld.co.kr/news/248128#:~:text=TOML(Tom's%20Obvious%20Minimal%20Language)%EC%9D%80%20%EA%B5%AC%EC%84%B1%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EC%A0%80%EC%9E%A5%EC%9D%84,%EC%95%84%EB%8B%88%EB%8B%A4(pip%EC%97%90%EC%84%9C%20%ED%8C%A8%ED%82%A4%EC%A7%80%20%EB%B9%8C%EB%93%9C%EB%A5%BC%20%EC%9C%84%ED%95%B4%20%EC%82%AC%EC%9A%A9%EB%90%98%EB%8A%94%20pyproject.toml%20%EC%B0%B8%EC%A1%B0).

 

파이썬 앱 구성을 더 쉽게⋯TOML의 이해와 기본 활용

소프트웨어 개발에서 흥미로운 반전은 가장 간단한 의사 결정이 때로는 가장 어려운 의사 결정이 되기도 한다는 것이다. 예를 들면 애플리케이션이나

www.itworld.co.kr

https://teddylee777.github.io/poetry/poetry-tutorial/

 

poetry 의 거의 모든것 (튜토리얼)

poetry 로 가상환경을 구축하는 방법을 단계별로 설명합니다.

teddylee777.github.io

 

posted by Peter Note
2014. 12. 31. 19:31 LLM FullStacker/Python

Dart는 점점 복잡해 지는 웹 애플리케이션을 좀 더 견고하고 확장 가능토록 만들기 위해 나온 언어이다. 구글의 수많은 웹 서비스를 생각해보면 자바스크립트가 아니라 좀 더 낳은 개발 언어로 웹을 개발하고 싶어할 것이고 그러한 요구에 자체적으로 Dart를 개발하고 퍼트리는 느낌이랄까. 마치 서버에서 Go를 만들어 자신들의 서비스에 광범위하게 쓰고 있는 것과 같은 이치일것 같다. 그래서 적어도 현업에서 사용하지않는다 해도 어떤 모습이 미래의 웹 개발 언어가 되어야 하는지 살펴볼 필요는 있겠다. 생각은 이렇다. 웹 프론트앤드 개발은 Dart를 서버 백앤드 개발은 Go를 구글은 실험하고 있는 단계이다. 이들 모두 3년이상 지속해서 소개되고 사용되고 구글 클라우드에 적용되고 있다. 그러나 Dart는 프론트 백앤드를 모두 개발할 수 있다. 우선은 프론트앤드에 집중해서 보도록 한다. 






Dart 개념 익히기 

  

  - Dart 언어 개발자인 길라드 브라차로 부터 다트에 대해 들어보자

    + Dart type checking system에 대해 설명하고 있다. 

    + 자바의 JVM 스팩을 쓴 개발자 답게 언어 전문가의 냄새가 물신난다.

   

  - Dart 언어 개발자의 전체 소개 동영상이다. 

    + 다트 플랫폼 전체를 간략히 잘 설명해 주고 있다. 꼭 보자 

   


  - Dart언어의 특징을 간략히 보도록 하자. (한글)

   - 처음은 무조건 사이트부터 방법해서 https://angulardart.org/ 

    + 다트 소개 영상이다. 모든 것이 잘 요약되어 있다. (시리즈 동영상들)

    + Angular의 철학에 근거해서 만들어 졌기 때문에 테스트 가능하고 간결한 웹개발을 이끈다.

    + Dart 언어를 사용하기 때문에 class, annotation, inheritance등은 자바 개발자에게 익숙함을 제공하고 확장가능한 웹을 만듦

    + 모던 웹을 위한 Shadow DOM, Web Component를 시작할 수 있다. 

    참조)  테스트 가능성은 Angular의 DI (Dependency Injection)을 통해 가능해 진다. 

             Two-way data binding을 통해 간결한 코드 개발이 가능하다.

    


  - Dart로 시작하는 AngularDart는 Web Component 스팩을 구현하고 있는 Polymer.dart와 함께 어떤 방향으로 가는지 먼저 본다. 

    + 본영상이 JavaZone에서 발표됐다는 것은 자바 개발자에게 아주 익숙한 신택스로 Dart 언어가 구성되었기 때문일 것이다. 

    


  - Dart 언어에 대해 개념을 잡자

    + https://www.dartlang.org

  - DartEditor를 사용한다. 

    + 이클립스 기반이어서 자바개발자에게 친근감 마저 든다. 

    + 패키지 import 와 이클립스 debugging 등 확장자가 .java 에서 .dart로 바뀌고 웹과 서버 모두를 개발 할 수 있다. 

    


  - 문법 요약은 Dart Tip 11개에 대한 동영상을 보자





Dart 익히기 


 - Dart를 가지고 웹을 개발할 때는 어떻게 하는지 보자 

    

  

  - 웹 애플리케이션을 개발과정을 읽어보자 다트로 어떻게 하는 거지?

    + 다트는 기본적으로 Dart VM 에서 돌어간다. 웹에서 작동하려면 두가지 방법이 있다. 

    + 첫째는 Chormium 브라우져에 Dart VM을 넣은 Dartium 브라우져에서 수행. 

       개발시 Dartium으로 수행하면 DartEditor(Eclipse기반)에서 바로 디버깅이 가능하다. 

    + 둘째는 dart2js 툴 또는 pub build를 이용해서 자바스크립트로 바꿔서 일반브라우져에서 사용하는 것이다.  

    + DartEditor에서 Tools --> Pub Build(integrated JS)를 선택하면 모던 브라우져 모두에 수행 가능한 파일이 생성된다.

       


  - 본격적으로 Dart 강좌를 들어가자

  - Dart의 유용한 글과 라이브러리는 다토스피어(http://www.dartosphere.org/) 에서 검색한다. 

    + 다크관련 블로그 글들

    + 라이브러리 업데이트 현황

    + https://pub.dartlang.org 에서 배포된 다트 라이브러리를 찾을 수 있다.




Dart 는 메이져 모던 브라우져에서 수행된다. 


  - Dart를 Javascript로 변환해 주는 과정에 대한 설명 

    + 자바스크립트로 변환하고 top level 펑션은 $.main 이다. 

    + Tree Shaking 통해 필요없는 코드를 떨구어내고 자바스크립트로 전환한다는 의미 

    + Dart의 특징을 자바스크립트 코드로 어떻게 이식하고 있는지 설명한다. 예) Class 상속

    + JS로 전환할 때 많은 알고리즘과 방법이 동원되고 있다. 역시 문제 해결을 위해 알고리즘이 중요함 

    + JS로 전환할 때 --minify 로 사이즈를 줄여서 얻을 수 있다.(45분) 

    + 손으로 작성한 JS보다 성능이 좋다. 결론은 이것이다. 모바일에서 더 낳은 성능을 얻고 싶다면!!!

     

     



  계속해서 업데이트 예정...




<참조> 

  

  - dartlang.org




posted by Peter Note
2014. 12. 24. 17:15 LLM FullStacker/Python

처음으로 새로운 프레임워크를 접하게 되었을 때 어떻게 시작해야할지 막막하다. 그럴땐 공부할 꺼리들을 정리해 보고 시작하자. 새롭게 시작할 AngularDart의 컨텐츠를 정리해 보자. 






AngularJS 개발자가 AngularDart 개발하기 


  - AngularDart의 상당 부분이 실은 AngularJS v2.0에 많은 영향을 미쳤다. (미스코의 말)

    + AngularJS개발자를 위한 AngularDart 이해하기

  - Dartlang을 모르고서 AngularDart를 보면 안되겠죠?  

  - UI Framework과 연동해서 웹 애플리케이션을 만들어 본다. (깃헙 소스)

    


  - 코드랩을 따라한다.

    + 예제 데모를 돌려보면 최신 IE 11, FF, Safari, Chrome에서 잘 돌아감. 

    + HTML의 디렉티브는 AngularJS와 거의 같음. 코드만 .dart 로 작성함 

  - 개발하며 API를 참조한다.





AngularDart와 Polymer 연동하기


  - 우선 AngularDart 소개영상과 25분부터 이어지는 Polymer.Dart를 보자 

    + 보고 있으면 아마도 ng-conf 2014에서 소개한 Angular v2.0 영상의 14분 부터 보면 뭔가 떠오를지 모르겠다. 

    

 

  - 첫번째 영상에서 Web Component 개념을 이야기하는 Polymer.dart를 다시 보자. 

  - 다시 정리하고 있는 Parsley의 Web Component & Dart 동영상을 보자

  - 따라하기 하며 Dart와 Polymer.dart를 연결해 보기 


계속해서 업데이트 예정...




<참조> 


  - Dart와 Web Component에 대한 다른 영상

  - 미스코 헤베리의 AngularDart를 만든 이유 

The Angular team's mission is to make building web-applications easy on the web. We want to support as many languages as possible.

AngularJS supports: JavaScript and through transpilation CoffeeScript and TypeScript.

AngularDart obviously supports Dart. 

1) Dart is significantly different from JavaScript that transpilation approach would not create the experience we were looking for, for this reason we have rewritten it. 

2) Dart has Types, and Type annotations, and so while rewriting AngularDart we have chose to take advantage of these language features. 

3) We have also learned from our mistakes on AngularJS and taken the opportunity to correct them, such as much improved Directive API. Finally we have take advantage of the latest browser technologies and based AngularDart on top of Shadow DOM.

4) All of the learnings we have gained in building AngularDart, will be applied back to AngularJS v2. This is only expected since AngularDart is younger than AngularJS.

Angular is a philosophy on how applications should be built and we wanted to make the question of language choice orthogonal to your choice of using Angular. Any web-language you choose, there is an Angular you can use with it.



posted by Peter Note
2014. 12. 24. 14:53 LLM FullStacker/Python

빠르게 메타지식을 흡수해 변환에 적응하는 능력을 지적 겸손이라 한다. 태도의 겸손이 아닌 내가 아는 것이 전부가 아니고 더 낳은 방법과 기술이 있다면 메타지식을 빠르게 흠수할 수 있는 능력이 필요한 시대가 되었다. 새로운 웹 개발언어로 성능과 생산성 증대를 목표로 하는 Dart에 대해 공부를 해본다.






중요 개념 


  - 모든 변수는 Object 이다. 

  - 정적 타입과 동적(dynamic) 타입이 가능하다   

  - 정적 타입 오류를 컴파일 타임에 알려준다

  - main() 펑션이 있다

  - public, protected, private 같은 것이 없고 _ (underscore)로 표현한다 

  - warning 은 프로그램이 수행 안될지도 모른다 이지만 수행을 막지는 않는다. 

    error가 컴파일 타임이 나면 수행할 수 없고 런타임에 발생하면 exception이 발생한다.  

  - 런타임 모드는 production 과 checked 두가지다. 개발시에는 checked 모드로 사용한다. 

     production 모드에서는 assert 구문을 무시한 최적화를 통해 성능을 향상시켜준다. 

  - 키워드 

   

    1 : built-in indentifier : 자바스크립트를 다트로 포팅을 쉽게 해준다. 

    2 : 제한적인 예약어로 비동기 지원과 관련이 있다. 

    



변수 (Variables)


  - 예 : 'Peter' 값을 가지는 String 객체의 레퍼런스 주소값을 name이라는 변수가 가지고 있다. 

var name = 'Peter';


  - 최기화 되지 않은 변수는 null 초기값을 갖는다. 숫자가 초기값이 없어도 null 초기값을 갖는다. 

    assert 구문은 production 모드에서 무시된다. 만일 assert 구문이 true가 아니면 exception을 던진다. 

int lineCount;

assert(lineCount == null);


  - 옵셔널 타입으로 String name = 'Bob'으로 직접 지정해 줄 수도 있지만 타입 스타일 가이드에 따라 var를 사용한다. swift와 유사함 

  - final은 변수의 값을 변경하고 싶지 않을 경우 var 대신 사용한다. const는 수치값을 지정한다. 

  - numbers, strings, booleans, lists, maps, symbols 관련 빌트인 타입을 가지고 있다. (예제 참조)

    + numbers : int, double 있고 이들은 num의 서브타입이다. 다트의 int와 자바스크립트 int는 틀리다. 다트 int는 arbitrary-precision integer

    + strings : UTF-16 코드를 따르고 ''  또는 "" 사용가능. 'hi peter ${expression}' 식으로 문자안에 ${} 표현가능. swift와 유사함

    + booleans : bool 타입으로 true, false를 값을 가져야 하고 자바스크립트와 틀리다. 즉, var name='pter'; if(name)하면 false이다. 

    + lists : 다트의 배열은 List 오브젝트이다. 인덱싱은 0부터 시작한다. GenericsCollections을 살펴보자 

    + maps : key-value에 대해 Map 오브젝트를 사용한다. JSON처럼 literal 지정 

    + symbols : Symbol 오브젝트를 통해서 operator와 identifier를 표현한다. 




펑션 (Functions)


  - 예 : 스타일 가이드에 따라 파라미터와 리턴 타입 지정한다. 

// 파라미터와 리턴 타입을 명시하는게 스타일 가이드 

void printNumber(num number) { 

  print('this is $number');


// 하지만 생략도 가능 

printNumber(number) 

  print('this is $number');

 


  - => expr;{ return expr; } 표현과 같다. coffeescript 같은 축약형 좋다. 하기 표현은 위 표현과 동치 

printNumber(number) => print('this is $number');


  - 옵션널 파라미터

    + 기본 설정 : enable(bool flag1, bool flag2) { ... }

    + Optional named parameter는 paramName: value로 지정 

       예) enable({bool flag1: false, bool flag2: true}) { ... } 사용 enable(flag1: true)

    + Optional positional parameter는 [] 마크를 사용

       예) say(String from, String msg, [String device]) { ... } 사용 say('hi', 'peter') 또는 say('hi', 'peter', 'ios')

  

  - 애플리케이션은 최상위 레벨에서 main() 펑션를 갖는다. 애플리케이션의 진입점역할을 한다. 자바와 유사함

    .. 오퍼레이터는 cascade operator이다. 즉, 이어서 호출한다. 

void main() {

  querySelector('#peter')

    ..text = 'Hi dowon'

    ..onClick.listen(reservedText);


  - Functions as first-class objects 이다. 펑션을 다른 펑션에 파라미터로 전달하거나 리턴하는 것이 가능. 이건 자바스크립트부터 쭉... 

printElm(element) {

  print(element);

}


var list = [1,2,3];

list.forEach(printElm); // printElm을 파라미터로 전달 


  - 자바스크립트는 function 레벨에서 lexical scope를 갖듯 다트도 lexical scope를 갖는다. 즉, 변수의 스코프가 정적으로 정해진다. (단, 자바스크립의 this는 호출되는 시점에 결정되므로 이부분에 틀림. 아래 참조 링크를 보자) 다트는 curly raches outwards를 따른다. (자바스크립트는 변수에 var를 줌으로 로컬 변수 스코프임을 지정한다) 

  - lexical closures는 lexical scope안의 변수를 접근하는 펑션 오브젝트이다. 

closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.


  - 모든 펑션은 리턴값을 갖고 지정하지 않으면 return null; 이다. 




연산자 (Operators)


  - 연산자 종류 

    


  - 타입 테스트 오퍼레이터 

    



제어 흐름 (Control Flow Statement)


  - if(){ ... } else if() { ... } else { ... }

  - for ( 초기값 ; 비교 ; 증분 ) { ... } 또는 for in 

  - while() { ... } 또는 do { ... } while ()

  - while에서 break, for 에서 continue 

  - switch ~ case ~ default




예외처리 (Exceptions)


  - 다트의 예외는 unchecked exception 이다. 

  - 다트는 ExceptionError 타입을 제공한다. 

  - throw 하면 에러를 일으킨다. 

  - on catch 으로 exception을 catch 하고 전파되는 것을 막는다. 

try {

  aa();

} on OutofException {  // known exception

  bb();

} on Exception catch (e) { // anyting else that is an exception

  print('exception is: $e');

} catch (e) {

  print('really unknown : $e');

}

 

  - finally : finally가 수행된 후에 exception이 전파된다 




클래스 (Classes)


  - 다트는 객체지향 언어이다. 

  - new 키워드로 클래스의 인스턴스인 오브젝트를 생성한다. 

  - 클래스는 펑션과 데이터를 멤버로 갖고 특히 오브젝트의 펑션을 메소드라 부른다. dot(.)로 호출한다. cascade operator(..)은 싱글 객체의 멤버를 연속적으로 호출할 때 사용한다.

  - 생성자는 클래스와 같은 이름을 자고 this는 현재 인스턴스를 가르킨다. 자바와 유사

  - 생성자를 선언하지 않으면 아규먼트 없는 기본 생성자가 자동 제공됨. 자바와 유사 

  - 생성자는 상속되지 않는다. 

class Point {

  num x;

  num y;


  Point(this.x, this.y);

}


  - get, set 키워드를 통해 프로퍼티를 만들 수 있다. 

class Rectangle {

  num left;

  num top;


  Rectangle(this.left, this.top);


  num get right   => left;

         set right(num value) => left = value - left;

}


  - abstract class를 만들 수 있다. 상속은 extends를 사용함.  자바와 유사 

abstract class Door { 

  void open();

}


  - 연산자도 오버라이드 할 수 있음 

  - 모든 클래스인 암묵적으로 interface를 정의할 수 있다. 만일 A 클래스가 B의 구현체를 상속받지 않고 B의 API만을 사용하고 싶을 경우 implements 키워드를 사용한다. 자바에는 없는 재미난 부분

// A person. The implicit interface contains greet().

class Person {

  final _name;          // In the interface, but visible only in this library,

  Person(this._name);   // Not in the interface, since this is a constructor.

  String greet(who) => 'Hello, $who. I am $_name.'; // In the interface.

}


// An implementation of the Person interface.

class Imposter implements Person {

  final _name = "";      // We have to define this, but we don't use it.

  String greet(who) => 'Hi $who. Do you know who I am?';

}


greetBob(Person person) => person.greet('bob');


main() {

  print(greetBob(new Person('kathy')));

  print(greetBob(new Imposter()));

}


  - extends 키워드로 상속을 하고 super는 부모 클래스를 가르킴. 자바와 유사

  - 상속시 부모 메소드에 대한 @override를 명시적으로 사용해 오버라이딩이 가능하다. 

  - 클래스에 @proxy라고 하면 @override시에 warning을 준다. 

  - 다중 상속시에 mixin 개념의 클래스 코드 재사용이 도입. with 키워드를 사용한다. mixin 할때는 upser, 생성 선언이 없다. 

class Musicain extends Performer with Musical, Aggressive, Demented { 

  ...

}


  - 클래스 소속 메소드와 변수는 static 키워드를 사용한다. 자바와 유사




제네릭 (Generics)


  - 다트에서 타입은 옵셔널이다. 의도를 명확히 하기 위해 공식적으 타입 파라미터를 같는 타입이다. (generic == parameterized) type

    예에서 문자로 지정을 한다는 의도를 분명히 한다. 

var names = new List<String>();

names.addAll(['Seth', 'Kathy', 'Lars']);

// ...

names.add(42); // Fails in checked mode (succeeds in production mode).


  - type variables로는 통상 E, T, S, K, V 같은 단일 문자를 갖는다. 

  - 제네릭은 코드의 중복을 방지해 준다. 상속하여 구현 하면 됨 

// Object 경우 

abstract class ObjectCache {

  Object getByKey(String key);

  setByKey(String key, Object value);

}


// String 경우 

abstract class StringCache {

  String getByKey(String key);

  setByKey(String key, String value);

}


// 하나로 줄여줌 

abstract class Cache<T> {

  T getByKey(String key);

  setByKey(String key, T value);

}


  - Collection literal에도 사용가능하다. 

var names = <String>['Seth', 'Kathy', 'Lars'];

var pages = <String, String>{

  'index.html': 'Homepage',

  'robots.txt': 'Hints for web robots',

  'humans.txt': 'We are people, not machines'

};


 


라이브러리와 가시성 (Libraries and visibility) 


  - import, part, library 지시자(Directives) 사용한다. 

  - 라이브러리는 Pub Package and Asset Manager인 pub 툴로 패키지를 사용 배포한다. 

  - import 'dart:html';  형식으로 import는 URI 형시그로 라이브러리를 지정한다. 

  - 빌트인은 'dart:xxx' 로 시작한다. 

  - pub 툴 배포로 제공되는 것은 import 'package:<file path>'; 로 지정한다. 예) import 'package:utils/utils.dart';

  - as로 aliasing이 가능 예) import 'package:lib2/lib2.dart' as lib2; 

  - show, hide 통해 라이브러리 일부만 가져오기 가능 예) import 'package:lib2/lib2.dart' show foo;

  - 라이브러리의 Lazily loading이 가능하다. deferred as 키워드를 사용한다. AngularJS의 $q를 보자  

    + 애플리케이션 초기 시작시간을 줄이기 위해 사용

    + A/B 테스트를 수행하기 위해

    + 사용이 적은 것들 로딩할 때 

    예) import 'package:deferred/hello.dart' deferred as hello;  하기에 then 구문으로 비동기적 호출을 한다.

hello.loadLibrary().then((_) {

  hello.printGreeting();

});


  - 다른 방법으로는 async 키워드를 사용한다. loadLibrary()는 Future를 리턴한다. 

greet() async {

  await hello.loadLibrary();

  hello.printGreeting();

}


  - library <라이브러리명칭>; 으로 사용한다. part는 라이브러리의 첨부된 파일을 지칭한다. 

library ballgame;   // Declare that this is a library named ballgame.


import 'dart:html'; // This app uses the HTML library.


part 'ball.dart';  // ballgame의 일부이다. 


 


비동기 지원 (Asynchrony support)


  - async 와 await 키워드를 사용한다. 

  - 다트 라이브러리는 Future 오브젝트를 리턴하는 펑션셋을 가지고 있다.  

  - dart 또는 dartanalyzer에서 async 지원을 위해 옵션을 주어야 한다. DartEditor (Eclipse기반)에도 넣어줌 

    

dart --enable-async async_await.dart

dartanalyzer --enable-async async_await.dart


  - async 펑션선언 

check() async {

  //...

}


look() async => //...


  - await <expression> 에서 expression은 타입 Future를 가지고 있고 이는 오브젝트를 리턴하기 위한 promise이다. 리턴된 오브젝트가 유효할 때까지 실행은 멈춘다. 




Typedefs


  - 다트에서 펑션, 문자, 숫자 모두 오브젝이다. 

  - typedef 또는 function-type alias 는 필드나 리턴타입을 선언할 때 사용할 수 있는 펑션타입에 이름을 준다. 

// f를 compare로 할당할 때 int f(Object, Object)의 타입정보가 사라진다.

class SortedCollection {

  Function compare;


  SortedCollection(int f(Object a, Object b)) {

    compare = f;

  }

}


// typedef로 펑션타입을 정의한다.

typedef int Compare(Object a, Object b);


class SortedCollection {

  Compare compare;


  SortedCollection(this.compare);

}




메타데이터 (Metadata)


  -  메타데이터는 추가적인 정보를 주기위해 사용한다. @ 키워드로 애노테이션을 사용한다. 

  - @deprecated, @override, @proxy 등의 메타데이터 애노테이션을 사용한다. 

  - 커멘트는 한줄 // 사용하고 다중은 /* */을 사용한다. 




참조 

  

  - 다트 기초 

  - 구글 취업이 원하는 인재상 : 지적 겸손에 대하여

  - 자바스트립트에서의 lexical scope와 this의 의미 번역 (원문)

  - 컴퓨터 사이언스에서 Lexical Scope 위키피디아

  - Dart Slides 및 동영상

  - Dart VM으로 서버 만들기 Framework 종류

posted by Peter Note
prev 1 next