27

私が使用する一般的なパターンは、同じ名前の属性にSomeClass.__init__()引数を割り当てることです。self例:

class SomeClass():
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

実際、これは他の人にとって一般的なタスクである必要があり、PyDevにはこれへのショートカットがあります。パラメータリストにカーソルを置いてクリックすると、ボイラープレートコードを作成するCtrl+1オプションが表示されます。Assign parameters to attributes

この割り当てを実行するための、別の短くエレガントな方法はありますか?

4

10 に答える 10

9

ボイラープレートコードは悪いことだというあなたの感覚に共感します。しかし、この場合、より良い代替案があるかどうかはわかりません。可能性を考えてみましょう。

いくつかの変数について話している場合、一連のself.x = x行は読みやすいです。実際、その明確さは、読みやすさの観点からそのアプローチを好ましいものにしていると思います。入力するのは少し面倒かもしれませんが、それだけでは、実際に何が起こっているのかを曖昧にする可能性のある新しい言語構造を正当化するのに十分ではありません。確かに、vars(self).update()シェナニガンを使用することは、この場合の価値よりも混乱を招くでしょう。

一方、に9、10、またはそれ以上のパラメーターを渡す場合は、__init__とにかくリファクタリングする必要があります。したがって、この懸念は、たとえば5〜8個のパラメータを渡すことを含む場合にのみ実際に当てはまります。self.x = xこれで、8行の行が入力と読み取りの両方でどのように煩わしくなるかがわかります。しかし、5-8パラメータのケースが、別の方法を使用することを正当化するのに十分一般的または面倒であるかどうかはわかりません。ですから、あなたが提起している懸念は原則として良いものですが、実際には、それを無関係にする他の制限的な問題があると思います。

この点をより具体的にするために、オブジェクト、dict、および名前のリストを受け取り、dictの値をリストの名前に割り当てる関数について考えてみましょう。これにより、どの変数が自分自身に割り当てられているかを明確に保つことができます。(割り当てられる変数の明示的な列挙を必要としないこの問題の解決策を提案することは決してありません。それは希土類バグの磁石になります):

>>> def assign_attributes(obj, localdict, names):
...     for name in names:
...         setattr(obj, name, localdict[name])
...
>>> class SomeClass():
...     def __init__(self, a, b, c):
...         assign_attributes(self, vars(), ['a', 'b', 'c'])

さて、ひどく魅力的ではありませんが、これは単純な一連のself.x = x線よりも理解するのが難しいです。また、状況によっては、1行、2行、場合によっては3行または4行よりも長く、入力するのが面倒です。したがって、5つのパラメータの場合から始めて特定の見返りを得るだけです。しかし、それはあなたが人間の短期記憶容量の限界(= 7 +/- 2「チャンク」)に近づき始める正確な瞬間でもあります。したがって、この場合、コードはすでに少し読みづらく、これはさらに難しくなります。

于 2011-12-30T19:46:40.770 に答える
8

あなたはこれを行うことができます、それは単純さの長所を持っています:

>>>  class C(object):
    def __init__(self, **kwargs):
        self.__dict__ = dict(kwargs)

これにより、インスタンスを作成するコードに任せてC、構築後にインスタンスの属性を決定します。例:

>>> c = C(a='a', b='b', c='c')
>>> c.a, c.b, c.c
('a', 'b', 'c')

Cすべてのオブジェクトに、、、および属性を持たabたい場合c、このアプローチは役に立ちません。

(ところで、このパターンは、Pythonで列挙型を定義する問題の一般的な解決策として、Guido自身の悪い自己から来ています。上記のようなクラスを作成すると、のEnumようなコードを記述でき、Colors = Enum(Red=0, Green=1, Blue=2)以降は、、、を使用できます。)Colors.RedColors.GreenColors.Blue

の代わりに設定self.__dict__した場合に発生する可能性のある問題の種類を把握することは、価値のある演習です。kwargsdict(kwargs)

于 2011-12-30T23:57:38.760 に答える
4

@pcperiniの答えのMod:

>>> class SomeClass():
        def __init__(self, a, b=1, c=2):
            for name,value in vars().items():
                if name != 'self':
                    setattr(self,name,value)

>>> s = SomeClass(7,8)
>>> print s.a,s.b,s.c
7 8 2
于 2011-12-30T19:30:43.263 に答える
3

あなたの特定のケースは、 namedtupleで処理することもできます:

>>> from collections import namedtuple
>>> SomeClass = namedtuple("SomeClass", "a b c")
>>> sc = SomeClass(1, "x", 200)
>>> print sc
SomeClass(a=1, b='x', c=200)
>>> print sc.a, sc.b, sc.c
1 x 200
于 2011-12-30T23:05:32.317 に答える
2

デコレータマジック!!

>>> class SomeClass():
        @ArgsToSelf
        def __init__(a, b=1, c=2, d=4, e=5):
            pass

>>> s=SomeClass(6,b=7,d=8)
>>> print s.a,s.b,s.c,s.d,s.e
6 7 2 8 5

定義中:

>>> import inspect
>>> def ArgsToSelf(f):
    def act(self, *args, **kwargs):
        arg_names,_,_,defaults = inspect.getargspec(f)
        defaults=list(defaults)
        for arg in args:
            setattr(self, arg_names.pop(0),arg)
        for arg_name,arg in kwargs.iteritems():
            setattr(self, arg_name,arg)
            defaults.pop(arg_names.index(arg_name))
            arg_names.remove(arg_name)
        for arg_name,arg in zip(arg_names,defaults):
            setattr(self, arg_name,arg)
        return f(*args, **kwargs)
    return act

もちろん、このデコレータを一度定義して、プロジェクト全体で使用することもできます。
また、このデコレータは、だけでなく、任意のオブジェクト関数で機能します__init__

于 2011-12-31T10:43:43.197 に答える
1

次のように、setattr()を介して実行できます。

[setattr(self, key, value) for key, value in kwargs.items()]

あまり美しくはありませんが、スペースを節約できます:)

だから、あなたは得るでしょう:

  kwargs = { 'd':1, 'e': 2, 'z': 3, }

  class P():
     def __init__(self, **kwargs):
        [setattr(self, key, value) for key, value in kwargs.items()]

  x = P(**kwargs)
  dir(x)
  ['__doc__', '__init__', '__module__', 'd', 'e', 'z']
于 2011-12-30T19:03:59.003 に答える
1

その単純なユースケースでは、明示的に(PyDevのCtrl + 1を使用して)配置するのが好きだと言わなければなりませんが、場合によっては、大量の実装を使用することもありますが、受け入れられた属性が事前に宣言された属性から作成されるクラスを使用しますクラスで、何が期待されているかを知ることができます(そして、より読みやすいと思うので、名前付きのタプルよりも好きです-静的コード分析やコード完了を混乱させることはありません)。

私はそれのレシピをhttp://code.activestate.com/recipes/577999-bunch-class-created-from-attributes-in-class/に載せました。

基本的な考え方は、クラスをBunchのサブクラスとして宣言し、インスタンス内にそれらの属性を作成することです(デフォルトまたはコンストラクターで渡された値のいずれかから)。

class Point(Bunch):
    x = 0
    y = 0

p0 = Point()
assert p0.x == 0
assert p0.y == 0

p1 = Point(x=10, y=20)
assert p1.x == 10
assert p1.y == 20

また、Alex Martelliは多数の実装も提供しました:http : //code.activestate.com/recipes/52308-the-simple-but-handy-collector-of-a-bunch-of-named/引数からのインスタンスですが、静的コード分析を混乱させる可能性があります(そして、IMOは物事を追跡するのを難しくする可能性があります)ので、ローカルで作成され、どこにも渡さずに同じスコープ内に捨てられるインスタンスにのみそのアプローチを使用しますそうしないと)。

于 2011-12-31T18:08:15.713 に答える
1

locals()とを使用して自分で解決しました__dict__

>>> class Test:
...     def __init__(self, a, b, c):
...         l = locals()
...         for key in l:
...             self.__dict__[key] = l[key]
... 
>>> t = Test(1, 2, 3)
>>> t.a
1
>>> 
于 2016-05-19T09:42:05.297 に答える
0

免責事項

これを使用しないでください:私は単にOPの当初の意図に最も近い答えを作成しようとしていました。コメントで指摘されているように、これは完全に未定義の動作に依存しており、シンボルテーブルの変更を明示的に禁止しています。

ただし、これは機能し、非常に基本的な状況でテストされています。

解決

class SomeClass():
    def __init__(self, a, b, c):
        vars(self).update(dict((k,v) for k,v in vars().iteritems() if (k != 'self')))

sc = SomeClass(1, 2, 3)
# sc.a == 1
# sc.b == 2
# sc.c == 3

組み込み関数を使用してvars()、このスニペットはメソッドで使用可能なすべての変数__init__(この時点では、、、、、および)を繰り返し、の変数を同じに設定selfaます。これは明らかに引数参照を無視します。に(悪い決定のように見えたので。)bcselfselfself.self

于 2011-12-30T19:15:13.513 に答える
0

@ user3638162の答えに関する問題の1つはlocals()、「self」変数が含まれていることです。したがって、余分な。が必要になりますself.self。余分な自己を気にしないのであれば、その解決策は単純に

class X:
    def __init__(self, a, b, c):
        self.__dict__.update(locals())

x = X(1, 2, 3)
print(x.a, x.__dict__)

によって建設後に削除するselfことができますdel self.__dict__['self']

または、Python3で導入された辞書内包表記を使用して、構築中に自己を削除することもできます。

class X:
    def __init__(self, a, b, c):
        self.__dict__.update(l for l in locals().items() if l[0] != 'self')

x = X(1, 2, 3)
print(x.a, x.__dict__)
于 2017-12-05T09:30:00.390 に答える