Python 为什么要在构造函数中放置属性变量

Python 为什么要在构造函数中放置属性变量,python,oop,constructor,properties,Python,Oop,Constructor,Properties,从其他语言中,我习惯于编写一个类属性,之后我可以访问它,而无需像 在几乎所有的例子中,我处理的属性变量都在构造函数self中 Class MyClass: def __init__(self, value = 0): self._value = value 对我来说,这没有意义,因为你想在属性中设置它。谁能解释一下把value变量放在构造函数中有什么用吗?因为@property不是一个变量的装饰器,它是一个允许它像属性一样工作的函数。您仍然需要创建一个类变量来使用由@p

从其他语言中,我习惯于编写一个类属性,之后我可以访问它,而无需像

在几乎所有的例子中,我处理的属性变量都在构造函数self中

Class MyClass:
    def __init__(self, value = 0):
        self._value = value
对我来说,这没有意义,因为你想在属性中设置它。谁能解释一下把value变量放在构造函数中有什么用吗?

因为@property不是一个变量的装饰器,它是一个允许它像属性一样工作的函数。您仍然需要创建一个类变量来使用由@property修饰的函数:

@property decorator将voltage方法转换为同名只读属性的“getter”,并将voltage的docstring设置为“获取当前电压”

属性对象具有可用作装饰器的getter、setter和deleter方法,这些方法创建属性的副本,并将相应的访问器函数设置为装饰函数。最好用一个例子来说明这一点:


我猜你是从C++语言或java语言来的,通常把属性私有化,然后为它们写显式的吸气剂和设定器。在Python中,除了按约定之外,没有私有的东西,并且不需要为只需要按原样编写和读取的变量编写getter和setter@属性和相应的setter decorators可用于添加其他行为,如日志记录访问,或具有可以像真实属性一样访问的伪属性,例如,您可能有一个由半径定义的Circle类,但您可以为直径定义一个@属性,这样您仍然可以编写Circle.diameter

更具体地说,对于您的问题:如果要在创建对象时设置属性,则希望将该属性作为初始值设定项的参数。您不希望创建一个空对象,然后立即用属性填充它,因为这样会产生大量噪音并降低代码的可读性


顺便说一句:uu init_uuu实际上不是构造函数。Python对象的构造函数是γ- Nexjava,并且几乎从不覆盖它。

< P> Python对象不是基于C++或Java的结构,它们是基于JavaScript的DICT。这意味着实例属性是动态的,您可以在运行时添加新属性或删除现有属性,它们不是在类级别定义的,而是在实例级别定义的,它们的定义非常简单,只需为它们赋值即可。虽然从技术上讲,它们可以在代码中的任何地方定义,甚至在类之外,约定和良好实践是最终将它们定义为初始值设定项中的默认值_init__方法-真正的构造函数名为_new__,但很少有理由重写它以明确给定类的实例应该具有哪些属性

注意这里使用的术语属性——在python中,我们不讨论成员变量或成员函数,而是讨论属性和方法。实际上,由于Python类也是类型类的实例或的子类的对象,它们也有属性,因此我们有每个实例的实例属性和属于类对象本身的类属性,并且在实例之间共享。可以在实例上查找类属性,只要它不被同名的实例属性遮挡

另外,由于Python函数也是对象提示:在Python中,所有东西——可以放在赋值RHS上的所有东西——都是对象,因此数据属性和函数属性没有不同的名称空间,Python的方法实际上是在类本身上定义的函数——也就是说,它们是类属性,恰好是函数类型的实例。由于方法需要访问实例才能对其进行处理,因此给定对象(如果它实现了适当的接口)在查找实例但在类上解析时,可以返回其他对象。函数使用这种机制,因此它们将自己转变为方法可调用对象,将函数和实例包装在一起,这样您就不必将实例传递给函数,但更一般地说,它支持计算属性

属性类是计算属性的通用实现,它封装了一个getter函数,并最终封装了一个setter和一个deleter——因此在Python中属性有一个非常特殊的含义,即属性类本身或它的一个实例。此外,@decorator语法并不是什么神奇的东西,也不是特定于属性的,它只是一种语法糖,因此给定一个decorator函数:

 def decorator(func):
     return something
这:

这只是一个快捷方式:

 def foo():
     # code here

 foo = decorator(foo)
在这里,我将decorator定义为一个函数,但任何可调用对象可调用对象都是一个类的实例,该类定义了_call _; magic方法 d Python类是可调用的,甚至可以通过调用实例化它的类来实现

回到你的代码:

# in py2, you want to inherit from `object` for
# descriptors and other fancy things to work.
# this is useless in py3 but doesn't break anything either...

class MyClass(object):

    # the  `__init__` function will become an attribute
    # of the `MyClass` class object

    def __init__(self, value=0):
        # defines the instance attribute named `_value`
        # the leading underscore denotes an "implementation attribute"
        # - something that is not part of the class public interface
        # and should not be accessed externally (IOW a protected attribute)
        self._value = value

    # this first defines the `my_property` function, then
    # pass it to `property()`, and rebinds the `my_property` name
    # to the newly created `property` instance. The `my_property` function
    # will then become the property's getter (it's `fget` instance attribute)
    # and will be called when the `my_property` name is resolved on a `MyClass` instance

    @property
    my_property(self):
        print('I got the value: {}'.format(self._value))
        # let's at least return something
        return self._value
然后,您可能希望检查该类及其实例:

>>> print(MyClass.__dict__)
{'__module__': 'oop', '__init__': <function MyClass.__init__ at 0x7f477fc4a158>, 'my_property': <property object at 0x7f477fc639a8>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}
>>> print(MyClass.my_property)
<property object at 0x7f477fc639a8>
>>> print(MyClass.my_property.fget)
<function MyClass.my_property at 0x7f477fc4a1e0>
>>> m = MyClass(42)
>>> print(m.__dict__)
{'_value': 42}
>>> print(m.my_property)
I got the value: 42
42
>>> 
作为结论:如果你希望用一种语言做任何有用的事情,你必须学习这种语言——你不能期望它能像你所知道的其他语言一样工作。虽然一些特性是基于通用概念IE函数、类等,但它们实际上可以以完全不同的方式实现,Python的对象模型几乎与java的对象模型没有任何共同之处,所以只需在Python中编写java或C++或C++等就不象在java FWW中尝试编写Python一样。
注意:为了完整性起见:Python对象实际上可以通过使用_slots _;来构造为基于结构的,但这里的目的不是为了防止动态添加属性,这只是一个副作用,而是为了使这些类的实例的大小更轻,这在您知道一次将有数千个或更多的实例时非常有用给定时间。

Btw print'I获得值:'&self.\u值应为print'I获得值:%d'%self.\u我猜是值。在属性中设置它是什么意思?这个属性是不可设置的。很容易理解,我们使用@property来获取动态值。最简单的例子可能是基于当前时间获取值。它不是一个静态值,因此不能仅在初始化期间分配它。
# in py2, you want to inherit from `object` for
# descriptors and other fancy things to work.
# this is useless in py3 but doesn't break anything either...

class MyClass(object):

    # the  `__init__` function will become an attribute
    # of the `MyClass` class object

    def __init__(self, value=0):
        # defines the instance attribute named `_value`
        # the leading underscore denotes an "implementation attribute"
        # - something that is not part of the class public interface
        # and should not be accessed externally (IOW a protected attribute)
        self._value = value

    # this first defines the `my_property` function, then
    # pass it to `property()`, and rebinds the `my_property` name
    # to the newly created `property` instance. The `my_property` function
    # will then become the property's getter (it's `fget` instance attribute)
    # and will be called when the `my_property` name is resolved on a `MyClass` instance

    @property
    my_property(self):
        print('I got the value: {}'.format(self._value))
        # let's at least return something
        return self._value
>>> print(MyClass.__dict__)
{'__module__': 'oop', '__init__': <function MyClass.__init__ at 0x7f477fc4a158>, 'my_property': <property object at 0x7f477fc639a8>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}
>>> print(MyClass.my_property)
<property object at 0x7f477fc639a8>
>>> print(MyClass.my_property.fget)
<function MyClass.my_property at 0x7f477fc4a1e0>
>>> m = MyClass(42)
>>> print(m.__dict__)
{'_value': 42}
>>> print(m.my_property)
I got the value: 42
42
>>>