code: def face_normals(self):
          
          # check shape of cached normals
          cached = self._cache['face_normals']
          if np.shape(cached) == np.shape(self._data['faces']):
              return cached
  
          log.debug('generating face normals')
          # use cached triangle cross products to generate normals
          # this will always return the correct shape but some values
          # will be zero or an arbitrary vector if the inputs had
          # a cross product below machine epsilon
          normals, valid = triangles.normals(
              triangles=self.triangles,
              crosses=self.triangles_cross)
  
          # if all triangles are valid shape is correct
          if valid.all():
              # put calculated face normals into cache manually
              self._cache['face_normals'] = normals
              return normals
  
          # make a padded list of normals for correct shape
          padded = np.zeros((len(self.triangles), 3),
                            dtype=np.float64)
          padded[valid] = normals
  
          # put calculated face normals into cache manually
          self._cache['face_normals'] = padded
  
          return padded
docs: Return the unit normal vector for each face.
  
          If a face is degenerate and a normal can't be generated
          a zero magnitude unit vector will be returned for that face.
  
          Returns
          -----------
          normals : (len(self.faces), 3) np.float64
            Normal vectors of each face