Idea about method parameters
Kragen Sitaker
kragen at dnaco.net
Tue Oct 16 21:00:00 EDT 2001
In article <1634093.6GMIcojqen at lunix.schabi.de>,
Markus Schaber <markus at schabi.de> wrote:
>Well - compare the following example just reconstructed from
>a class I use in a small database, building a chained list:
>
>class Tankung:
> def __init__(Liter, # the amount of fuel
> Datum, # the date
> Preis, # the price
> Tachostand, # the kilometer count
> Waehrung = "DM", # DM or Euro?
> Tankstelle, # where was it bought
> Bemerkung= "", # any remarks?
> prev = None) # the previous one, omit for first in chain
>
> self.Liter = Liter # set the amount of fuel
> self.Datum = Datum # set the date
> self.Preis = Preis # set the price
> self.Waehrung = Waehrung # set the currency
> self.Tankstelle = Tankstelle # set the fuel station
> self.Bemerkung = Bemerkung # set the remarks
>
> self.Tachostand = int(Tachostand) # ensure the kilometer count is
> # an integer
>
> self.prev = prev # set the previous one
> try: # build the chained list
> self.prev.next = self
> except TypeError:
> pass #prev was None or alike
>
>and in the proposed syntax:
>
>class Tankung:
> def __init__(self.Liter, # set the fuel
> self.Datum, # set the date
> self.Preis, # set the price
> Tachostand, # the kilometer count
> self.Waehrung = "DM", # DM or Euro?
> self.Tankstelle, # where was it bought
> self.Bemerkung= "", # any remarks?
> self.prev = None) # the previous one, omit for first in
> # chain
>
> self.Tachostand = int(Tachostand) # ensure the kilometer count is
> # an integer
> try: # build the chained list
> self.prev.next = self
> except TypeError:
> pass #prev was None or alike
>
>I just rebuilt it from brain because the source is on another machine,
>and put the Comments in English instead of German so there might be
>typos :-)
>
>In my eyes, the second example is more clear and elegant.
I agree; you're already asking for trouble by duplicating the long list
of attribute list and in the actual parameters where Tankungen are
created, but if you create Tankungen in a lot of places, the
readability might be worth it.
Coincidentally, I wrote something this morning that might make your
life easier, and posted it under the subject 'defstruct.py'.
# I occasionally find myself writing code like the following:
# class Point:
# def __init__(self, x, y):
# self.x = x
# self.y = y
# and that's the whole class. This little module lets me write the above code
# as
# Point = defstruct('x', 'y')
# and have done with it.
#
# The name is taken from Common Lisp; the syntax is taken from MzScheme's
# define-struct and is similar to the Common Lisp boa constructor syntax.
# define-record-type from SRFI 9 is nasty and Scheme-specific enough that
# I didn't use it.
#
# I hereby dedicate this code to the public domain and disavow any copyright
# interest in it.
#
# -- Kragen Sitaker, 2001-10-16
def defstruct(*fields):
class Struct:
def __init__(self, *contents):
if len(contents) != len(self.structfields):
raise TypeError, (
"wrong number of arguments: expected %d %s, got %d" %
(len(self.structfields),
repr(self.structfields),
len(contents)))
for fieldnum in range(len(contents)):
setattr(self, self.structfields[fieldnum], contents[fieldnum])
Struct.structfields = fields
return Struct
def test():
point = defstruct('x', 'y')
p1 = point(1, 2)
assert p1.x == 1
assert p1.y == 2
complex = defstruct('real', 'imag')
assert point is not complex
assert isinstance(p1, point)
assert not isinstance(p1, complex)
test()
With this, your code above would become something like:
Now, as it sits, it doesn't support default or named parameters; but
those wouldn't be hard to add. Your example becomes:
from defstruct import defstruct
Tankung = defstruct('Liter', 'Datum', 'Preis', 'Tachostand', 'Waehrung',
'Tankstelle', 'Bemerkung')
class Listnode:
def __init__(self, data, prev=None):
self.tank = apply(Tankung, data)
self.prev = prev
if self.prev is not None:
self.prev.next = self
Me, I'd probably dispense with the Listnode and just make Python lists
of Tankungen, but I assume you tried that first and it wasn't good
enough.
I think I could add parameters with defaults as follows:
Tankung = defstruct('Liter', 'Datum', 'Preis', 'Tachostand',
{'Waehrung': "DM"}, {'Tankstelle': "nowhere"},
{'Bemerkung': ""})
That's not as pretty as Waehrung="DM", Tankstelle="nowhere",
Bemerkung="", but that's the price we pay for having a non-extensible
language syntax. (If we ask for all the keyword arguments inside
defstruct, we get them, in a dict. Shuffled into an arbitrary order.
Oops.)
And I think I could just throw any and all named parameters (whether or
not mentioned in the original struct definition) into the object.
None of the above requires any changes to the language.
--
<kragen at pobox.com> Kragen Sitaker <http://www.pobox.com/~kragen/>
Perilous to all of us are the devices of an art deeper than we possess
ourselves.
-- Gandalf the White [J.R.R. Tolkien, "The Two Towers", Bk 3, Ch. XI]
More information about the Python-list
mailing list