[coding] Decorator

自定义decorator 格式是: def decorator name func : def wrapper args, kwargs : func args, kwargs other func return results return wrapper 比如下面这个 from fasthtml.common import import numpy as

自定义decorator

格式是:

def decorator_name(func):

  def wrapper(*args, **kwargs):
      func(*args, **kwargs) 
      other func
      return results

  return wrapper

比如下面这个

from fasthtml.common import *
import numpy as np, seaborn as sns, matplotlib.pylab as plt

def fh_svg(func):
  "show svg in fasthtml decorator"
  def wrapper(*args, **kwargs):
      func(*args, **kwargs) # calls plotting function
      f = io.StringIO() # create a buffer to store svg data
      plt.savefig(f, format='svg', bbox_inches='tight')
      f.seek(0) # beginning of file
      svg_data = f.getvalue()
      plt.close()
      return NotStr(svg_data)
  return wrapper

@fh_svg
def plot_heatmap(matrix,figsize=(6,7),**kwargs):
  plt.figure(figsize=figsize)
  sns.heatmap(matrix, cmap='coolwarm', annot=False,**kwargs)

@delegates(func)

解释**kwargs

from fastcore.meta import delegates

def func1(a,b): return a+b

@delegates(func1)
def func2(c,**kwargs): return c+ func1(**kwargs)

测的时候用双问号,比如

func2??

@classmethod

function里第一个放cls, 用的时候就是ClassName.class_method()

class ClassName:
    def __init__(self, arg1, arg2):
        self.arg1 = arg1  # instance attribute

    def method1(self):
        # instance method
        print(f"arg1 is {self.arg1}")

    @classmethod
    def class_method(cls):
        # class method
        print("This is a class method")

function本身可以反过来影响class里面的attributes

class Dog:
    species = "Canis familiaris"
    
    def __init__(self, name):
        self.name = name

    @classmethod
    def set_species(cls, new_species):
        cls.species = new_species

比如可以用

Dog.set_species("Canis lupus") # 会改变self.species

@staticmethod

和一般定义的function是一样的,只不过为了整洁放到了class里面,它并不会反过来 影响class

放在一个class里的function上,同时注意function里不要加self

class Data:

    @staticmethod
    def func(url): return query(url)

用的时候,可以省略class的括号,直接query。比如

Data.func(url)

@lru_cache 保存读取

可以保存function的output in cache, 下次就不会再重新读取。对于大数据很好用

@lru_cache
def get_data(): return pd.read_parquet('data.parquet')

注意()里不能放argument,所以在class里的func一般都是func(self),这个时候只需在上面加一个staticmethod即可,这样就不用加self了

@staticmethod
@lru_cache
def get_data(): return pd.read_parquet('data.parquet')

@njit

njit是jit(nonpython=True)的version。nonpython=True时,是最快的,确保function里都是numpy的东西。如果有pandas,那就无效。

给计算function提速

添加图片注释,不超过 140 字(可选)

@patch

往现有的class里添加function

from fastcore.utils import patch

格式是@patch

换行,跟function,第一个position是self: classname,function里用self(跟class里的用法一样)

@patch
def itemgot(self:L, *idxs):
        x = self
        for idx in idxs: x = x.map(itemgetter(idx))
        return x

如果是classmethod, 那么cls_method=True,然后把self改成cls,function里用cls

@patch(cls_method=True)ly
def splitlines2(cls:L, s, keepends=False): return cls(s.splitlines(keepends))

@overload

decorator, 用来定义输入和输出的type,function冒号后面跟 '...'

@overload
def process_fold_input(
    fold_input: folding_input.Input,
    data_pipeline_config: pipeline.DataPipelineConfig | None,
    model_runner: None,
    output_dir: os.PathLike[str] | str,
    buckets: Sequence[int] | None = None,
) -> folding_input.Input:
  ...

@overload
def process_fold_input(
    fold_input: folding_input.Input,
    data_pipeline_config: pipeline.DataPipelineConfig | None,
    model_runner: ModelRunner,
    output_dir: os.PathLike[str] | str,
    buckets: Sequence[int] | None = None,
) -> Sequence[ResultsForSeed]:
  ...

@dataclass

可以使class定义省略

原先要写成

class Hero:
    def __init__(self, title:str, statement:str):
         self.title=title
         self.statement=statement

现在可以直接写成:

from dataclasses import dataclass,asdict

@dataclass
class Hero:
    title: str
    statement: str
    
    def __ft__(self):
        """ The __ft__ method renders the dataclass at runtime."""
        return Div(H1(self.title),P(self.statement), cls="hero")

顺序是自动的,Hero('a','b')就会把a给title,b给statement。

用asdict把它转换成dictionary:

h =Hero('a','b')
asdict(h) # 转换成一个dictionary