解决在3.6之前的Python版本中不设置u name_uu的方法

2024-09-29 05:15:31 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python3.6中,我可以使用__set_name__钩子来获取描述符的类属性名。如何在python2.x中实现这一点?在

以下是在Python 3.6中运行良好的代码:

class IntField:
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if not isinstance(value, int):
            raise ValueError('expecting integer')
        instance.__dict__[self.name] = value

    def __set_name__(self, owner, name):
        self.name = name

class Example:
    a = IntField()

Tags: instancenameselfreturnif属性valuedef
2条回答

有各种不同程度的解决方案。我总是喜欢用类装饰器。在

class IntField(object):
    def __get__(self, instance, owner):            
        if instance is None:
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):            
        if not isinstance(value, int):
            raise ValueError('expecting integer')
        instance.__dict__[self.name] = value

def with_intfields(*names):
    def with_concrete_intfields(cls):
        for name in names:
            field = IntField()
            field.name = name
            setattr(cls, name, field)
        return cls
    return with_concrete_intfields

你可以这样使用它:

^{pr2}$

演示:

$ python2.7 -i clsdec.py
>>> [x for x in vars(Example) if not x.startswith('_')]
['a', 'b']
>>> Example.a.name
'a'
>>> e.a = 3
>>> e.b = 'test'
[...]
ValueError: expecting integer

请确保在Python2.7中显式地从object子类,这让我在起草这个答案的第一个版本时遇到了麻烦。在

您可能正在寻找元类,有了它,您可以在类创建时处理类属性。在

class FooDescriptor(object):
    def __get__(self, obj, objtype):
        print('calling getter')

class FooMeta(type):
    def __init__(cls, name, bases, attrs):
        for k, v in attrs.iteritems():
            if issubclass(type(v), FooDescriptor):
                print('FooMeta.__init__, attribute name is "{}"'.format(k))

class Foo(object):
    __metaclass__ = FooMeta
    foo = FooDescriptor()


f = Foo()
f.foo

输出:

^{pr2}$

如果需要在创建类之前更改类,则需要在元类中重写__new__,而不是{}。有关此主题的详细信息,请参阅此答案:Is there any reason to choose __new__ over __init__ when defining a metaclass?

相关问题 更多 >