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

Dan*_*mov 5 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
Run Code Online (Sandbox Code Playgroud)

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

我们都被告知不要将我们的内部工作暴露给客户端代码,但是附加数据根本不与封装有关,对吧?这个习惯用法是Python代码常见的吗?


就是我的意思......

每一个Tweet有标准领域,如id,text,owner.
当为用户返回推文列表时,您希望显示此用户是否"赞成"推文.

显然,为了获得is_favorite你需要为此查询多对多关系user.
可以预先填充Tweetis_favorite当前用户相对应的对象吗?

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


我知道这样可以正常工作,但我想知道在开源项目中做这样的事情是否会让其他开发人员蔑视我.

边注:

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

NPE*_*NPE 6

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

该对象不知道您正在弄乱其属性.例如,考虑如果Profile稍后扩展为具有agep.age代码无关的属性,将会发生什么.

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

  • @DanAbramov:我没有资格评论Django的限制,但在普通的Python中,我可能会将用户的收藏放入`set`而不是将`is_favourite`作为`Tweet`的属性. (3认同)
  • @Owen:是的.IMO的关键区别在于,通过子类化,问题可能更容易定位,因为它位于基类和子类之间.在外部添加属性意味着问题代码可以在代码库*中的任何位置*. (2认同)

Tim*_*man 5

我认为答案是:视情况而定。首先,如果你真的想阻止它,你可以通过__slots__在类中定义。添加未在类中实际定义的属性通常不是一个好习惯,因为它可能会让阅读代码的人感到困惑并且很少有用。

但在某些时候,能够做到这一点是很有用的,Python 文档讨论了这一点,作为获得类似于 C 结构或 Pascal 记录的东西的方法(请参阅 http://docs.python.org/tutorial/classes.html根据第 9.7 节“零碎事项”。)