没有属性样板的Python类

时间:2013-06-14 17:31:38

标签: python oop metaprogramming

我的许多课程看起来像以下课程来代表帐户

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 个答案:

答案 0 :(得分:3)

不确定它是多么惯用,但以下内容满足您的要求:

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

答案 1 :(得分:1)

Here are some recipes you can try:覆盖__setattr____dict____slots__和/或init。让我们知道什么对你有用。

答案 2 :(得分:0)

目前有许多图书馆可以满足这种需求:attrsdataclassespydantic,...以及我对此景观的新添加pyfields

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

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

混合
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与其他更多的“多合一”库相反,仅以“最小可行产品”精神集中于字段和构造函数。因此,如果您还希望dict表示和转换,哈希,相等和比较,则应使用另一个库将它们添加到类的顶部。我目前正在开发mixture库,为此提供混合类,并具有点菜功能的相同哲学-无论有无{{1} }。

有关详细信息,请参见pyfields documentation。不要犹豫,提供反馈!