Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!weretis.net!feeder1.news.weretis.net!feeder.erje.net!newsfeed.xs4all.nl!newsfeed6.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; 'python.': 0.04; 'parameter': 0.05; 'suppose': 0.05; 'subject:Python': 0.05; 'python': 0.08; 'attribute.': 0.09; 'bits.': 0.09; 'descriptor': 0.09; 'descriptors': 0.09; 'first:': 0.09; 'googled': 0.09; 'properly.': 0.09; 'def': 0.13; 'received:209.85.210.174': 0.13; 'received:mail-iy0-f174.google.com': 0.13; 'protocol': 0.15; '"register"': 0.16; '107': 0.16; '117': 0.16; 'attribute,': 0.16; 'instantiated': 0.16; 'metaclass': 0.16; 'name)': 0.16; 'name):': 0.16; 'instance': 0.18; 'seems': 0.19; '(or': 0.22; "doesn't": 0.22; 'here?': 0.23; 'values.': 0.23; 'consist': 0.24; 'skip:_ 20': 0.26; 'all,': 0.27; "i'm": 0.27; 'bit': 0.28; 'message- id:@mail.gmail.com': 0.28; 'pass': 0.28; 'class': 0.29; 'invoke': 0.30; 'pattern': 0.30; 'protocols': 0.30; 'value)': 0.30; 'does': 0.32; 'that,': 0.32; 'thanks': 0.32; 'to:addr:python-list': 0.33; 'there': 0.33; 'field,': 0.34; 'calling': 0.34; 'smart': 0.34; 'try:': 0.34; 'here,': 0.34; 'issue': 0.35; 'facing': 0.36; 'run': 0.37; 'reference': 0.37; 'but': 0.37; 'received:google.com': 0.37; 'skip:_ 10': 0.37; 'enough': 0.37; 'some': 0.38; 'received:209.85': 0.38; 'skip:o 20': 0.38; 'sometimes': 0.38; 'should': 0.38; 'e.g.': 0.38; 'why': 0.39; 'except': 0.39; 'called': 0.39; 'received:209': 0.39; 'or,': 0.39; 'to:addr:python.org': 0.40; 'type': 0.60; 'design': 0.61; 'below': 0.63; 'share': 0.66; 'divided': 0.73; 'charm': 0.84; 'value):': 0.84; '111': 0.91; 'fields,': 0.91 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; bh=TO0u/x0h6xg0ej9iCRe29mLQFMSznivwl5Obh9CLTnY=; b=iOjspCYr72BhFiHneE8ahFJGeSP4IYWhEevSirxQOc36VVXJVwBXEoYK+o/H78yRAh WooYKQDc9dxYesNQVQNf8Gza9nXR3wbha+YnZoMRYN7tPbjU/sBF6KFjfj3V66aho3pC 6phcFzeFEbdx10P08375s5E1CrrozF1OZk9sY= MIME-Version: 1.0 Date: Thu, 19 Jan 2012 13:55:21 +0800 Subject: Python Descriptor as Instance Attribute From: Hua Yanghao To: python-list@python.org Content-Type: text/plain; charset=UTF-8 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 65 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1326952524 news.xs4all.nl 6976 [2001:888:2000:d::a6]:42932 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:19115 Hi all, Currently descriptors only work as class attribute, and doesn't work as a descriptor when it is an instance attribute. e.g. if we have descriptor class DescriptorTest, class Dummy(object): d = DescriptorTest() class Dummy2(object): def __init__(self): self.d = DescriptorTest() The instance of Dummy2 does not invoke the descriptor protocols on "d". Whereas Dummy() instances all share the same descriptor "d". Yes I know d.__get__() have an "instance" parameter which can be used to store per-instance values, but sometimes it is just not enough (or it is that I do not know a better approach exists). Suppose the below scenario, I want to model a "Register". A register is consist of some fields, which have different number of bits. e.g. a 32 bit register divided into 3 field, bit[0] to bit[7] is called M, bit[8] to bit[15] is called N, and bit[16] to bit[31] is called Z. I want to model a register that, when instantiated as "reg", reg.M/N/Z can directly reference each field, calling a descriptor protocol to verify and return the values. Yes, I know I can use metaclass to create a different class for different registers, but that's not seems to be a very smart approach here, as I want all register instances be of type "Register". But the default python protocol will not run descriptor protocols if a descriptor is an instance attribute. I'm sure I should not be the only one that facing this issue and I googled around and found a solution to redefine the __setattr__ and __getattribute__ to look up the descriptor protocols first: 107 def __getattribute__(self, name): 108 value = object.__getattribute__(self, name) 109 if hasattr(value, '__get__'): 110 value = value.__get__(self, self.__class__) 111 return value 112 113 def __setattr__(self, name, value): 114 try: 115 obj = object.__getattribute__(self, name) 116 except AttributeError: 117 pass 118 else: 119 if hasattr(obj, '__set__'): 120 return obj.__set__(self, value) 121 return object.__setattr__(self, name, value) This works like a charm and each instance of "Register" now invoke the descriptors properly. I just do not understand, why such behavior is not a default in python. Or, is there a better design pattern here? Thanks & Best Regards, Hua Yanghao