ऊपर समाधान के साथ समस्या यह है कि यह उदाहरण चर से वर्ग चर तक पहुँचने के लिए काम नहीं होता है:
print(Foo.number)
# 4
f = Foo()
print(f.number)
# 'Foo' object has no attribute 'number'
इसके अलावा, metaclass स्पष्ट का उपयोग नहीं किया जाता है तो अच्छा, नियमित property
सजावट का उपयोग करने के रूप में।
मैंने इन समस्याओं को हल करने का प्रयास किया। यहाँ कैसे यह अब काम करता है:
@classproperty_support
class Bar(object):
_bar = 1
@classproperty
def bar(cls):
return cls._bar
@bar.setter
def bar(cls, value):
cls._bar = value
# @classproperty should act like regular class variable.
# Asserts can be tested with it.
# class Bar:
# bar = 1
assert Bar.bar == 1
Bar.bar = 2
assert Bar.bar == 2
foo = Bar()
baz = Bar()
assert foo.bar == 2
assert baz.bar == 2
Bar.bar = 50
assert baz.bar == 50
assert foo.bar == 50
जैसा कि आप देख, हम @classproperty
उस वर्ग चर के लिए @property
के रूप में उसी तरह काम करता है। केवल एक चीज जिसकी हमें आवश्यकता होगी अतिरिक्त @classproperty_support
कक्षा सजावट है।
समाधान केवल पढ़ने-योग्य वर्ग गुणों के लिए भी काम करता है।
class classproperty:
"""
Same as property(), but passes obj.__class__ instead of obj to fget/fset/fdel.
Original code for property emulation:
https://docs.python.org/3.5/howto/descriptor.html#properties
"""
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj.__class__)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj.__class__, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(obj.__class__)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel, self.__doc__)
def classproperty_support(cls):
"""
Class decorator to add metaclass to our class.
Metaclass uses to add descriptors to class attributes, see:
http://stackoverflow.com/a/26634248/1113207
"""
class Meta(type):
pass
for name, obj in vars(cls).items():
if isinstance(obj, classproperty):
setattr(Meta, name, property(obj.fget, obj.fset, obj.fdel))
class Wrapper(cls, metaclass=Meta):
pass
return Wrapper
नोट:: कोड का परीक्षण नहीं किया गया है बहुत, नोट करने के लिए के रूप में आप उम्मीद करता है, तो यह काम नहीं करता स्वतंत्र महसूस
यहाँ कार्यान्वयन है।
यह केवल पढ़ने योग्य विशेषता नहीं है। पायथन वर्णनकर्ता जानबूझकर वर्ग-स्तरीय कॉल को 'setattr' और' delattr' को उनके '__set__' और '__delete__' विधियों के साथ अवरुद्ध नहीं करते हैं। तो 'Foo.number = 6' अभी भी काम कर सकता है। – HardlyKnowEm