在 Python 中动态添加属性是否会令人不悦?

发布于 2024-12-12 23:55:01 字数 1419 浏览 1 评论 0原文

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

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

p = Profile()
p.age = 42

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

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


正是我的意思...

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

显然,要获取is_favorite,您需要查询该用户的多对多关系。
使用与当前用户相对应的 is_favorite预填充 Tweet 对象可以吗?

当然,我可以公开一个方法 is_favorite_for(user) 但我点击了 Django 模板语言 限制不允许从模板内部调用带有参数的方法。另外,我相信模板根本不应该调用方法


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

旁注:

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

In Python, you can assign an arbitrary attribute from outside the defining class:

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

p = Profile()
p.age = 42

The underlying mechanism here is __dict__ attribute that maintains a dictionary of all attributes.

We were all told not to expose our inner workings to the client code, but attaching new data doesn't have to do with encapsulation at all, right? Is this idiom common for Python code?


Just What I Mean…

Each Tweet has standard fields, like id, text, owner.
When returning tweet list for a user, you want to display if a tweet is “favorited” by this user.

Obviously, to obtain is_favorite you need to query many-to-many relationship for this user.
Would it be OK to pre-fill Tweet objects with is_favorite corresponding to current user?

Sure I could expose a method is_favorite_for(user) but I'm hitting Django template language limitations that doesn't allow to call methods with arguments from inside the template. Also, I believe a template should not be calling methods at all.


I know this will work fine, but I wonder if doing something like that in an open source project would get other developers to look on me with contempt.

Sidenote:

I come from C#/.NET background where dynamic types were introduced very recently and aren't adapted widely except for some niche areas (interoperability, IoC frameworks, REST client frameworks, etc).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╰◇生如夏花灿烂 2024-12-19 23:55:01

我的观点是,这是一种不好的做法。

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

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

My view is that it is a bad practice.

The object doesn't know that you're messing with its attributes. Consider, for example, what would happen if Profile were later expanded to have an attribute called age, unrelated to p.age in your code.

If you want to add attributes, why not subclass Profile, or have an external mapping of Profiles to an object with your custom attributes?

愛放△進行李 2024-12-19 23:55:01

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

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

I think the answer is: It depends. First, if you really want to prevent it you can by defining __slots__ in the class. And it is not generally a good practice to add attributes not actually defined in the class, as it can be confusing to someone reading
the code and is rarely useful.

But at certain times, it is useful to be able to do this and Python documentation discusses this as a way to get something similar to a C struct or Pascal Record (see http://docs.python.org/tutorial/classes.html under section 9.7 Odds and Ends.)

无所的.畏惧 2024-12-19 23:55:01

如果该属性只是有时存在,那么您可能会冒着为一个对象无缘无故出现 AttributeError 的风险,而代码对于同一类的另一个对象则运行良好(是的,当鸭子时,确切的类型并不那么重要) -打字,但同一类的对象经常被假定为相同的“鸭子类型”)。即使它没有发生,你也不能仅仅通过查看部分代码来确定,并且无论如何都很难检查。因此,这样做只会降低您的代码的可靠性。

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

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

If the attribute is only there sometimes, you risk getting an AttributeError out of nowhere for one object while the code worked fine for another object of the same class (yes, exact types aren't that important when duck-typing, but objects of the same class are frequently assumed to be of the same "duck type"). Even if it doesn't happen, you can't be sure just by looking at part of the code, and it's much harder to check in any case. So, doing this only makes your code less reliable.

Then there's the option of providing a default attribute as class attribute or property, only assigning an object attribute when it differs from the default. But for stuff that is expected to vary per object, the clarity of having every attribute ever listed in __init__ usually outweights any potential advantages of delaying instance attribute access.

That is not to say it's not acceptable, but you'd have to make a compelling argument for it to be considered a good idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文