הודעות Protobuf

באמצעות פרמטר ההגדרה use_proto_plus, אפשר לציין אם רוצים שהספרייה תחזיר הודעות proto-plus או הודעות protobuf. פרטים נוספים על הגדרת הפרמטר הזה זמינים במסמכי ההגדרה.

בקטע הזה מתוארות ההשלכות על הביצועים של הבחירה בסוגי ההודעות שבהן כדאי להשתמש. לכן מומלץ לקרוא ולהבין את האפשרויות כדי לקבל החלטה מושכלת.

ההבדלים בין הודעות Proto-plus לבין הודעות protobuf

צינור יצירת הקוד משלב את proto-plus כדי לשפר את הארגונומיה של ממשק הודעות protobuf, כך שההודעות יתנהגו יותר כמו אובייקטים מקוריים של Python. עם זאת, המשמעות היא שהשימוש ב-proto-plus מוסיף תקורה לביצועים.

ביצועים של Proto-plus

אחד היתרונות העיקריים של proto-plus הוא שהוא ממיר הודעות protobuf וסוגים מוכרים לסוגים מקוריים של Python בתהליך שנקרא type marshaling.

ההמרה מתרחשת כשניגשים לשדה במופע של הודעת 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 ולגשת לשדה name שלה כמו לכל אובייקט אחר של Python:

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

כשקוראים את השדה name ומגדירים אותו, הערך מומר מסוג str של Python מקורי לסוג string כדי שהערך יהיה תואם לזמן הריצה של protobuf.

על סמך ניתוחי הביצועים שלנו, הגענו למסקנה שהזמן שנדרש לביצוע המרות מסוג זה משפיע על הביצועים במידה כזו שמשתמשים צריכים להחליט, על סמך הצרכים שלהם, אם להשתמש בהודעות protobuf או לא.

תרחישי שימוש בהודעות proto-plus ו-protobuf

תרחישים לדוגמה לשימוש בהודעות בפורמט Proto-plus
Proto-plus מציע מספר שיפורים ארגונומיים בהשוואה להודעות protobuf, ולכן הוא אידיאלי לכתיבת קוד שקל לתחזק ולקרוא. הן חושפות אובייקטים מקוריים של Python, ולכן קל יותר להשתמש בהן ולהבין אותן.
תרחישים לדוגמה לשימוש בהודעות Protobuf
מומלץ להשתמש ב-protobufs בתרחישי שימוש שבהם הביצועים חשובים, במיוחד באפליקציות שצריכות לעבד במהירות דוחות גדולים, או באפליקציות שיוצרות בקשות לשינוי עם מספר גדול של פעולות, למשל עם BatchJobService או עם OfflineUserDataJobService.

שינוי דינמי של סוגי ההודעות

אחרי שבוחרים את סוג ההודעה המתאים לאפליקציה, יכול להיות שתצטרכו להשתמש בסוג השני עבור תהליך עבודה ספציפי. במקרה כזה, קל לעבור בין שני הסוגים באופן דינמי באמצעות כלי עזר שמוצעים בספריית הלקוח. שימוש באותו 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-plus, צריך להמיר אותן להודעות 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)

טיפוסים בני מנייה (enum)

סוגי ה-Enum שנחשפים על ידי הודעות proto-plus הם מופעים של הסוג המקורי enum של Python, ולכן הם יורשים מספר שיטות נוחות.

אחזור של סוג enum

כשמשתמשים בשיטה GoogleAdsClient.get_type כדי לאחזר סוגי enum, ההודעות שמוחזרות שונות מעט בהתאם לסוג ההודעות שבהן משתמשים: proto-plus או protobuf. לדוגמה:

הודעות בפורמט Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
הודעות Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

כדי לפשט את השליפה של סוגי הנתונים המנויים, יש מאפיין נוחות במופעים של GoogleAdsClient עם ממשק עקבי, לא משנה באיזה סוג הודעה משתמשים:

val = client.enums.CampaignStatusEnum.PAUSED

אחזור ערך enum

לפעמים כדאי לדעת את הערך או את מזהה השדה של enum מסוים. לדוגמה, PAUSED ב-CampaignStatusEnum מתאים ל-3:

הודעות בפורמט 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, מומלץ להשתמש בשיטת העזר copy_from ב-GoogleAdsClient:

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

הרשימה המלאה של שמות שמורים נוצרת במודול gapic generator. אפשר לגשת אליו גם באופן פרוגרמטי.

קודם כול, מתקינים את המודול:

python -m pip install gapic-generator

לאחר מכן, בסקריפט או ב-REPL של Python:

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())

מעקב אחר בעיות

אם יש לכם שאלות לגבי השינויים האלה או בעיות במעבר לגרסה העדכנית של הספרייה, אתם יכולים לדווח על בעיה בכלי למעקב אחרי בעיות.