Property with parameter...
Bengt Richter
bokr at oz.net
Mon Sep 13 13:56:04 EDT 2004
On Mon, 13 Sep 2004 11:09:07 +0200, aleaxit at yahoo.com (Alex Martelli) wrote:
>kepes.krisztian <kepes.krisztian at peto.hu> wrote:
>
>> Hi !
>>
>> I want to create a property that can use parameter(s).
>> In Delphi I can create same thing (exm: Canvas.Pixel[x,y] ->
>> Canvas.GetPixel(self,X,Y):integer; Canvas.SetPixel(self,X,Y,Color::integer);
>>
>> class A(object):
>> def __init__(self):
>> self.__Tags={}
>> def GetTag(self,tname):
>> return self.__Tags.get(tname,None)
>> def SetTag(self,tname,value):
>> self.__Tags[tname]=Value
>> Tag=property(GetTag,SetTag)
>>
>> a=A()
>> print a.Tag('A')
>> print a.Tag['A']
>>
>> But it is seems to be not possible in this way.
>
>Have your get method return an instance of an auxiliary class which
Why a get method when a.Tag can return the aux class instance as a plain attribute?
(other than that the OP mentioned 'property' and might want to protect
against a.Tag = 23 ;-) E.g. See below.
>implements __getitem__ and __setitem__ (if you want to use square
>brackets; if you want to use round parentheses, then __call__, but
>beware -- you can't have a bare call on the left of an assignment!!!).
>
>For example, a small refactoring of your attempt might be:
>
>class A(object):
>
> def __init__(self):
> self.__Tags={}
> self.__TagsAccessor = None
>
> def getTagsAccessor(self):
> if not self.__tagsAccessor:
> def getter(__, tname):
> return self.__Tags.get(tname, None)
> def setter(__, tname, value):
> self.__Tags[tname] = value
> class TagAccessor: pass
> TagAccessor.__getitem__ = getter
> TagAccessor.__setitem__ = setter
> self.__TagsAccessor = TagAccessor()
> return self.__TagsAccessor
> Tag = property(getTagsAccessor)
>
>Now, you can use such code as:
>
>a = A()
>print a.Tag['foo']
>a.Tag['foo'] = 'barbaz'
>print a.Tag['foo']
>
>Note that we define no setter at all for Tag. This means that, e.g.:
>
>a.Tag = 23
>
>will raise "AttributeError: can't set attribute". The way we coded,
>a.Tag MUST be indexed when used on the left of an = sign in an
>assignment. If that's not what you want -- if you do want to allow
>assigning to bare a.Tag without an index -- then, and only then, write
>a setTagsAccessor and give it whatever semantics you wish, and pass it
>as the second argument in the call to property.
>
>Of course, you can refactor this basic idea in many different ways. I
>have used closures for getter and setter so as to finesse any trouble
>with your use of leading double underscore, though that means that the
>first argument of getter and setter CAN'T be named self (I used __ to
>indicate I mean to ignore that argument...), but there are many other
>possibilities, such as a more general TagAccessor class which takes
>self.__Tags in its __init__, etc, etc. You could even choose to use a
>custom descriptor class instead of the built-in property, but I don't
>think that's warranted if all you need is what you have expressed.
>
If the OP doesn't need to protect against a.Tag = 23 etc., seems like a
separate class for Tag might be simplest for him? I.e.,
>>> class TagClass(object):
... def __init__(self): self.__Tags = {}
... def __getitem__(self, k): return self.__Tags.get(k, None) # per OP
... def __setitem__(self, k, v): self.__Tags[k] = v
...
>>> class A(object):
... def __init__(self): self.Tag = TagClass()
...
Then
>>> a=A()
>>> a.Tag[2,3] = 'two, three'
>>> a.Tag[2,3]
'two, three'
>>> a.Tag
<__main__.TagClass object at 0x00901210>
>>> vars(a)
{'Tag': <__main__.TagClass object at 0x00901210>}
>>> vars(a.Tag)
{'_TagClass__Tags': {(2, 3): 'two, three'}}
For me, capitalized attributes kind of grate on the convention nerve though ;-)
Regards,
Bengt Richter
More information about the Python-list
mailing list