13

Ruby を調査しているときに、単純な構造体のようなクラスを作成するためにこれに出くわしました。

Person = Struct.new(:forname, :surname)
person1 = Person.new('John', 'Doe')
puts person1  #<struct Person forname="John", surname="Doe">

これにより、いくつかのPythonの質問が発生しました。このメカニズムの [非常に] 基本的なクローンを Python で作成しました。

def Struct(*args):
    class NewStruct:
        def __init__(self):
            for arg in args:
                self.__dict__[arg] = None

    return NewStruct

>>> Person = Struct('forename', 'surname')
>>> person1 = Person()
>>> person2 = Person()
>>> person1.forename, person1.surname = 'John','Doe'
>>> person2.forename, person2.surname = 'Foo','Bar'
>>> person1.forename
'John'
>>> person2.forename
'Foo'
  1. これを処理するための同様のメカニズムが Python に既にありますか? (私は通常、辞書を使用します)。

  2. Struct()正しい__init__()引数を作成する関数を取得するにはどうすればよいですか。person1 = Person('John', 'Doe')(この場合、可能であれば名前付き引数を実行したいと思います:person1 = Person(surname='Doe', forename='John')

興味のあることとして、これを行うためのより良い Python メカニズムがあったとしても、質問 2 に答えてもらいたいと思います。

4

7 に答える 7

17

Python 2.6 を使用している場合は、標準ライブラリの名前付きタプルクラスを試してください。

>>> from collections import namedtuple
>>> Person = namedtuple('Person', ('forename', 'surname'))
>>> person1 = Person('John', 'Doe')
>>> person2 = Person(forename='Adam', surname='Monroe')
>>> person1.forename
'John'
>>> person2.surname
'Monroe'

編集:コメントによると、Pythonの以前のバージョンのバックポートがあります

于 2009-08-12T08:01:06.463 に答える
3

これは、Cide の回答のフォローアップです (おそらく、より深く掘り下げたい人にとってのみ興味深いものです)。

__slots__ を使用する Cide の Struct() の更新された定義を使用して問題が発生しました。問題は、返されたクラスのインスタンスに読み取り専用の属性があることです。

>>> MS = Struct('forename','lastname')
>>> m=MS()
>>> m.forename='Jack'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyStruct' object attribute 'forename' is read-only

同じ名前のクラス属性がある場合、 __slots__ がインスタンスレベルの属性をブロックしているようです。__init__ メソッドを提供することでこれを克服しようとしたので、オブジェクトの作成時にインスタンス属性を設定できます。

def Struct1(*args, **kwargs):
    def init(self):
        for k,v in kwargs.items():
            setattr(self, k, v)
    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})

最終的な効果として、構築されたクラスは __init__ メソッドと __slots__ メンバーのみを認識します。これは必要に応じて機能しています。

>>> MS1 = Struct1('forename','lastname')
>>> m=MS1()
>>> m.forename='Jack'
>>> m.forename
'Jack'
于 2009-08-13T12:01:17.093 に答える
2

ThomasH のバリアントの更新:

def Struct(*args, **kwargs):
    def init(self, *iargs, **ikwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
        for i in range(len(iargs)):
            setattr(self, args[i], iargs[i])
        for k,v in ikwargs.items():
            setattr(self, k, v)

    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})

これにより、パラメーター (および名前付きパラメーター) を__init__()(検証なしで) に渡すことができます。

>>> Person = Struct('fname', 'age')
>>> person1 = Person('Kevin', 25)
>>> person2 = Person(age=42, fname='Terry')
>>> person1.age += 10
>>> person2.age -= 10
>>> person1.fname, person1.age, person2.fname, person2.age
('Kevin', 35, 'Terry', 32)
>>> 

アップデート

collections.pynamedtuple()でこれがどのように行われるかを調べます。クラスが作成され、文字列として展開され、評価されます。酸洗い等にも対応。

于 2009-08-13T22:54:16.673 に答える
1

名前付きタプルがある

>>> from collections import namedtuple
>>> Person = namedtuple("Person", ("forename", "surname"))
>>> john = Person("John", "Doe")
>>> john.forename 
'John'
>>> john.surname 
'Doe'
于 2009-08-12T08:00:34.467 に答える