属性和类方法有什么区别?

13

类的属性和方法有什么区别?据我所知,属性在创建对象时计算。而方法是在调用它时进行计算。

除此之外,还有其他的区别吗?

例如,在我的class Product()中有一个property

@property
    def total_ammount_in_store(self):
        consignments = self.product.package.consignments
        total_ammount = 0
        for consignment in consignments:
            total_ammount += consignment.package_ammount

当我渲染一些页面时,我会传递一些产品。例如:{'products':Product.objects.filter(expiration_data < datetime.now())

我不需要每次获取Product实例时都计算total_ammount_in_store。如果我只需要在模板中调用它时进行计算,{{product.total_ammount_in_store}},这是否可行?

method是在创建对象时计算的吗?


这更像是类属性而不是类方法 https://dev59.com/9HPYa4cB1Zd3GeqPexZi#17000468 - madzohan
2个回答

15
每次访问product.total_ammount_in_store时都会调用该属性,而不是在创建产品时调用。
因此,在模板中包含{{ product.total_ammount_in_store }}将得到正确的结果。
通过使用装饰器property,您可以访问product.total_ammount_in_store,而不是像实例方法product.total_ammount_in_store()一样。 在Django模板语言中,这种差异并不明显,因为Django会在模板中自动调用方法。
不要将实例方法与类方法混淆,它们完全不同。 类方法属于您的类Product而不是单个实例product。 调用类方法时,您无法访问实例变量(例如self.package)。

当我尝试调试我的项目时,我注意到当我传递render我的产品时,total_ammount_in_store属性也被执行了。 - Andrew
在属性内部引发异常。回溯应该显示访问该属性的代码。 - Alasdair
1
@Andrew,使用Alasdair的想法,但有一个例外。 - geckon
@Alasdair 是的,我找到了。在模板中,我使用了基于 total_amount_in_storeis_available 属性。谢谢。 - Andrew
1
@Andrew,请注意类方法和实例方法之间的区别。 - geckon
显示剩余4条评论

3

@property装饰器可用于为类的实例变量(在您的情况下是self.total_ammount_in_store)实现getter。每次调用some_product.total_ammount_in_store时,都会执行装饰的方法。仅在创建新对象时执行它是没有意义的-您想要获取当前存储量,不是吗? 更多关于@property的阅读内容请参阅Python文档(它是Python的构造,而不是Django的):

https://docs.python.org/2/library/functions.html#property

关于类方法,它们是完全不同的东西。顾名思义,它们与类相关,而不是实例。因此,调用类方法不需要实例,但是你也不能在类方法中使用任何实例变量(因为它们与特定实例相关)。
至于与Django相关的部分...
如果你在模板中包含{{ some_product.total_ammount_in_store }},那么每次显示页面时,都会从some_product实例获取库存总量。这意味着装饰过的total_ammount_in_store getter被调用了。
例如,如果产品的库存总量在其生命周期内没有改变,你可以在__init__方法中计算该金额,然后仅返回该值。如果总库存量可以更改,则也可以这样做,但是你需要确保每次应更改时重新计算该金额-例如通过调用方法。像这样:
class Product(object):
    def __init__(self):
        # ...
        # other initialization
        # ...
        self.recalculate_amount()

    def recalculate_amount(self):
        consignments = self.product.package.consignments
        self._total_amount = 0
        for consignment in consignments:
            self._total_amount += consignment.package_amount

    @property
    def total_amount(self):
        """Get the current total amount in store."""
        return self._total_amount

每次调用some_product.total_ammount_in_store时,getter仍然会被调用(例如在Django模板中),但它不会每次都计算金额 - 它会使用存储的金额。

关于你回答的最后一个部分的问题:比如,当我在视图中写下如下代码:Product.objects.filter(some_condition),它会重新计算每个实例的总金额吗? - Andrew
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Andrew
只有在创建新对象时才会触发。有关更多信息,请阅读该方法的文档:https://docs.python.org/2/reference/datamodel.html#object.__init__ - geckon
@AndrewпјҢжҳҜзҡ„гҖӮе®ғеҸӘдјҡиў«recalculate_amountж–№жі•жӣҙж–°гҖӮе®һйҷ…дёҠпјҢжӮЁеҸҜд»Ҙж·»еҠ еҸҰдёҖз§Қжӣҙж–°йҮ‘йўқзҡ„ж–№ејҸпјҲдҫӢеҰӮж·»еҠ еҸҰдёҖдёӘж–№жі•ship(self, how_many)пјҢиҜҘж–№жі•е°Ҷд»Һself._total_amountдёӯеҮҸеҺ»how_manyзӯүпјүпјҢдҪҶжҖ»йҮ‘йўқдёҚдјҡеңЁжҜҸж¬ЎиҺ·еҸ–е…¶еҖјж—¶йҮҚж–°и®Ўз®—гҖӮ - geckon
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/76663/discussion-between-andrew-and-geckon。 - Andrew
显示剩余2条评论

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