是否在Python中动态添加属性?

时间:2011-10-28 16:34:12

标签: python oop encapsulation dynamic-languages design-principles

在Python中,您可以从定义类之外分配任意属性

class Profile(models.Model):
    user = models.OneToOneField(User)  
    name = models.CharField(max_length=140)

p = Profile()
p.age = 42

这里的基础机制是__dict__属性,它维护所有属性的字典。

我们都被告知not to expose our inner workings to the client code,但附加新的数据根本不与封装有关,对吧?这个习惯用法是Python代码常用的吗?


我的意思......

每个Tweet都有标准字段,例如idtextowner
当为用户返回推文列表时,您希望显示该用户是否“收藏”推文。

显然,要获得is_favorite,您需要查询此user的多对多关系。
是否可以使用与当前用户相对应的Tweet预先填充is_favorite个对象

当然,我可以公开一个方法is_favorite_for(user)但是我遇到了Django template language限制,这些限制不允许从模板内部调用带有参数的方法。另外,我认为模板不应该根本调用方法


我知道这将工作很好,但我想知道在开源项目中做这样的事情是否会让其他开发人员蔑视我。

  

旁注:

     

我来自C#/ .NET背景,其中最近引入了动态类型,除了一些利基领域(互操作性,IoC框架,REST客户端框架等)之外,它们没有得到广泛的适应。

3 个答案:

答案 0 :(得分:6)

我认为这是一种不好的做法。

该对象不知道您正在弄乱其属性。例如,考虑一下如果Profile后来扩展为具有名为age的属性,与代码中的p.age无关,会发生什么。

如果要添加属性,为什么不将Profile子类化,或者将Profiles外部映射到具有自定义属性的对象?

答案 1 :(得分:3)

我认为答案是:这取决于。首先,如果你真的想要阻止它,你可以在课堂上定义__slots__。添加类中未实际定义的属性通常不是一个好习惯,因为它可能会让读者感到困惑  代码很少有用。

但在某些时候,能够做到这一点很有用,Python文档将此作为一种类似于C结构或Pascal记录的方式进行讨论(请参阅第9.7节“赔率和结束”中的http://docs.python.org/tutorial/classes.html。 )

答案 2 :(得分:2)

如果属性有时只存在,那么对于一个对象,你可能会冒出一个AttributeError的冒险,而代码对同一个类的另一个对象工作正常(是的,确切的类型并不重要) -typing,但同一类的对象经常被认为是相同的“鸭子类型”)。即使它没有发生,你也不能仅仅通过查看部分代码来确定,并且在任何情况下检查都要困难得多。因此,这样做只会降低您的代码可靠性。

然后可以选择提供默认属性作为类属性或属性,仅在与默认属性不同时指定对象属性。但对于预期每个对象不同的内容,__init__中列出的每个属性的清晰度通常会超过延迟实例属性访问的任何潜在优势。

这并不是说这是不可接受的,但你必须提出一个令人信服的论据才能被认为是一个好主意。