如何处理Python查找:创建一个点分隔的名称并使用它直到销毁 = 777

6 投票
1 回答
3900 浏览
提问于 2025-04-15 15:15

我刚开始学Python,对Python的点名查找过程特别感兴趣,想要试试。请问我该如何在“make.py”里写一个类或函数,让这些赋值语句能够成功运行呢?

import make

make.a.dot.separated.name = 666
make.something.else.up = 123
make.anything.i.want = 777

1 个回答

20
#!/usr/bin/env python

class Make:
    def __getattr__(self, name):
        self.__dict__[name] = Make()
        return self.__dict__[name]

make = Make()

make.a.dot.separated.name = 666
make.anything.i.want = 777

print make.a.dot.separated.name
print make.anything.i.want

当找不到某个命名的值时,会调用这个特别的 __getattr__ 方法。比如说,写 make.anything.i.want 其实就相当于:

m1 = make.anything    # calls make.__getattr__("anything")
m2 = m1.i             # calls m1.__getattr__("i")
m2.want = 777

上面的实现通过调用 __getattr__ 方法,创建了一系列的 Make 对象,每当访问一个未知的属性时,就会这样做。这让我们可以把点号访问嵌套得很深,直到最后赋值的时候,才会真正给这个属性一个值。

Python 文档 - 自定义属性访问:

object.__getattr__(self, name)

当在常规地方找不到某个属性时,就会调用这个方法(也就是说,这个属性既不是实例属性,也不在 self 的类树中)。name 是属性的名字。这个方法应该返回计算出来的属性值,或者抛出一个 AttributeError 异常。

要注意,如果通过正常的方式找到了这个属性,就不会调用 __getattr__()。这是 __getattr__()__setattr__() 之间故意设计的不对称。这么做是为了提高效率,同时也因为如果不这样的话,__getattr__() 就没有办法访问实例的其他属性。值得一提的是,至少对于实例变量来说,你可以通过不在实例属性字典中插入任何值(而是插入到另一个对象中)来假装拥有完全的控制权。想要在新式类中真正实现完全控制,可以参考下面的 __getattribute__() 方法。

object.__setattr__(self, name, value)

当尝试给某个属性赋值时,就会调用这个方法。这个方法会替代正常的机制(也就是说,把值存储在实例字典中)。name 是属性的名字,value 是要赋给它的值。

如果 __setattr__() 想要给实例属性赋值,它不应该直接执行 self.name = value —— 这样会导致递归调用自己。相反,它应该把值插入到实例属性的字典中,比如 self.__dict__[name] = value。对于新式类来说,应该调用同名的基类方法,而不是直接访问实例字典,例如 object.__setattr__(self, name, value)

撰写回答