生成的代码参考

生成的代码参考

gRPC Python 依赖于协议缓冲区编译器 (protoc) 生成代码。它使用一个插件来补充由普通 protoc 生成的代码,使其包含 gRPC 特定的代码。对于包含 gRPC 服务的 .proto 服务描述,普通 protoc 生成的代码会被合成到 _pb2.py 文件中,而 gRPC 特定的代码则会放到 _pb2_grpc.py 文件中。后者 Python 模块会导入前者。本页的重点是生成代码中 gRPC 特定的子集。

示例

考虑以下 FortuneTeller proto 服务

service FortuneTeller {
  // Returns the horoscope and zodiac sign for the given month and day.
  rpc TellFortune(HoroscopeRequest) returns (HoroscopeResponse) {
    // errors: invalid month or day, fortune unavailable
  }

  // Replaces the fortune for the given zodiac sign with the provided one.
  rpc SuggestFortune(SuggestionRequest) returns (SuggestionResponse) {
    // errors: invalid zodiac sign
  }
}

当服务被编译时,gRPC protoc 插件会生成类似于以下 _pb2_grpc.py 文件的代码

import grpc

import fortune_pb2

class FortuneTellerStub(object):

  def __init__(self, channel):
    """Constructor.

    Args:
      channel: A grpc.Channel.
    """
    self.TellFortune = channel.unary_unary(
        '/example.FortuneTeller/TellFortune',
        request_serializer=fortune_pb2.HoroscopeRequest.SerializeToString,
        response_deserializer=fortune_pb2.HoroscopeResponse.FromString,
        )
    self.SuggestFortune = channel.unary_unary(
        '/example.FortuneTeller/SuggestFortune',
        request_serializer=fortune_pb2.SuggestionRequest.SerializeToString,
        response_deserializer=fortune_pb2.SuggestionResponse.FromString,
        )


class FortuneTellerServicer(object):

  def TellFortune(self, request, context):
    """Returns the horoscope and zodiac sign for the given month and day.
    errors: invalid month or day, fortune unavailable
    """
    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
    context.set_details('Method not implemented!')
    raise NotImplementedError('Method not implemented!')

  def SuggestFortune(self, request, context):
    """Replaces the fortune for the given zodiac sign with the provided
one.
    errors: invalid zodiac sign
    """
    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
    context.set_details('Method not implemented!')
    raise NotImplementedError('Method not implemented!')


def add_FortuneTellerServicer_to_server(servicer, server):
  rpc_method_handlers = {
      'TellFortune': grpc.unary_unary_rpc_method_handler(
          servicer.TellFortune,
          request_deserializer=fortune_pb2.HoroscopeRequest.FromString,
          response_serializer=fortune_pb2.HoroscopeResponse.SerializeToString,
      ),
      'SuggestFortune': grpc.unary_unary_rpc_method_handler(
          servicer.SuggestFortune,
          request_deserializer=fortune_pb2.SuggestionRequest.FromString,
          response_serializer=fortune_pb2.SuggestionResponse.SerializeToString,
      ),
  }
  generic_handler = grpc.method_handlers_generic_handler(
      'example.FortuneTeller', rpc_method_handlers)
  server.add_generic_rpc_handlers((generic_handler,))

代码元素

gRPC 生成的代码首先导入 grpc 包和由 protoc 合成的普通 _pb2 模块,该模块定义了非 gRPC 特定的代码元素,例如与协议缓冲区消息和反射所用描述符对应的类。

对于 .proto 文件中的每个服务 Foo,会生成三个主要元素

Stub

生成的 Stub 类供 gRPC 客户端使用。它有一个构造函数,接受一个 grpc.Channel 对象并初始化该存根。对于服务中的每个方法,初始化器会向存根对象添加一个同名的相应属性。根据 RPC 类型(一元或流式),该属性的值将是可调用对象,类型为 UnaryUnaryMultiCallableUnaryStreamMultiCallableStreamUnaryMultiCallableStreamStreamMultiCallable

Servicer

对于每个服务,都会生成一个 Servicer 类,它作为服务实现的超类。对于服务中的每个方法,Servicer 类中都会生成一个相应的函数。用服务实现来覆盖此函数。与 .proto 文件中代码元素相关的注释会作为文档字符串出现在生成的 Python 代码中。

注册函数

对于每个服务,都会生成一个函数,用于在 grpc.Server 对象上注册实现该服务的 Servicer 对象,以便服务器可以将查询路由到相应的服务实现者。此函数接受一个实现 Servicer 的对象(通常是上述生成的 Servicer 代码元素的子类实例)和一个 grpc.Server 对象。