رسائل Protobuf

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

يصف هذا القسم تأثيرات الأداء لكل خيار حتى تتمكّن من اختيار أفضل نهج لتطبيقك.

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

تدمج مسارات إنشاء الرموز البرمجية proto-plus كطريقة لتحسين سهولة استخدام واجهة رسائل protobuf من خلال جعلها تعمل بشكل يشبه كائنات Python العادية. ومع ذلك، يعني هذا أنّ استخدام 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 والوصول إلى حقل 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".

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

رسائل 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. When using proto-plus messages, convert them to protobuf messages to use the helper:

رسائل 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، وبالتالي تكتسب عددًا من الطرق المريحة.

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

When using the GoogleAdsClient.get_type method to retrieve enums, the messages that are returned are slightly different depending on whether you're using proto-plus or protobuf messages. على سبيل المثال:

رسائل Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
رسائل Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

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

val = client.enums.CampaignStatusEnum.PAUSED

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

Sometimes it's useful to know the value, or field ID, of a given enum, for example, PAUSED on CampaignStatusEnum corresponds to 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"))

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

في بعض الأحيان، يكون من المفيد معرفة اسم حقل تعداد. على سبيل المثال، عند قراءة العناصر من واجهة برمجة التطبيقات، قد تريد معرفة حالة الحملة التي يتوافق معها العدد الصحيح 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، استخدِم طريقة المساعدة 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

بعد ذلك، في 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 تحدّد ما إذا تم ضبط رسالة فرعية أو حقل 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.