21 октомври 2008

Речник с директен достъп до стойностите в Python

Често попадам на интересни хакове в python, които с помощта на някакъв странен клас, със странни нечетими методи, успява на направи нещо готино с езика, но от друга страна е супер грозно. Днес попаднах на един прост и елегантен хак, който не е грозен, а напротив, дори е красив. Ето кода който намерих:

class AttrDict(dict):

def __getattr__(self, name):
if name in self:
return self[name]
raise AttributeError('%s not found' % name)

def __setattr__(self, name, value):
self[name] = value


Както виждате този клас описва речник, който има странни __getattr__ и __setattr__ методи, които му придават чара. Общо взето, този код дефинира нов вид речник, със директен OO достъп, да речем че направим това:

person = AttrDict({'id': 5})


Виждате че personе инстанция на този клас, който пък от своя страна наследява от инстанция на метакласът dict, т.е. казваме му да наследи всичките атрибути и методи на речника {'id': 5}, но всеки речник, би свършил работа, ако бяхме оставили скобите празни, само щяхме да имаме празен речник от новия тип. Сега, новите атрибути __settattr__ и __getattr__, които горния клас предефинира, имат готин ефект:

print person.id # 5
person.id = 6
print person.id # 6


Това е синтактична захар за това:

print person[id] # 5
person[id] = 6
print person[id] # 6


Елегантно и красиво, но ето и недостатъка, не може да използвате литерали(числа, например), като ключове в речника, или поне няма да можете да имате достъп до тях, т.е. Това не работи:

person = AttrDict({1: 5})
person.1 #изписва грешка
person[1] #връща 5


Може би това е една от причините поради която Python няма това нещо вградено, не бих си представил как Гуидо би реагирал, но или ще избухне в гняв, или ще падне на пода от смях.

Няма коментари: