Protobuf 메시지

Python 클라이언트 라이브러리 버전 14.0.0에는 라이브러리에서 proto-plus 메시지 또는 protobuf 메시지를 반환할지 여부를 지정하는 use_proto_plus라는 새로운 필수 구성 매개변수가 도입되었습니다. 이 매개변수를 설정하는 방법에 관한 자세한 내용은 구성 문서를 참고하세요.

이 섹션에서는 사용할 메시지 유형을 선택할 때 성능에 미치는 영향을 설명합니다. 따라서 충분한 정보를 바탕으로 결정을 내리려면 옵션을 읽고 이해하는 것이 좋습니다. 그러나 코드를 변경하지 않고 14.0.0 버전으로 업그레이드하려면 use_proto_plusTrue로 설정하여 인터페이스가 브레이킹 체인지되는 것을 방지할 수 있습니다.

Proto Plus 메시지와 protobuf 메시지

10.0.0 버전에서 Python 클라이언트 라이브러리가 새로운 코드 생성기 파이프라인으로 이전되었습니다. 이 파이프라인은 proto-plus를 네이티브 Python 객체처럼 동작하도록 하여 protobuf 메시지 인터페이스의 인체공학을 개선하는 방법으로 통합했습니다. 이러한 개선의 단점은 Proto-Plus로 인해 성능 오버헤드가 발생한다는 것입니다.

Proto Plus 성능

proto-plus의 주요 이점 중 하나는 유형 마샬링이라는 프로세스를 통해 protobuf 메시지잘 알려진 유형을 네이티브 Python 유형으로 변환한다는 것입니다.

마샬링은 proto-plus 메시지 인스턴스에서 필드에 액세스할 때, 특히 protobuf 정의에서와 같이 필드가 읽히거나 설정된 경우에 발생합니다.

syntax = "proto3";

message Dog {
  string name = 1;
}

이 정의가 proto-plus 클래스로 변환되면 다음과 같이 표시됩니다.

import proto

class Dog(proto.Message):
    name = proto.Field(proto.STRING, number=1)

그런 다음 Dog 클래스를 초기화하고 다른 Python 객체와 마찬가지로 name 필드에 액세스할 수 있습니다.

dog = Dog()
dog.name = "Scruffy"
print(dog.name)

name 필드를 읽고 설정할 때 값이 protobuf 런타임과 호환되도록 네이티브 Python str 유형에서 string 유형으로 변환됩니다.

10.0.0 버전 출시 이후 진행한 분석에 따르면 이러한 유형 변환에 소요되는 시간이 성능에 큰 영향을 미치므로 사용자에게 protobuf 메시지를 사용할 수 있는 옵션을 제공하는 것이 중요합니다.

proto-plus 및 protobuf 메시지의 사용 사례

Proto + 메시지 사용 사례
Proto-plus는 protobuf 메시지에 비해 인체공학적으로 개선된 여러 가지 기능을 제공하므로 유지관리 및 읽기 쉬운 코드를 작성하는 데 이상적입니다. 네이티브 Python 객체를 노출하므로 사용하고 이해하기가 더 쉽습니다.
Protobuf 메시지 사용 사례
성능에 민감한 사용 사례, 특히 대용량 보고서를 빠르게 처리해야 하거나 BatchJobService 또는 OfflineUserDataJobService를 사용하는 등 많은 수의 작업으로 변경 요청을 빌드하는 앱에서 protobuf를 사용하세요.

동적으로 메시지 유형 변경

앱에 적합한 메시지 유형을 선택한 후에는 특정 워크플로에 다른 유형을 사용해야 한다는 것을 알게 될 수도 있습니다. 이 경우 클라이언트 라이브러리에서 제공하는 유틸리티를 사용하여 두 유형 간에 쉽게 전환할 수 있습니다. 위와 동일한 Dog 메시지 클래스 사용:

from google.ads.googleads import util

# Proto-plus message type
dog = Dog()

# Protobuf message type
dog = util.convert_proto_plus_to_protobuf(dog)

# Back to proto-plus message type
dog = util.convert_protobuf_to_proto_plus(dog)

Protobuf 메시지 인터페이스 차이점

proto-plus 인터페이스는 자세히 문서화되어 있지만, 여기서는 Google Ads 클라이언트 라이브러리의 일반적인 사용 사례에 영향을 미치는 몇 가지 주요 차이점을 살펴보겠습니다.

바이트 직렬화

Proto Plus 메시지
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Protobuf 메시지
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

JSON 직렬화

Proto Plus 메시지
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Protobuf 메시지
from google.protobuf.json_format import MessageToJson, Parse

serialized = MessageToJson(campaign)
deserialized = Parse(serialized, campaign)

필드 마스크

api-core에서 제공하는 필드 마스크 도우미 메서드는 protobuf 메시지 인스턴스를 사용하도록 설계되었습니다. 따라서 proto+ 메시지를 사용할 때는 도우미를 활용할 수 있도록 protobuf 메시지로 변환하세요.

Proto Plus 메시지
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
protobuf_campaign = util.convert_proto_plus_to_protobuf(campaign)
mask = field_mask(None, protobuf_campaign)
Protobuf 메시지
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
mask = field_mask(None, campaign)

열거형

proto-plus 메시지에 의해 노출되는 enum은 Python의 네이티브 enum 유형의 인스턴스이므로 여러 편의 메서드를 상속합니다.

enum 유형 검색

GoogleAdsClient.get_type 메서드를 사용하여 enum을 검색할 경우 반환되는 메시지는 proto-plus 또는 protobuf 메시지를 사용하는지에 따라 약간 다릅니다. 예를 들면 다음과 같습니다.

Proto Plus 메시지
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Protobuf 메시지
val = client.get_type("CampaignStatusEnum").PAUSED

enum을 더 간단하게 검색할 수 있도록 사용 중인 메시지 유형과 관계없이 일관된 인터페이스를 갖는 GoogleAdsClient 인스턴스에 편의성 속성이 있습니다.

val = client.enums.CampaignStatusEnum.PAUSED

열거형 값 검색

지정된 enum의 값 또는 필드 ID를 아는 것이 유용한 경우도 있습니다. 예를 들어 CampaignStatusEnumPAUSED3에 해당합니다.

Proto Plus 메시지
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the value of campaign status
print(campaign.status.value)
Protobuf 메시지
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
campaign.status = status_enum.PAUSED
# To read the value of campaign status
print(status_enum.CampaignStatus.Value(campaign.status))

enum 이름 검색

enum 필드의 이름을 아는 것이 유용할 때가 있습니다. 예를 들어 API에서 객체를 읽을 때 int 3가 해당하는 캠페인 상태를 알아야 할 수 있습니다.

Proto Plus 메시지
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
Protobuf 메시지
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
# Sets the campaign status to the int value for PAUSED
campaign.status = status_enum.PAUSED
# To read the name of campaign status
status_enum.CampaignStatus.Name(campaign.status)

반복 필드

proto-plus 문서에 설명된 대로 반복되는 필드는 일반적으로 유형이 지정된 목록과 동일하며, 이는 list와 거의 동일하게 동작합니다.

반복되는 스칼라 필드에 추가

반복되는 스칼라 유형 필드(예: string 또는 int64 필드)에 값을 추가할 때 인터페이스는 메시지 유형에 관계없이 동일합니다.

Proto Plus 메시지
ad.final_urls.append("https://www.example.com")
Protobuf 메시지
ad.final_urls.append("https://www.example.com")

여기에는 다른 모든 일반적인 list 메서드도 포함됩니다(예: extend).

Proto Plus 메시지
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Protobuf 메시지
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])

반복되는 필드에 메시지 유형 추가

반복되는 필드가 스칼라 유형이 아닌 경우 반복되는 필드에 추가할 때의 동작이 약간 다릅니다.

Proto Plus 메시지
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Protobuf 메시지
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

반복 필드 할당

스칼라 및 비스칼라 반복 필드의 경우 모두 여러 가지 방법으로 필드에 목록을 할당할 수 있습니다.

Proto Plus 메시지
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Protobuf 메시지
# Protobuf messages do not allow assignment, but you can replace the
# existing list using slice syntax.
urls = ["https://www.example.com"]
ad.final_urls[:] = urls

빈 메일

메시지 인스턴스에 정보가 포함되어 있는지 또는 필드가 설정되어 있는지 아는 것이 유용한 경우가 있습니다.

Proto Plus 메시지
# When using proto-plus messages you can simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not campaign
Protobuf 메시지
is_empty = campaign.ByteSize() == 0

메시지 사본

proto-plus 및 protobuf 메시지의 경우 모두 GoogleAdsClient에서 copy_from 도우미 메서드를 사용하는 것이 좋습니다.

client.copy_from(campaign, other_campaign)

빈 메시지 필드

빈 메시지 필드를 설정하는 프로세스는 사용 중인 메시지 유형에 관계없이 동일합니다. 해당 필드에 빈 메시지를 복사하기만 하면 됩니다. 메시지 사본 섹션과 빈 메시지 필드 가이드를 참고하세요. 다음은 빈 메시지 필드를 설정하는 방법의 예입니다.

client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))

예약된 단어인 필드 이름

proto-plus 메시지를 사용할 때, 이름이 Python의 예약어인 경우 필드 이름에 자동으로 맨 뒤에 밑줄이 표시됩니다. 다음은 Asset 인스턴스를 사용하는 예입니다.

asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE

예약된 이름의 전체 목록갭 생성기 모듈에서 구성됩니다. 프로그래매틱 방식으로 액세스할 수도 있습니다.

먼저 모듈을 설치합니다.

python -m pip install gapic-generator

그런 다음 Python REPL 또는 스크립트에서 다음을 실행합니다.

import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)

필드 정보

protobuf 메시지 인스턴스의 필드에는 기본값이 있으므로 필드의 설정 여부를 항상 직관적으로 알 수 있는 것은 아닙니다.

Proto Plus 메시지
# Use the "in" operator.
has_field = "name" in campaign
Protobuf 메시지
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

protobuf Message 클래스 인터페이스에는 메시지의 필드가 기본값으로 설정되어 있는지 여부를 확인하는 HasField 메서드가 있습니다.

Protobuf 메시지 메서드

protobuf 메시지 인터페이스에는 proto-plus 인터페이스에 포함되지 않은 몇 가지 편의 메서드가 포함되어 있습니다. 하지만 proto-plus 메시지를 protobuf 메시지로 변환하여 간단하게 액세스할 수 있습니다.

# Accessing the ListFields method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.ListFields())

# Accessing the Clear method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.Clear())

Issue Tracker

이러한 변경사항에 관해 궁금한 점이 있거나 라이브러리 14.0.0 버전으로 이전하는 데 문제가 있는 경우 추적기에서 문제를 신고해 주세요.