繁体   English   中英

用于自动绑定 __init__ 参数的 Python 装饰器

[英]Python decorator for automatic binding __init__ arguments

是否有自动绑定到方式self (一些)的参数__init__方法?

我的意思是这样的:

class Person:
    @lazy_init
    def __init__(self, name, age, address):
        ...

... 代替:

class Person:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
        ...

我想知道人们在这种情况下是否已经使用了类似的东西。 或者有什么理由我不应该首先这样做?

这绝对是可能的,这是一个有点幼稚的实现:

from functools import wraps

def lazy_init(init):
    import inspect
    arg_names = inspect.getargspec(init)[0]

    @wraps(init)
    def new_init(self, *args):
        for name, value in zip(arg_names[1:], args):
            setattr(self, name, value)
        init(self, *args)

    return new_init

class Person:
    @lazy_init
    def __init__(self, name, age):
        pass

p = Person("Derp", 13)
print p.name, p.age

一旦你开始拥有除了映射到属性的属性之外的东西,你就会遇到麻烦。 您至少需要某种方式来指定将哪些 args 初始化为属性......在这一点上它只会变得比它的价值更麻烦。

供将来遇到此问题的所有其他人参考(Python 3.7 或更高版本):有一个dataclass装饰器可以做到这一点。

例子

from dataclasses import dataclass

@dataclass
class Person:
    name
    age
    address

# other methods...

由我创建的 initify.py :) 它完全符合您的期望。

class Animal:
   @init_args(exclude=["name"])
   def __init__(self, name):
       pass

或使用默认值:

class Animal:
   @init_args
   def __init__(self, name="Default name"):
       pass

甚至排除继承:

class Dog(Animal):
   @init_args(exclude=["name"])
   def __init__(self, species):
       pass

https://github.com/prankymat/initify.py

在这里,以最简单的形式:

def lazy_init(*param_names):
  def ret(old_init):
    def __init__(self, *args, **kwargs):
      if len(args) > len(param_names):
        raise TypeError("Too many arguments")
      for k in kwargs:
        if k not in param_names:
          raise TypeError("Arg %r unexpected" % k)
      for par, arg in zip(param_names, args):
        setattr(self, par, arg)
      for par, arg in kwargs.items():
        setattr(self, par, arg)
      old_init(*args, **kwargs)
    return __init__
    #
  return ret


class Q(object):
  @lazy_init("a", "b")
  def __init__(self, *args, **kwargs):
    print "Original init"

>>> q = Q(1, 2)
Original init
>>> q.a, q.b
(1, 2)

考虑制作一个类装饰器来覆盖__str__

您可以像这样使用 Python 3.7 中的数据类:

from dataclasses import dataclass

@dataclass
class MyClass:
    var_1: str
    var_2: float

或者你可以像这样使用fastcore库中的store_attr()方法:

from fastcore.utils import store_attr

class MyClass:
    def __init__(self, var_1, var_2):
        store_attr()

两者都产生等效的 init 方法:

def __init__(self, var_1, var_2):
    self.var_1 = var_1
    self.var_2 = var_2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM