5

多くの場合、__init__メソッドはこれに似ているようです。

def __init__(self, ivar1, ivar2, ivar3):
    self.ivar1 = ivar1
    self.ivar2 = ivar2
    self.ivar3 = ivar3

*args引数を(またはに頼らずに)リストに変換し、パラメーターの名前と渡された引数を使用してインスタンス変数を設定するため**kwargsに使用する方法はありますか?そして多分リストをスライスします、例えばあなたが望まないのであなたはsetattr少なくともそれをスライスする必要があるでしょう。[1:]self.self

(実際には、名前と値を保持するための辞書である必要があると思います)

このような:

def __init__(self, ivar1, ivar2, ivar3, optional=False):
    for k, v in makedict(self.__class__.__init__.__args__): # made up __args__
        setattr(self, k, v)

ありがとう!

不明の答えに答えて、私はこれがうまくいくことを発見しました:

Class A(object):
    def __init__(self, length, width, x):
        self.__dict__.update(dict([(k, v) for k, v in locals().iteritems() if k != 'self']))

また

Class A(object):
    def __init__(self, length, width, x):
        self.__dict__.update(locals())
        del self.__dict__['self']

悪くない..

4

9 に答える 9

7

どうぞ。はい、これは醜い邪悪なハックです。はい、オブジェクトには__dict__変数が必要です。しかしねえ、それはきちんとした小さなワンライナーです!

def __init__(self):
    self.__dict__.update(locals())

コンストラクターは、任意のタイプの引数を取ることができます。

class test(object):
    def __init__(self, a, b, foo, bar=5)...

a = test(1,2,3)
dir(a)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'foo', 'bar', 'self']

自己も含まれますが、簡単に削除したり、自己を無視した独自の更新機能を作成したりできます。

于 2009-09-14T02:55:37.750 に答える
6

inspect.getargspecを使用して、デコレータとしてカプセル化できます。オプションの引数とキーワード引数の検索は少し注意が必要ですが、これでうまくいくはずです。

def inits_args(func):
    """Initializes object attributes by the initializer signature"""
    argspec = inspect.getargspec(func)
    argnames = argspec.args[1:]
    defaults = dict(zip(argnames[-len(argspec.defaults):], argspec.defaults))
    @functools.wraps(func)
    def __init__(self, *args, **kwargs):
        args_it = iter(args)
        for key in argnames:
            if key in kwargs:
                value = kwargs[key]
            else:
                try:
                    value = args_it.next()
                except StopIteration:
                    value = defaults[key]
            setattr(self, key, value)
        func(self, *args, **kwargs)
    return __init__

その後、次のように使用できます。

class Foo(object):
    @inits_args
    def __init__(self, spam, eggs=4, ham=5):
        print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)
于 2009-09-14T06:24:38.043 に答える
4

引数が関数シグネチャで個別に指定されている場合、引数をリストとして取得する良い方法はありません。おそらく検査やフレームハックで何かを行うことができますが、それはあなたが行ったように単にそれを綴るよりも醜いでしょう。

于 2009-09-14T02:51:23.750 に答える
3

inspect.getargspecを試してください:

In [31]: inspect.getargspec(C.__init__)

Out[31]: ArgSpec(args=['self', 'ivar1', 'ivar2', 'ivar3', 'optional'],

                 varargs=None, keywords=None, defaults=(False,))
于 2009-09-14T03:09:28.623 に答える
2

コレクションモジュールからの新しいnamedtuple(Python 2.6の新機能)が機能するかどうかを確認します。

于 2009-09-14T02:52:25.853 に答える
2

引数のイントロスペクションを使用してそれを行うことができますが、コードは置き換えようとしているコードよりも長くなります。特にあなたがkwを扱っているなら、あなたはそれをしなければならないかもしれません。

この短いコードはほとんどの場合に機能します(Unknownsの例から改善されています)。

>>> class Foo:
...   def __init__(self, labamba, **kw):
...       params = locals().copy()
...       del params['self']
...       if 'kw' in params:
...           params.update(params['kw'])
...           del params['kw']
...       self.__dict__.update(params)

しかし、これは醜いハックであり、怠惰以外の特別な理由がないためにコードが読みにくくなるため、実行しないでください。また、5〜6個を超えるinitパラメーターを持つクラスが実際にどのくらいの頻度でありますか?

于 2009-09-14T06:38:39.400 に答える
1

私はそれが最も好きで、長すぎず、コピー貼り付けとサブ分類の両方ができます。

class DynamicInitClass(object):
      __init_defargs=('x',)
      def __init__(self,*args,**attrs):
        for idx,val in enumerate(args): attrs[self.__init_defargs[idx]]=val
        for key,val in attrs.iteritems(): setattr(self,key,val)
于 2009-11-13T03:58:20.440 に答える
0

特別なクラスから派生してみませんか?私はそれがこのようにより明確でより柔軟だと思います:

class InitMe:
    def __init__(self, data):
        if 'self' in data:
             data = data.copy()
             del data['self']
        self.__dict__.update(data)


class MyClassA(InitMe):
    def __init__(self, ivar1, ivar2, ivar3 = 'default value'):
        super().__init__(locals())


class MyClassB(InitMe):
    def __init__(self, foo):
        super().__init__({'xxx': foo, 'yyy': foo, 'zzz': None})
# or    super().__init__(dict(xxx=foo, yyy=foo, zzz=None))

class MyClassC(InitMe):
    def __init__(self, foo, **keywords):
        super().__init__(keywords)
于 2009-09-14T08:28:50.383 に答える
0

指定されたパラメーターから動的にクラス変数を宣言する場合は、クラスの初期化中にこれを行うための短くてクリーンな方法があります。

class Foo():

    def __init__(self, **content):
        if isinstance(content, dict):
            self.hello = 'world' # normal declaration instance variable
            for key, value in content.items():
                self.__setattr__(key, value)

    test = "test" # class variable


>>> content = {'foo':'bar'}
>>> instance = Foo(**content)
>>> instance.foo 
>>> 'bar'
于 2020-02-15T13:12:27.860 に答える