class_docstr: DataHandler with **(L)earnable (P)rocessor**
  
  This handler will produce three pieces of data in pd.DataFrame format.
  
  - DK_R / self._data: the raw data loaded from the loader
  - DK_I / self._infer: the data processed for inference
  - DK_L / self._learn: the data processed for learning model.
  
  The motivation of using different processor workflows for learning and inference
  Here are some examples.
  
  - The instrument universe for learning and inference may be different.
  - The processing of some samples may rely on label (for example, some samples hit the limit may need extra processing or be dropped).
  
      - These processors only apply to the learning phase.
  
  Tips for data handler
  
  - To reduce the memory cost
  
      - `drop_raw=True`: this will modify the data inplace on raw data;
  
  - Please note processed data like `self._infer` or `self._learn` are concepts different from `segments` in Qlib's `Dataset` like "train" and "test"
  
      - Processed data like `self._infer` or `self._learn` are underlying data processed with different processors
      - `segments` in Qlib's `Dataset` like "train" and "test" are simply the time segmentations when querying data("train" are often before "test" in time-series).
      - For example, you can query `data._infer` processed by `infer_processors` in the "train" time segmentation.
docstr: Motivation:
  - When user want to get a quick data handler.
  
  The created data handler will have only one shared Dataframe without processors.
  After creating the handler, user may often want to dump the handler for reuse
  Here is a typical use case
  
  .. code-block:: python
  
      from qlib.data.dataset import DataHandlerLP
      dh = DataHandlerLP.from_df(df)
      dh.to_pickle(fname, dump_all=True)
  
  TODO:
  - The StaticDataLoader is quite slow. It don't have to copy the data again...
code: def from_df(cls, df: pd.DataFrame) -> "DataHandlerLP":
      """
      Motivation:
      - When user want to get a quick data handler.
  
      The created data handler will have only one shared Dataframe without processors.
      After creating the handler, user may often want to dump the handler for reuse
      Here is a typical use case
  
      .. code-block:: python
  
          from qlib.data.dataset import DataHandlerLP
          dh = DataHandlerLP.from_df(df)
          dh.to_pickle(fname, dump_all=True)
  
      TODO:
      - The StaticDataLoader is quite slow. It don't have to copy the data again...
  
      """
      loader = data_loader_module.StaticDataLoader(df)
      return cls(data_loader=loader)
  
imports: import warnings
  from typing import Callable, Union, Tuple, List, Iterator, Optional
  import pandas
  from qlib.typehint import Literal
  from ...log import get_module_logger, TimeInspector
  from ...utils import init_instance_by_config
  from ...utils.serial import Serializable
  from .utils import fetch_df_by_index, fetch_df_by_col
  from ...utils import lazy_sort_index
  from .loader import DataLoader
  from .None import processor
  from .None import loader
label_desc: Use image node_id 14 for calling the DataHandlerLP obj's underlying member method code with example usage: obj.from_df(cls, df) and returns: cls