gpt4 book ai didi

python - 只读python属性?无法打印对象

转载 作者:太空宇宙 更新时间:2023-11-04 03:51:21 24 4
gpt4 key购买 nike

我有一个名为 xcx_Oracle.Connection 实例,我正在尝试print x.clientinfox.module 并获取:

“cx_Oracle.Connection”对象的属性“module”不可读

(奇怪的是我可以打印 x.username)

我仍然可以成功地执行 dir(x) 并且我没有时间查看 cx_Oracle 的源代码(很多是用 C 实现的)所以我想知道实现者是如何做到这一点的?是通过滚动描述符吗?或者与 __getitem__ 相关的东西?这样做的动机是什么?

最佳答案

您可以使用自定义描述符在 Python 中非常轻松地完成此操作。

查看Descriptor Example在指南中。如果您只是更改 __get__ 方法以引发 AttributeError……就是这样。我们不妨重命名它并删除日志记录内容以使其更简单。

class WriteOnly(object):
"""A data descriptor that can't be read.
"""

def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name

def __get__(self, obj, objtype):
raise AttributeError("No peeking at attribute '{}'!".format(self.name))

def __set__(self, obj, val):
self.val = val

class MyClass(object):
x = WriteOnly(0, 'x')

m = MyClass()
m.x = 20 # works
print(m.x) # raises AttributeError

请注意,在 2.x 中,如果您忘记了 (object) 并创建了一个经典类,描述符将不起作用。 (我相信描述符本身实际上可以是经典类……但不要那样做。)在 3.x 中,没有经典类,所以这不是问题。

那么,如果该值是只写的,您将如何读取它?

好吧,这个玩具示例毫无用处。但是你可以,例如,在 obj 而不是你自己上设置一些私有(private)属性,此时知道数据存储位置的代码可以找到它,但随意的内省(introspection)不能。


但您甚至不需要描述符。如果您想要一个只写属性,而不管您将它附加到哪个类,那是一回事,但如果您只想阻止对特定类的某些成员的读取访问,则有一种更简单的方法:

class MyClass(object):
def __getattribute__(self, name):
if name in ('x', 'y', 'z'):
raise AttributeError("No! Bad user! You cannot see my '{}'!".format(name))
return super().__getattribute__(self, name)

m = MyClass()
m.x = 20
m.x # same exception

有关更多详细信息,请参阅 data model 中的 __getattr____getattribute__ 文档文档中的章节。

在 2.x 中,如果您将 (object) 关闭并创建一个经典类,则属性查找规则完全不同,并且没有完全记录,您真的不希望学习它们,除非你打算在 90 年代花很多时间,所以……不要那样做。此外,2.x 显然需要 2.x 风格的显式 super 调用,而不是 3.x 风格的魔法 super()


从 C API 方面来看,您拥有大部分相同的 Hook ,但它们有些不同。参见 PyTypeObject s 了解详细信息,但基本上:

  • tp_getset 可让您使用 getter 和 setter 函数自动构建描述符,这与 @property 类似但不完全相同。
  • tp_descr_gettp_descr_set 分别用于构建描述符。
  • tp_getattrotp_setattro 类似于 __getattr____setattr__ ,除了它们被调用的规则有点不同,当您知道没有需要 Hook 属性访问的基类时,您通常会调用 PyObject_GenericGetAttr 而不是委托(delegate)给 super()

不过,您为什么会那样做?

就我个人而言,我已经完成了类似的工作以了解有关 Python 数据模型和描述符的更多信息,但这并不是将其放入已发布库中的理由。

我猜通常有人这样做是因为他们试图在 Python 上强加错误的 OO 封装概念(基于传统的 C++ 模型)——或者更糟的是,试图构建 Java 风格封装安全(如果没有安全的类加载器和它附带的所有东西,它就无法工作)。

但在某些情况下,可能存在一些通用代码通过内省(introspection)使用这些对象,并且“欺骗”该代码可能以一种试图欺骗人类用户的方式有用。例如,想象一个序列化库试图 pickle 或 JSON-ify 或任何所有属性。您可以轻松地将其编写为忽略不可读的属性。 (当然,您也可以很容易地做到这一点,比如说,忽略以 _ 为前缀的属性……)

至于为什么 cx_Oracle 这样做......我从来没有看过它,所以我不知道。

关于python - 只读python属性?无法打印对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21148044/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com