类工厂生成简单的类结构类?

kjf*_*tch 11 python struct class-factory

在调查Ruby时,我遇到了这个问题来创建一个类似Struct的类:

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

这为我提出了一些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'
Run Code Online (Sandbox Code Playgroud)
  1. Python中是否已有类似的机制来处理这个问题?(我通常只使用字典).

  2. 我如何获得Struct()创建正确__init__()参数的函数.(在这种情况下,我想尽可能执行person1 = Person('John', 'Doe')命名参数:person1 = Person(surname='Doe', forename='John')

我想,感兴趣的是,即使有更好的Python机制来解决问题2也是如此.

Ali*_*ell 16

如果您使用的是Python 2.6,请尝试使用标准库namedtuple类.

>>> 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'
Run Code Online (Sandbox Code Playgroud)

编辑:根据评论,早期版本的Python有一个backport

  • 旧版python的命名元组(工作在2.4)http://code.activestate.com/recipes/500261/ (2认同)

Cid*_*ide 10

如果您正在运行python <2.6或者想扩展您的类以执行更多操作,我建议您使用type()内置函数.这比你的解决方案更有优势,因为设置是__dict__在类创建而不是实例化时发生的.它也没有定义__init__方法,因此如果类__init__因某种原因再次调用,则不会导致奇怪的行为.例如:

def Struct(*args, **kwargs):
    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), kwargs)
Run Code Online (Sandbox Code Playgroud)

像这样使用:

>>> MyStruct = Struct("forename", "lastname")
Run Code Online (Sandbox Code Playgroud)

相当于:

class MyStruct(object):
    forename = None
    lastname = None
Run Code Online (Sandbox Code Playgroud)

这个:

>>> TestStruct = Struct("forename", age=18, name="TestStruct")
Run Code Online (Sandbox Code Playgroud)

相当于:

class TestStruct(object):
    forename = None
    age = 18
Run Code Online (Sandbox Code Playgroud)

更新

此外,您可以编辑此代码,以便非常容易地防止分配除指定变量之外的其他变量.只需将Struct()工厂更改为assign即可__slots__.

def Struct(*args, **kwargs):
    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    kwargs['__slots__'] = kwargs.keys()
    return type(name, (object,), kwargs)
Run Code Online (Sandbox Code Playgroud)


fra*_*ca7 5

正如其他人所说,在Python 2.6/3.x中命名为元组.对于旧版本,我通常使用Stuff类:

class Stuff(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

john = Stuff(forename='John', surname='Doe')
Run Code Online (Sandbox Code Playgroud)

但这并不能保护您免受误导.在ActiveState上还有一个命名元组的方法:

http://code.activestate.com/recipes/500261/


kjf*_*tch 3

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()})
Run Code Online (Sandbox Code Playgroud)

这允许参数(和命名参数)传递到__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)
>>> 
Run Code Online (Sandbox Code Playgroud)

更新

看看在collections.pynamedtuple()中这是如何做到的。该类被创建并扩展为字符串并进行评估。还支持pickling等等。