Python属性和变量赋值

3
下面是一个从本教程中设计的类,旨在演示Python中property的功能。
该类设置和获取摄氏温度,并将其转换为华氏温度:
class Celsius:
    def __init__(self, current_temp = 25):
        self.temperature = current_temp

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    def get_temperature(self):
        print("Getting value")
        return self._temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = 50

    temperature = property(get_temperature,set_temperature)
问题: self.temperature(一个实例变量)是否确实引用类变量temperature?如果是,为什么?

示例:

obj = Celsius()
print(obj._temperature, obj.temperature)

返回:

设置值
获取值
50 50

我只是不明白一个已赋值的实例变量(current_temp)怎么会引用一个类变量。如果我有什么误解,对不起。


为什么你的setter无条件将self._temperature设置为50? - user2357112
看看这个非常好的关于 Python 中实例变量和类变量的博客。那应该能帮助你理解。 - Sunny Patel
@user2357112supportsMonica 我想展示self.temperature是通过属性设置而不是在init期间通过赋值设置的。我刚刚更新了这个例子。还有疑惑吗? - DSH
1
Python 沿着方法解析顺序搜索类和所有祖先,寻找属性的描述符。它找到了一个(该属性),并调用属性的 setter 来处理操作。 - user2357112
1
为什么属性(名为temperature)是self.temperature的描述符?正是因为它有这个名称。如果您使用NEW_NAME作为名称,那么您将能够执行self.NEW_NAME = 30,并且它将调用set_temperature - Karl Knechtel
显示剩余4条评论
1个回答

1
“self.temperature”(一个实例变量)实际上是引用类变量“temperature”吗?
你指的是“属性”,而不是“变量”。但是,是的。
如果是这样,那么为什么呢?
因为类的实例“没有温度属性”(它们只有一个“_temperature”属性),所以在Python未能在实例中找到该属性后,它也会检查类。
也许你被__init__方法对“self.temperature”进行赋值所迷惑。然而,这并不会在实例中创建一个“temperature”属性,因为首先找到的是属性。
属性查找有复杂的规则,旨在使您能够做您想要的事情——例如,使property工作。

我不明白一个已经赋值的实例变量(current_temp)怎么可能引用一个类变量。

我在你的代码中没有看到current_temp,所以无法帮助你。


代码令人困惑的部分原因是它以非常非标准的方式执行操作。 通常情况下, property 以其装饰器形式使用,看起来像这样:

class Celsius:
    def __init__(self, current_temp = 25):
        # set the underlying value directly; don't use the property
        # although you *can*, but it's arguably clearer this way
        self._temperature = current_temp

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    # the getter is given the name that the property should have.
    @property
    def temperature(self):
        print("Getting value")
        return self._temperature

    # The setter is "attached" to the getter with this syntax
    @temperature.setter
    # It doesn't matter that this has the same name, because of how the
    # internal attachment logic works.
    def temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value # good idea to actually use the value!

奖励:可以说,更好的设计是拥有单独的 celciusfahrenheit 属性,并且能够从 celcius 或 fahrenheit 值创建实例(使用 staticmethod 创建工厂方法)。它看起来像这样:

class Temperature:
    # Secret implementation detail: we store the value in celcius.
    # We could have chosen fahrenheit instead, and do the conversions
    # the other way around. Users should not call this directly.
    def __init__(self, c):
        # Actually, I lied. One good reason to use the property in
        # the init method is to enforce bounds checking.
        self.celcius = c

    # We offer factory methods that let the user be explicit about
    # how the initial value is provided.
    @staticmethod
    def in_celcius(c):
        return Temperature(c)

    @staticmethod
    def in_fahrenheit(f):
        return Temperature((f - 32) * 5/9)

    # Now we define properties that let us get and set the value
    # as either a celcius value or a fahrenheit one.
    @property
    def celcius(self):
        return self._celcius

    @celcius.setter
    def celcius(self, c):
        if c < -273:
            raise ValueError("below absolute zero")
        self._celcius = c

    @property
    def fahrenheit(self):
        return (self._celcius * 9/5) + 32

    @fahrenheit.setter
    def fahrenheit(self, f):
        # use the other property to reuse the bounds-checking logic.
        self.celcius = (f - 32) * 5/9

好的回答!三个后续问题:1)实例变量和实例属性(或类变量和类属性)之间有什么区别?2)current_tempinit的参数。3)“但是,这不会在实例上创建温度属性,因为首先找到了该属性”。为什么属性在self.temperature被赋值给current_temp之前被发现? - DSH
1
  1. 在Python中没有“实例变量”。实际上,“变量”在Python代码中并不是最好的术语;我们有“名称”,属性是一种名称。有关更多详细信息,请尝试访问https://nedbatchelder.com/text/names1.html。
  2. 噢,我忽略了那个。无论如何,希望思路清晰明了。
  3. 请参阅有关查找规则的链接。
- Karl Knechtel

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