По существу я хочу сделать что-то вроде этого:
class foo:
x = 4
@property
@classmethod
def number(cls):
return x
Затем я хотел бы, чтобы следующее работало:
>>> foo.number
4
К сожалению, вышеупомянутое не работает. Вместо данного меня 4
это дает мне <property object at 0x101786c58>
. Там какой-либо путь состоит в том, чтобы достигнуть вышеупомянутого?
Дескриптор свойства
всегда возвращает сам себя при доступе из класса (т. Е. Когда экземпляр
имеет значение None
в его методе __ get __
) .
Если это не то, что вы хотите, вы можете написать новый дескриптор, который всегда использует объект класса ( владелец
) вместо экземпляра:
>>> class classproperty(object):
... def __init__(self, getter):
... self.getter= getter
... def __get__(self, instance, owner):
... return self.getter(owner)
...
>>> class Foo(object):
... x= 4
... @classproperty
... def number(cls):
... return cls.x
...
>>> Foo().number
4
>>> Foo.number
4
Это сделает Foo.number
свойством только для чтения :
class MetaFoo(type):
@property
def number(cls):
return cls.x
class Foo(object, metaclass=MetaFoo):
x = 4
print(Foo.number)
# 4
Foo.number = 6
# AttributeError: can't set attribute
Объяснение : Обычный сценарий при использовании внешнего вида @property примерно так:
class Foo(object):
@property
def number(self):
...
foo = Foo()
Свойство, определенное в Foo
, доступно только для чтения по отношению к своим экземплярам. То есть foo.number = 6
вызовет AttributeError
.
Аналогично, если вы хотите, чтобы Foo.number
вызывал ошибку AttributeError
, вам необходимо настроить свойство, определенное в типе (Foo)
. Отсюда необходимость в метаклассе.
Обратите внимание, что этот доступ только для чтения не застрахован от хакеров. Свойство можно сделать доступным для записи, изменив Foo class:
class Base(type): pass
Foo.__class__ = Base
# makes Foo.number a normal class attribute
Foo.number = 6
print(Foo.number)
печатает
6
или, если вы хотите сделать Foo.number
настраиваемым свойством,
class WritableMetaFoo(type):
@property
def number(cls):
return cls.x
@number.setter
def number(cls, value):
cls.x = value
Foo.__class__ = WritableMetaFoo
# Now the assignment modifies `Foo.x`
Foo.number = 6
print(Foo.number)
также печатает 6.