Python 对象不是基于结构的(如 C++ 或 Java),它们是基于字典的(如 Javascript)。这意味着实例属性是动态的(您可以在运行时添加新属性或删除现有属性),并且不是在类级别而是在实例级别定义的,并且通过分配给它们来定义它们非常简单。虽然从技术上讲,它们可以在代码中的任何位置(甚至在类之外)定义,但惯例(和良好做法)是在初始化程序(__init__ 方法 - 真正的构造函数被命名为 @ 987654323@ 但几乎没有理由重写它)以明确给定类的实例应该具有哪些属性。
注意这里使用的术语“属性”——在python中,我们不谈论“成员变量”或“成员函数”,而是谈论“属性”和“方法”。实际上,由于 Python 类也是对象(type 类的实例或子类),它们也有属性,所以我们有实例属性(每个实例)和类属性(属于类对象本身) ,并在实例之间共享)。可以在实例上查找类属性,只要它没有被同名的实例属性遮蔽。
此外,由于 Python 函数也是对象(提示:在 Python 中,所有东西——你可以放在赋值的 RHS 上的所有东西——都是一个对象),“数据”属性和“函数”没有不同的命名空间" 属性,而 Python 的“方法”实际上是在类本身上定义的函数 - IOW 它们是恰好是 function 类型的实例的类属性。由于方法需要访问实例才能对其进行处理,there's a special mechanism that allow to "customize" attribute access 所以一个给定的对象 - 如果它实现了正确的接口 - 当它在一个实例上查找但在类上解析时,它可以返回除自身之外的其他东西。这种机制被函数使用,因此它们将自己变成方法(将函数和实例包装在一起的可调用对象,因此您不必将实例传递给函数),而且更普遍地作为对计算属性的支持。
property 类是计算属性的通用实现,它包装了一个 getter 函数(最终是一个 setter 和一个 deleter)——因此在 Python 中“属性”具有非常特定的含义(property 类本身或它的实例)。此外,@decorator 语法没有什么神奇之处(也不是特定于属性),它只是语法糖,所以给定了一个“装饰器”函数:
def decorator(func):
return something
这个:
@decorator
def foo():
# code here
只是一个快捷方式:
def foo():
# code here
foo = decorator(foo)
在这里,我将decorator 定义为一个函数,但可以使用任何可调用对象(“可调用”对象是定义__call__ 魔术方法的类的实例)来代替-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
>>>
作为结论:如果你希望用一种语言做任何有用的事情,你必须学习这种语言——你不能仅仅期望它像你知道的其他语言一样工作。虽然一些特性是基于通用概念(即函数、类等),但它们实际上可以以完全不同的方式实现(Python 的对象模型与 Java 的对象模型几乎没有共同之处),因此只需尝试编写 Java(或 C 或C++ 等)在 Python 中不起作用(就像尝试在 Java FWIW 中编写 Python 一样)。
注意:只是为了完整起见:Python 对象 可以 实际上通过使用 __slots__ 来“基于结构” - 但这里的目的不是防止动态添加属性(这只是副作用),但要使这些类的实例在大小上“更轻”(当您知道在给定时间将拥有数千或更多实例时,这很有用)。