问题 在Python中将PHP的__get()与__get __()和__getattr __()进行比较


有什么区别 __get__() 和 __getattr__() 在Python?我来自PHP背景,只有 __get()。我什么时候应该使用哪个功能?

我一直试图解决这个问题。我看到很多问题 这个,询问之间的区别 __getattr__() 和 __getattribute__()但是。


1133
2017-11-24 14:44


起源



答案:


您将找到所有这些方法的详细文档 这里

来自PHP,您应该首先熟悉Python对象模型。它比PHP更丰富,所以你不应该尝试将你的PHP知识1:1映射到Python。如果要开发PHP,请使用PHP。如果你想用Python开发,学习Python。

回到原来的问题: __getattr__ 可能是与...相同的功能 __get PHP中的函数。 __get__ 在Python中用于实现描述符。有关描述符的详细信息也可以在我上面提到的文档中找到。


5
2017-11-24 15:02



你几乎不值得 决不 必须直接访问这些方法。您可能需要覆盖它们,但是您永远不应该调用它们。 - Daniel Roseman
@Daniel Roseman:几乎从不,但是 classproperty(property) 不能被实例遮蔽的东西可能很方便 def __get__(self, obj, cls): return self.fget.__get__(cls, type(cls))() 和 def __set__(self, obj, val): self.fset.__get__(type(obj), type(type(obj)))(val)。 - eryksun
当然, __getattr__() 类似于PHP __get(),但有一些重要的区别。有关详细信息,请参阅我的回答 - phant0m


答案:


您将找到所有这些方法的详细文档 这里

来自PHP,您应该首先熟悉Python对象模型。它比PHP更丰富,所以你不应该尝试将你的PHP知识1:1映射到Python。如果要开发PHP,请使用PHP。如果你想用Python开发,学习Python。

回到原来的问题: __getattr__ 可能是与...相同的功能 __get PHP中的函数。 __get__ 在Python中用于实现描述符。有关描述符的详细信息也可以在我上面提到的文档中找到。


5
2017-11-24 15:02



你几乎不值得 决不 必须直接访问这些方法。您可能需要覆盖它们,但是您永远不应该调用它们。 - Daniel Roseman
@Daniel Roseman:几乎从不,但是 classproperty(property) 不能被实例遮蔽的东西可能很方便 def __get__(self, obj, cls): return self.fget.__get__(cls, type(cls))() 和 def __set__(self, obj, val): self.fset.__get__(type(obj), type(type(obj)))(val)。 - eryksun
当然, __getattr__() 类似于PHP __get(),但有一些重要的区别。有关详细信息,请参阅我的回答 - phant0m


首先,PHP确实如此  有一个相当于Python的 __get__() - 差远了!你最需要的是什么 __getattr__()

我来自PHP背景,只有 __get__

PHP 有一个 神奇的方法 叫 __get(),只要您尝试访问不存在的属性,就会调用它。

非等价物的简短列表

首先,让我们清楚一些事情:

  • PHP确实如此  有一个相当于Python的 __get__()
  • PHP确实如此  有一个相当于Python的 __getattr__()
  • PHP确实如此  有一个相当于Python的 __getattribute__()
  • Python确实如此  有一个相当于PHP的 __get()

(并分别针对所有setter方法。)

与Achim的假设相反, __get() 不  和Python一样 __getattr__()
Python不区分方法和属性,但PHP确实如此,这就是PHP有第二种方法的原因: __call()

__call() 每当您尝试在不存在的对象上调用方法时执行。 Python没有相应的,因为一个方法只是一个可调用的对象(属性)。

PHP中的一个例子:

<?php

$obj = new stdClass();
($obj->test)();

在Python中,这将失败 AttributeError。但是,在PHP中,这样做 甚至没有编译

解析错误:语法错误,意外'('第4行

与Python比较:

obj.method()
# is eqvuivalent to:
(obj.method)()

这是一个重要的区别。我们得出结论,PHP和Python思考调用方法的方式完全不同。

PHP的“呼叫意识”

  • PHP的 obj  知道 你称之为方法
    • 您可以在调用的对象上显式处理对不存在的方法的调用
    • 这是因为PHP的表达式模型非常不一致(PHP 5.4虽然向前迈了一小步)
  • 但是Python的 obj 不

这使得PHP可以拥有 obj.does_not_exist 评估 3但是 obj.does_not_exist() 至 5

据我所知,在Python中不可能这样做。 (这将允许我们将PHP的不一致性描述为一项功能。)

因此,我们将一个子弹点扩展到“不等效”列表:

  • Python确实如此  有一个相当于PHP的 __call()/__callStatic()

总结一下

PHP提供了两种不同的机制:

  • __get() 对于不存在的属性
  • __call() 用于调用不存在的方法

Python只有一种机制,因为它不区分属性和方法,只要它涉及它们都是属性。

  • __getattr__() 当属性不存在时调用。
  • obj.non_existing() 不是特殊的“调用语法”,它是调用运算符的表达式 () 被申请;被应用: (obj.__getattr__("non_existing"))()

放弃__getattr__() 当属性不存在时,并不总是调用。 __getattribute__() 在查找链中具有最高优先级,因此可能导致 __getattr__() 被忽略

__get__() Python中的内容与上面提到的完全不同。

该文档描述了描述符 "a descriptor is an object attribute with “binding behavior”"。我可以直接理解“绑定行为”应该是什么意思,但仅仅因为我已经理解了描述符的作用。

我会选择将描述符描述为“自我意识 属性“可以在多个类之间共享。

让我解释一下,我的意思是“自我意识”。这样的属性:

  • 知道 当他们被访问或阅读时
  • 知道 当他们被写入
  • 知道 他们是通过阅读/撰写的
  • 知道 当他们被删除

这些属性是独立的对象:“描述符”对象,即遵循所谓的对象 “描述符协议”,它定义了一组方法及其对应的签名,这些对象可以实现。

对象不拥有描述符属性。实际上,它们属于对象的对应类(或其祖先)。但是,相同的描述符对象可以“属于”多个类。

注意:“通过他们阅读的人”,提及的正确方法是什么 obj 在 obj.attr?我会说: attr 访问“通过” obj


8
2017-08-10 12:15



你可以用Python做任何事情。 imgur.com/a/qJ5wp - Beetle