رسائل Protobuf

يقدّم إصدار 14.0.0 من مكتبة برامج Python مَعلمة إعداد جديدة مطلوبة تُسمى use_proto_plus وتحدّد ما إذا كنت تريد من المكتبة عرض رسائل Proto-plus أو رسائل Protobuf. ولمعرفة تفاصيل عن كيفية ضبط هذه المَعلمة، يُرجى الاطّلاع على مستندات الضبط.

يصف هذا القسم الآثار المترتبة على اختيار أنواع الرسائل التي سيتم استخدامها، لذلك ننصحك بقراءة الخيارات وفهمها واتّخاذ قرار مدروس. مع ذلك، إذا أردت الترقية إلى الإصدار 14.0.0 بدون إجراء تغييرات على الرمز، يمكنك ضبط use_proto_plus على True لتجنُّب تعطُّل التغييرات في الواجهة.

Proto-plus مقابل رسائل Protobuf

في الإصدار 10.0.0، تم نقل مكتبة برامج Python إلى مسار إنشاء رموز جديد يدمج proto-plus كوسيلة لتحسين بيئة واجهة رسالة Protobuf من خلال جعلها تتصرف بشكل أشبه بكائنات Python الأصلية. المقايضة من هذا التحسين هو أن النموذج الأوّلي بالإضافة إلى يقدم النفقات العامة للأداء.

أداء 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.

في التحليل الذي أجريناه منذ إطلاق الإصدار 10.0.0، توصّلنا إلى أنّ الوقت المستغرق في إجراء هذه النوعية من الإحالات الناجحة له تأثير كبير بما يكفي على الأداء، وبالتالي يجب منح المستخدمين خيار استخدام رسائل النموذج الأوّلي.

حالات الاستخدام الخاصة برسائل Proto-plus وProtobuf

حالات استخدام رسالة Proto-plus
يوفّر Proto-plus عددًا من التحسينات المريحة مقارنةً بالرسائل الأوّلية، لذا فهي مثالية لكتابة رموز برمجية سهلة القراءة وقابلة للصيانة. وبما أنّها تعرض كائنات Python الأصلية، يسهل استخدامها وفهمها.
حالات استخدام رسالة Protobuf
استخدِم النماذج الأولية لحالات الاستخدام الحسّاسة للأداء، وخاصةً في التطبيقات التي تحتاج إلى معالجة تقارير كبيرة بسرعة، أو التي تنشئ طلبات تغيير باستخدام عدد كبير من العمليات، على سبيل المثال مع 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)

الاختلافات في واجهة رسالة النموذج الأوّلي

واجهة Proto-plus موثقة بالتفصيل، ولكننا سنسلط الضوء هنا على بعض الاختلافات الرئيسية التي تؤثر في حالات الاستخدام الشائعة لمكتبة عملاء "إعلانات Google".

تسلسل وحدات البايت

رسائل Proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
رسائل النموذج الأولي
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

تسلسل JSON

رسائل Proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
رسائل النموذج الأولي
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)
رسائل النموذج الأولي
from google.api_core.protobuf_helpers import field_mask

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

عمليات التعداد

إن التعدادات التي يتم الكشف عنها من خلال رسائل Proto-plus هي مثيلات من النوع enum الأصلي في Python، وبالتالي تكتسب عددًا من الطرق الملائمة.

استرداد نوع التعداد

عند استخدام طريقة GoogleAdsClient.get_type لاسترداد التعدادات، تكون الرسائل التي يتم عرضها مختلفة قليلاً بناءً على ما إذا كنت تستخدم رسائل Proto-plus أو protobuf. مثلاً:

رسائل Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
رسائل النموذج الأولي
val = client.get_type("CampaignStatusEnum").PAUSED

لتبسيط عملية استرداد التعدادات، هناك سمة ملائمة في مثيلات GoogleAdsClient التي لها واجهة متسقة بغض النظر عن نوع الرسالة الذي تستخدمه:

val = client.enums.CampaignStatusEnum.PAUSED

استرداد قيمة التعداد

قد يكون من المفيد أحيانًا معرفة القيمة أو معرّف الحقل لتعداد معيّن، مثلاً، تتجاوب 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)
رسائل النموذج الأولي
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))

استرداد اسم التعداد

قد يكون من المفيد أحيانًا معرفة اسم حقل تعداد. على سبيل المثال، عند قراءة كائنات من واجهة برمجة التطبيقات، قد ترغب في معرفة حالة الحملة التي تتوافق معها 3 int:

رسائل Proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
رسائل النموذج الأولي
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")
رسائل النموذج الأولي
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"])
رسائل النموذج الأولي
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)
رسائل النموذج الأولي
# 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 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
رسائل النموذج الأولي
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، تظهر أسماء الحقول تلقائيًا مع شرطة سفلية لاحقة إذا كان الاسم أيضًا كلمة محجوزة في بايثون. إليك مثال على استخدام مثيل Asset:

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

يتم إنشاء القائمة الكاملة للأسماء المحجوزة في وحدة منشئ gapic. يمكن الوصول إليها برمجيًا أيضًا.

أولاً، ثبِّت الوحدة:

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
رسائل النموذج الأولي
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())

أداة تتبّع المشاكل

إذا كانت لديك أي أسئلة حول هذه التغييرات أو أي مشاكل في نقل البيانات إلى الإصدار 14.0.0 من المكتبة، يمكنك الإبلاغ عن مشكلة في جهاز التتبّع.