Python类的无属性样板代码

3
许多我的课程看起来像以下类来表示账户。
class Account(object):
    def __init__(self, first, last, age, id, balance):
        self.first = first
        self.last = last
        self.age = age
        self.id = id
        self.balance = balance

    def _info(self):
        return self.first, self.last, self.age, self.id, self.balance

    def __eq__(self, other):
        return self._info == other._info()

    def __hash__(self):
        return hash((type(self), self.info()))

    def ... # other methods follow

但实际上,我关心的只有以下属性列表:first,last,age,id,balance。是否有一种标准方法来定义符合这种结构的Python类?
乍一看,我想到了namedtuple,但我不确定它是否允许我事后添加其他方法。实际上,我想要像以下这样的东西。
class Account(object):
    attributes = "first last age id balance"

    def ... # other methods

什么是获取这个的最佳方法?
3个回答

4

我不确定这是否是习惯用语,但下面的内容符合你的需求:

不确定如何运用,但以下满足您的需求:

class Slottable:
    def __init__(self, *args):
        for slot, arg in zip(self.slots.split(' '), args):
            setattr(self, slot, arg)

    def _info(self):
        return tuple(getattr(self, attr) for attr in self.slots.split())

    def __eq__(self, other):
        return self._info() == other._info()

    def __hash__(self):
        return hash((type(self), self._info()))


class Account(Slottable):
    slots = "first last age id balance"

    def fullname(self):
        return self.first + " " + self.last

matt = Account("Matthew", "Smith", 28, 666, 1E6)
john = Account("John", "Jones", 46, 667, 1E7)

d = {matt: 5, john: 6}  # Hashable

print matt.fullname()
#=> "Matthew Smith"
print john.fullname()
#=> "John Jones"
print matt == matt, matt == john
#=> True False
matt.age = 29  # Happy birthday!
print matt.age
#=> 29

哎呀,这个处理变异的不太好。特别是它没有遵循单一真相原则。冗余数据既保存在__info中,也保存在每个属性中。 - MRocklin
@MRocklin 变异?你为什么想要这个?!? :-) 我编辑了这个例子来处理变异,并只在属性字典中保留信息。 - JohnJ

1

1
许多库被用来满足这个需求: attrs, dataclasses, pydantic, ... 以及我新加入这个领域的 pyfields

选择主要取决于您需要或不需要的功能。 pyfields 专注于字段定义和可选验证和转换,没有对您的类的任何限制。 可以成为本地的字段将变得与 Python 本机属性一样快,而需要回调(验证器/转换器)的字段则使用描述符实现。

您可以将自己的构造函数与

from pyfields import field, init_fields

class Account(object):
    first = field(doc="first name")
    last = field(doc="last name")
    age = field(doc="the age in years")
    id = field(doc="an identifier")
    balance = field(doc="current balance in euros")

    @init_fields
    def __init__(self, msg):
        print(msg)

a = Account("hello, world!", first="s", last="marie", age=135, id=0, balance=-200000)
print(vars(a))

产生
hello, world!
{'balance': -200000, 'id': 0, 'age': 135, 'last': 'marie', 'first': 's'}

与其他“一站式”库相反,pyfields 仅专注于字段和构造函数,并具有“最小可行产品”的精神。因此,如果您还想要字典表示和转换、哈希、相等性和比较,您应该使用另一个库在类中添加它们。我目前正在开发一个 mixture 库,提供混合类,具有相同的“点菜”功能哲学 - 您将能够使用或不使用 pyfields

请参阅 pyfields文档 以获取详细信息。请不要犹豫提供反馈!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接