18

我见过两个不同的 Python 对象用于将任意数据组合在一起:空类和函数。

def struct():
    pass

record = struct
record.number = 3
record.name = "Zoe"


class Struct:
    pass

record = Struct()
record.number = 3
record.name = "Zoe"

即使该类不是空的,只要它是在运行时定义的,它似乎就可以工作。

但是当我变得自大并尝试使用内置函数或类来做到这一点时,它不起作用。

record = set()
record.number = 3
AttributeError: 'set' object has no attribute 'number'

record = pow
pow.number = 3
AttributeError: 'builtin_function_or_method' object has no attribute 'number'

解释这种行为的内置类和“自定义”类和函数之间是否存在根本区别?

4

4 回答 4

8

不同之处在于函数对象和您的 Struct 对象都有__dict__属性,但set实例和内置函数没有:

>>> def struct():
...     pass
...
>>> record = struct
>>> record.number = 2
>>> struct.__dict__
{'number': 2}
>>> class Struct:
...     pass
...
>>> record = Struct()
>>> record.number = 3
>>> record.__dict__
{'number': 3}
>>> record=set()
>>> record.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'set' object has no attribute '__dict__'
>>> pow.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute '__dict__'

在类中,您可以使用插槽来模拟行为(尽管仅限于新型类):

>>> class StructWithSlots(object):
...     __slots__ = []
...
>>> record = StructWithSlots()
>>> record.number = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'StructWithSlots' object has no attribute 'number'
>>> record.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'StructWithSlots' object has no attribute '__dict__'
于 2013-07-11T14:32:16.560 回答
3

内置类型是用 C 编写的,不能像那样修改。但是在 py2.2 中引入的类型/类统一之后,您现在可以从内置类型继承并覆盖或添加您自己的属性到该子类。

您可以使用disabledfood包为内置类型添加属性:

该项目旨在为您提供在测试中找到天堂的方法,但如果您在生产代码中使用它可能会导致您下地狱。

>>> from forbiddenfruit import curse 
>>> def words_of_wisdom(self):
 ...     return self * "blah "
>>> curse(int, "words_of_wisdom", words_of_wisdom)
>>> assert (2).words_of_wisdom() == "blah blah "

当然,如果您足够自大,那么您可以在 C 中创建自己的类型并为其添加此类功能。

于 2013-07-11T13:59:02.823 回答
2

一些内置插件可能更具限制性。此外,使用插槽实现的类也不接受任意属性。

于 2013-07-11T13:55:35.840 回答
1

如果您想在自己的类中进行一些类似的保护,可以使用该__setattr__()方法。

class TestClass(object):
    # Accept the attributes in this list
    __valid_attributes = ["myattr1", "myattr2"]

    def __setattr__(self, name, value):
        if not name in TestClass.__valid_attributes:
            raise AttributeError(
                "{0} has no attribute '{1}'".format(self.__class__.__name__, name))
        self.__dict__[name] = value

现在您可以执行以下操作:

t = TestClass()
t.noattr = "test" # AttributeError: TestClass has no attribute 'noattr'

但是仍然可以设置“有效属性”:

t = TestClass()
t.myattr1 = "test"
print(t.myattr1) # test
于 2013-07-11T14:23:12.963 回答