Factory for Struct-like classes

E

eliben

Hello,

I want to be able to do something like this:

Employee = Struct(name, salary)

And then:

john = Employee('john doe', 34000)
print john.salary

Basically, Employee = Struct(name, salary) should be equivalent to:

class Employee(object):
def __init__(self, name, salary):
self.name = name
self.salary = salary

Ruby's 'Scruct' class (http://ruby-doc.org/core/classes/Struct.html)
does this. I suppose it can be done with 'exec', but is there a more
Pythonic way ?

Thanks in advance

P.S. I'm aware of this common "pattern":

class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)

Which allows:

john = Struct(name='john doe', salary=34000)
print john.salary

But what I'm asking for is somewhat more general.
 
M

Michele Simionato

Hello,

I want to be able to do something like this:

Employee = Struct(name, salary)

And then:

john = Employee('john doe', 34000)
print john.salary

Basically, Employee = Struct(name, salary) should be equivalent to:

class Employee(object):
def __init__(self, name, salary):
self.name = name
self.salary = salary

Ruby's 'Scruct' class (http://ruby-doc.org/core/classes/Struct.html)
does this. I suppose it can be done with 'exec', but is there a more
Pythonic way ?

Thanks in advance

P.S. I'm aware of this common "pattern":

class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)

Which allows:

john = Struct(name='john doe', salary=34000)
print john.salary

But what I'm asking for is somewhat more general.


NamedTuples: http://code.activestate.com/recipes/303439/
 
E

eliben

Try named tuplehttp://code.activestate.com/recipes/500261/

A named tuple implementation is part of Python 2.6 and 3.0. For older
versions of Python use the recipe from activestate.

Christian

Thanks Christian - this is exactly what I've been looking for.
Some thoughts...

1) I see this is done with exec anyway, so there's no more pythonic
way.

2) The definition of fields as a single string is weird. Why not use
**kwargs instead ?
 
M

Marc Christiansen

eliben said:
Hello,

I want to be able to do something like this:

Employee = Struct(name, salary)

And then:

john = Employee('john doe', 34000)
print john.salary

Basically, Employee = Struct(name, salary) should be equivalent to:

class Employee(object):
def __init__(self, name, salary):
self.name = name
self.salary = salary

Ruby's 'Scruct' class (http://ruby-doc.org/core/classes/Struct.html)
does this. I suppose it can be done with 'exec', but is there a more
Pythonic way ?

Thanks in advance

I have some old code laying around which should do what you want. It was
originally written by Kragen Sitaker in 2001-10-16 and is public domain.

def defstruct(*fields):
class Struct(object):
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 field, content in zip(self.structfields, contents):
setattr(self, field, content)
Struct.structfields = fields
return Struct

Use:
Employee = defstruct("name", "salary")
john = Employee('john doe', 34000)
print john.salary

Marc
 
M

Matthew Wilson

I find something like this useful, especially if any time I tried to
cram in an attribute that wasn't allowed, the class raises an exception.

One way to do it is to make a function that defines a class inside and
then returns it. See the code at the end of this post for an example.

I couldn't figure out how to do this part though:

I have to do this instead (notice that the args are strings):

Anyway, here's the code:

def struct_maker(*args):

class C(object):
arglist = args
def __init__(self, *different_args):

# Catch too few/too many args.
if len(self.arglist) != len(different_args):
raise ValueError("I need exactly %d args (%s)"
% (len(self.arglist), list(self.arglist)))

for a, b in zip(self.arglist, different_args):
setattr(self, a, b)

def __setattr__(self, k, v):
"Prevent any attributes except the first ones."
if k in self.arglist:
object.__setattr__(self, k, v)
else:
raise ValueError("%s ain't in %s"
% (k, list(self.arglist)))

return C

And here it is in action:

In [97]: Employee = struct_maker('name', 'salary')

In [98]: matt = Employee('Matt Wilson', 11000)

In [99]: matt.name, matt.salary

Out[99]: ('Matt Wilson', 11000)

In [100]: matt.invalid_attribute = 99
 
G

Gabriel Genellina

1) I see this is done with exec anyway, so there's no more pythonic
way.

It doesn't *have* to be done with exec - I think there are other
variants using metaclasses instead.
2) The definition of fields as a single string is weird. Why not use
**kwargs instead ?

Because the field ordering would be lost, which is important for a
named *tuple*.
(Anyway, I'd prefer a list of names instead of a single string...)
 
D

Dan Lenski

Trynamedtuplehttp://code.activestate.com/recipes/500261/

Anamedtupleimplementation is part of Python 2.6 and 3.0. For older
versions of Python use the recipe from activestate.

Christian

This named tuple recipe is pretty cool... I think there may be a
slight bug in the Python docs, though. The ActiveState page explains
that it avoids the overhead of a per-instance __dict__ by using the
__slots__ variable. However, according to the most-recent Python
docs, __slots__ does *NOT* work with subclasses of list, str, or
tuple.

From http://docs.python.org/ref/slots.html#l2h-222:

# __slots__ do not work for classes derived from ``variable-length''
built-in types such as long, str and tuple.

On the other hand, nametuple does appear to work as advertised.
AttributeError: 'Person' object has no attribute '__dict__'

So is there a bug in the Python docs? Does __slots__ in fact work
with subclasses of tuple?

Dan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top