הודעות לפרוטוקול

באמצעות פרמטר ההגדרה 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.

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

כדי לפשט את השליפה של ערכי enum, יש מאפיין נוחות במופעים של 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
# Native protobuf enum fields already store the integer value (3):
print(campaign.status)
# Or look up the integer value from the enum name string:
print(status_enum.CampaignStatus.Value("PAUSED"))

אחזור שם של טיפוס בן מנייה (enum)

לפעמים כדאי לדעת את השם של שדה enum. לדוגמה, כשקוראים אובייקטים מה-API, יכול להיות שתרצו לדעת לאיזה סטטוס קמפיין מתאים המספר השלם 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
print(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 check the message for truthiness.
is_empty = not bool(campaign)
הודעות Protobuf
is_empty = campaign.ByteSize() == 0

העתקת ההודעה

גם להודעות proto-plus וגם להודעות protobuf, משתמשים ב-method העזר 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")

לממשק המחלקה Message של protobuf יש שיטה HasField שקובעת אם הוגדרו הודעת משנה, שדה oneof או שדה סקלרי optional בהודעה, גם אם הם הוגדרו לערך ברירת מחדל. (קריאה ל-HasField בשדות סקלריים לא אופציונליים ב-proto3 מעלה ValueError.)

שיטות של הודעות Protobuf

ממשק ההודעות של protobuf כולל כמה שיטות נוחות שלא נכללות בממשק של proto-plus, אבל אפשר לגשת אליהן על ידי המרה של הודעת proto-plus להודעת protobuf המקבילה:

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

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

Issue Tracker

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