הודעות Protobuf

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

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

הודעות Proto-plus לעומת Protobuf

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

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

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

סידור נתונים מתרחש כשניגשים לשדה במכונה של הודעת Proto-plus, במיוחד כשקוראים או מגדירים שדה, למשל בהגדרת אב-טיפוס:

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.

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

תרחישים לדוגמה להודעות מסוג Proto-Plus ו-protobuf

תרחישים לדוגמה של שליחת הודעות אל Proto
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
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
הודעות Protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

סריאליזציה ל-JSON

הודעות Proto
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)

מסכות שדה

רכיב ה-method Helper של התממת השדה שמסופק על ידי api-core נועד להשתמש במופעים של הודעות מסוג protobuf. לכן, כשמשתמשים בהודעות מסוג proto+, צריך להמיר אותן להודעות protobuf כדי להשתמש בכלי העזר:

הודעות Proto
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)

מספרים שנחשפים באמצעות הודעות Proto-+ הם מופעים של סוג enum המקורי של Python, ולכן יורשים מספר שיטות נוחות.

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

כשמשתמשים בשיטה GoogleAdsClient.get_type כדי לאחזר טיפוסים בני מנייה (enum), ההודעות שמוחזרים משתנות מעט בהתאם לאופן שבו משתמשים בהודעות מסוג Proto-Plus או Protobuf. למשל:

הודעות Proto
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
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
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)

שדות חוזרים

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

צירוף לשדות סקלריים חוזרים

כשמוסיפים ערכים לשדות חוזרים של סוג סקלר, לדוגמה string או int64, הממשק זהה ללא קשר לסוג ההודעה:

הודעות Proto
ad.final_urls.append("https://www.example.com")
הודעות Protobuf
ad.final_urls.append("https://www.example.com")

זה כולל גם את כל שאר השיטות הנפוצות של list, לדוגמה extend:

הודעות Proto
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
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
# 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
# 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)

שדות ריקים של הודעות

התהליך להגדרת שדות של הודעות ריקות הוא זהה, ללא קשר לסוג ההודעה. אתם רק צריכים להעתיק הודעה ריקה בשדה הרלוונטי. פרטים נוספים מופיעים בקטע Message copy ובמדריך Empty Message Fields (שדות הודעות ריקים). דוגמה להגדרת שדה הודעה ריק:

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 Gen. אפשר לגשת אליו גם באופן פרוגרמטי.

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

python -m pip install gapic-generator

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

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

נוכחות בשדה

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

הודעות Proto
# 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 יש method HasField שקובעת אם השדה בהודעה הוגדר, גם אם הוא הוגדר לערך ברירת מחדל.

שיטות הודעה ב-Protobuf

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

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

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