code: func (m *Message) Attr(name string) (starlark.Value, error) {
  	// The field was already set?
  	val, ok := m.fields[name]
  	if ok {
  		return val, nil
  	}
  
  	// The field wasn't set, but it is defined by the proto schema? Need to
  	// generate and return the default value then, except for oneof alternatives
  	// that do not have defaults. This is needed to make sure callers are
  	// explicitly picking a oneof alternative by assigning a value to it, rather
  	// than have it picked implicitly be reading an attribute (which is weird).
  	if fd, ok := m.typ.fields[name]; ok {
  		if !fd.defaultable {
  			return starlark.None, nil
  		}
  		def, err := newDefaultValue(fd.typ)
  		if err != nil {
  			return nil, err
  		}
  		// Lazy initialization of fields is an implementation detail. From the
  		// caller's point of view, all fields had their default values even before
  		// the object was frozen. Lazy-initialize the field, even if we are frozen,
  		// but make sure it is frozen itself too.
  		//
  		// TODO(vadimsh): This is not thread safe and should be improved if a frozen
  		// *Message is shared between goroutines. Generally frozen values are
  		// assumed to be safe for cross-goroutine use, which is not the case here.
  		// If this becomes important, we can force-initialize and freeze all default
  		// fields in Freeze().
  		if m.frozen {
  			def.Freeze()
  		}
  		m.fields[name] = def
  		return def, nil
  	}
  
  	return nil, fmt.Errorf("proto message %q has no field %q", m.Type(), name)
  }
docs: // HasAttrs and HasSetField interfaces that make the message look like a struct.
  // Attr implements starlark.HasAttrs.