问题是指哪个更适合用于哪个用例,而不是技术背景。
在 python 中,您可以通过属性、描述符或魔术方法来控制属性的访问。在哪个用例中哪个是最pythonic的?它们似乎都具有相同的效果(请参见下面的示例)。
我正在寻找这样的答案:
- 属性:应在……情况下使用
- 描述符:在……的情况下,应该使用它而不是属性。
- 魔术方法:仅在……时使用。
示例
用例是可能无法在 __init__
方法中设置的属性,例如,因为该对象尚未出现在数据库中,但稍后会出现。每次访问属性时,都应尝试设置并返回。
作为在 Python shell 中使用复制和粘贴的示例,有一个类只想在第二次被要求时显示其属性。那么,哪一种是最好的方法,或者在不同的情况下,其中一种更可取?以下是实现它的三种方法:
具有属性::
class ContactBook(object):
intents = 0
def __init__(self):
self.__first_person = None
def get_first_person(self):
ContactBook.intents += 1
if self.__first_person is None:
if ContactBook.intents > 1:
value = 'Mr. First'
self.__first_person = value
else:
return None
return self.__first_person
def set_first_person(self, value):
self.__first_person = value
first_person = property(get_first_person, set_first_person)
使用 __getattribute__
::
class ContactBook(object):
intents = 0
def __init__(self):
self.first_person = None
def __getattribute__(self, name):
if name == 'first_person' \
and object.__getattribute__(self, name) is None:
ContactBook.intents += 1
if ContactBook.intents > 1:
value = 'Mr. First'
self.first_person = value
else:
value = None
else:
value = object.__getattribute__(self, name)
return value
描述符::
class FirstPerson(object):
def __init__(self, value=None):
self.value = None
def __get__(self, instance, owner):
if self.value is None:
ContactBook.intents += 1
if ContactBook.intents > 1:
self.value = 'Mr. First'
else:
return None
return self.value
class ContactBook(object):
intents = 0
first_person = FirstPerson()
它的每一个都有这种行为::
book = ContactBook()
print(book.first_person)
# >>None
print(book.first_person)
# >>Mr. First
最佳答案
基本上,尽可能使用最简单的。粗略地说,复杂性/重型性的顺序是:常规属性,property
, __getattr__
, __getattribute__
/描述符。 (__getattribute__
和自定义描述符都是您可能不需要经常做的事情。)这引出了一些简单的经验法则:
- 不要使用
property
如果普通属性会起作用。 - 如果
property
不写你自己的描述符将工作。 - 不要使用
__getattr__
如果property
将工作。 - 不要使用
__getattribute__
如果__getattr__
将工作。
更具体地说:使用属性来自定义对一个或一小组属性的处理;使用 __getattr__
定制所有属性的处理,或者除了一小部分之外的所有属性;使用 __getattribute__
如果你希望使用 __getattr__
但它不太管用;如果您正在做一些非常复杂的事情,请编写您自己的描述符类。
您使用 property
当您有一个或一小组属性时,您想要 Hook 其获取/设置。也就是说,你想要像 obj.prop
这样的东西和 obj.prop = 2
secret 调用您编写的函数来自定义发生的情况。
您将使用 __getattr__
当您想要对如此多的属性执行此操作时,您实际上并不想单独定义它们,而是希望将整个属性访问过程作为一个整体进行自定义。换句话说,而不是 Hook obj.prop1
, 和 obj.prop2
等等,你有这么多,你希望能够 Hook obj.<anything>
,并进行一般处理。
然而,__getattr__
仍然不会让您覆盖真正存在的属性所发生的情况,它只是让您 Hook 对任何使用属性的全面处理,否则会引发 AttributeError。使用 __getattribute__
让您可以处理一切,甚至可以正常工作而不会弄乱 __getattribute__
的普通属性.因此,使用 __getattribute__
有可能破坏相当基本的行为,因此只有在考虑使用 __getattr__
时才应使用它这还不够。它还会对性能产生显着影响。例如,您可能需要使用 __getattribute__
如果您正在包装一个定义某些属性的类,并且您希望能够以自定义方式包装这些属性,以便它们在某些情况下照常工作,但在其他情况下获得自定义行为。
最后,我想说编写您自己的描述符是一项相当高级的任务。 property
是一个描述符,对于大约 95% 的情况,它是您唯一需要的。 here 给出了一个很好的简单示例,说明您为什么要编写自己的描述符: 基本上,如果你不得不写几个 property
,你可能会这样做具有相似行为;描述符可让您分解出常见行为以避免代码重复。例如,自定义描述符用于驱动 Django 和 SQLAlchemy 等系统。如果您发现自己正在编写那种复杂程度的东西,您可能需要编写一个自定义描述符。
在您的示例中,property
将是最好的选择。如果你正在做 if name == 'somespecificname'
,它通常(不总是)是一个危险信号。里面__getattribute__
.如果您只需要专门处理一个特定的名称,您可能可以做到这一点,而不必屈服于 __getattribute__
的级别。 .同样,如果你为它的 __get__
编写所有描述符,那么编写你自己的描述符也没有意义。是您可以在属性的 getter 方法中编写的内容。
关于python - 属性与描述符与 __getattribute__ 的用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22616559/