Property with parameter...

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • kepes.krisztian

    #1

    Property with parameter...

    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):inte ger; Canvas.SetPixel (self,X,Y,Color ::integer);

    class A(object):
    def __init__(self):
    self.__Tags={}
    def GetTag(self,tna me):
    return self.__Tags.get (tname,None)
    def SetTag(self,tna me,value):
    self.__Tags[tname]=Value
    Tag=property(Ge tTag,SetTag)

    a=A()
    print a.Tag('A')
    print a.Tag['A']

    But it is seems to be not possible in this way.

    How to be can ?

    Thanx for help !
    KK


  • Alex Martelli

    #2
    Re: Property with parameter...

    kepes.krisztian <kepes.krisztia n@peto.hu> wrote:
    [color=blue]
    > 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):inte ger; Canvas.SetPixel (self,X,Y,Color ::integer);
    >
    > class A(object):
    > def __init__(self):
    > self.__Tags={}
    > def GetTag(self,tna me):
    > return self.__Tags.get (tname,None)
    > def SetTag(self,tna me,value):
    > self.__Tags[tname]=Value
    > Tag=property(Ge tTag,SetTag)
    >
    > a=A()
    > print a.Tag('A')
    > print a.Tag['A']
    >
    > But it is seems to be not possible in this way.[/color]

    Have your get method return an instance of an auxiliary class which
    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.__TagsAcce ssor = None

    def getTagsAccessor (self):
    if not self.__tagsAcce ssor:
    def getter(__, tname):
    return self.__Tags.get (tname, None)
    def setter(__, tname, value):
    self.__Tags[tname] = value
    class TagAccessor: pass
    TagAccessor.__g etitem__ = getter
    TagAccessor.__s etitem__ = setter
    self.__TagsAcce ssor = TagAccessor()
    return self.__TagsAcce ssor
    Tag = property(getTag sAccessor)

    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.


    Alex

    Comment

    • Bengt Richter

      #3
      Re: Property with parameter...

      On Mon, 13 Sep 2004 11:09:07 +0200, aleaxit@yahoo.c om (Alex Martelli) wrote:
      [color=blue]
      >kepes.krisztia n <kepes.krisztia n@peto.hu> wrote:
      >[color=green]
      >> 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):inte ger; Canvas.SetPixel (self,X,Y,Color ::integer);
      >>
      >> class A(object):
      >> def __init__(self):
      >> self.__Tags={}
      >> def GetTag(self,tna me):
      >> return self.__Tags.get (tname,None)
      >> def SetTag(self,tna me,value):
      >> self.__Tags[tname]=Value
      >> Tag=property(Ge tTag,SetTag)
      >>
      >> a=A()
      >> print a.Tag('A')
      >> print a.Tag['A']
      >>
      >> But it is seems to be not possible in this way.[/color]
      >
      >Have your get method return an instance of an auxiliary class which[/color]
      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.
      [color=blue]
      >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.__TagsAcce ssor = None
      >
      > def getTagsAccessor (self):
      > if not self.__tagsAcce ssor:
      > def getter(__, tname):
      > return self.__Tags.get (tname, None)
      > def setter(__, tname, value):
      > self.__Tags[tname] = value
      > class TagAccessor: pass
      > TagAccessor.__g etitem__ = getter
      > TagAccessor.__s etitem__ = setter
      > self.__TagsAcce ssor = TagAccessor()
      > return self.__TagsAcce ssor
      > Tag = property(getTag sAccessor)
      >
      >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
      >possibilitie s, 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.
      >[/color]
      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.,
      [color=blue][color=green][color=darkred]
      >>> class TagClass(object ):[/color][/color][/color]
      ... def __init__(self): self.__Tags = {}
      ... def __getitem__(sel f, k): return self.__Tags.get (k, None) # per OP
      ... def __setitem__(sel f, k, v): self.__Tags[k] = v
      ...[color=blue][color=green][color=darkred]
      >>> class A(object):[/color][/color][/color]
      ... def __init__(self): self.Tag = TagClass()
      ...

      Then[color=blue][color=green][color=darkred]
      >>> a=A()
      >>> a.Tag[2,3] = 'two, three'
      >>> a.Tag[2,3][/color][/color][/color]
      'two, three'[color=blue][color=green][color=darkred]
      >>> a.Tag[/color][/color][/color]
      <__main__.TagCl ass object at 0x00901210>[color=blue][color=green][color=darkred]
      >>> vars(a)[/color][/color][/color]
      {'Tag': <__main__.TagCl ass object at 0x00901210>}[color=blue][color=green][color=darkred]
      >>> vars(a.Tag)[/color][/color][/color]
      {'_TagClass__Ta gs': {(2, 3): 'two, three'}}

      For me, capitalized attributes kind of grate on the convention nerve though ;-)

      Regards,
      Bengt Richter

      Comment

      • Alex Martelli

        #4
        Re: Property with parameter...

        Bengt Richter <bokr@oz.net> wrote:
        ...[color=blue][color=green]
        > >Have your get method return an instance of an auxiliary class which[/color]
        > 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.[/color]

        Yes, if the OP is happy about potentially letting client code trample
        over his precious a.Tag by assigning to it, and further is happy having
        every instance of class A instantiating and holding an instance of a
        Tags class (rather than doing it just-in-time if and when that attribute
        is accessed) -- briefly, if he needs none of the advantages afforded by
        properties -- then he'd be best advised to avoid using properties.

        [color=blue]
        > 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.,
        >[color=green][color=darkred]
        > >>> class TagClass(object ):[/color][/color]
        > ... def __init__(self): self.__Tags = {}
        > ... def __getitem__(sel f, k): return self.__Tags.get (k, None) # per OP
        > ... def __setitem__(sel f, k, v): self.__Tags[k] = v
        > ...[color=green][color=darkred]
        > >>> class A(object):[/color][/color]
        > ... def __init__(self): self.Tag = TagClass()[/color]

        If instances of class A need no other access to the dictionary than that
        afforded to other code by the get/set-item special methods of this class
        TagClass (in addition to not needing any of the potential extras of
        properties), then this factoring (giving the TagClass instance whole
        responsibility for handling the dict) may indeed be optimal. More
        usually, though, the coupling may usefully be closer -- and I mentioned
        some other factorings that would afford that, besides the unusual one I
        showed in detail which used closures to effect the coupling.
        [color=blue]
        > For me, capitalized attributes kind of grate on the convention nerve[/color]
        though ;-)

        It's not a common convention in Python practice, agreed. Not unheard
        of, though -- I do believe it's mentioned in the style PEP, isn't it?


        Alex

        Comment

        Working...