class declaration shortcut

  • Thread starter =?iso-8859-1?q?Luis_M._Gonz=E1lez?=
  • Start date
?

=?iso-8859-1?q?Luis_M._Gonz=E1lez?=

I've come across a code snippet in www.rubyclr.com where they show how
easy it is to declare a class compared to equivalent code in c#.
I wonder if there is any way to emulate this in Python.

The code is as follows:

Person = struct.new( :name, :birthday, :children)

I tried something like this, but it's nothing close to what I'd like:

def klass(table, *args):
cls = new.classobj(table, (), {})
for i in args:
setattr(cls, i, i)
return cls

But this above is not what I want.
I guess I should find a way to include the constructor code inside
this function, but I don't know if this is possible.
Also, I wonder if there is a way to use the variable name in order to
create a class with the same name (as in "Person"above).

Well, if anyone has an idea, I'd like to know...

Luis
 
B

Bruno Desthuilliers

Luis M. González a écrit :
I've come across a code snippet in www.rubyclr.com where they show how
easy it is to declare a class compared to equivalent code in c#.
I wonder if there is any way to emulate this in Python.

The code is as follows:

Person = struct.new( :name, :birthday, :children)
s/struct/Struct/

I tried something like this, but it's nothing close to what I'd like:

def klass(table, *args):
cls = new.classobj(table, (), {})
for i in args:
setattr(cls, i, i)
return cls

But this above is not what I want.
I guess I should find a way to include the constructor code inside
this function, but I don't know if this is possible.
Also, I wonder if there is a way to use the variable name in order to
create a class with the same name (as in "Person"above).

Well, if anyone has an idea, I'd like to know...

Here's a *very* Q&D attempt - that doesn't solve the name problem:
def Struct(name, *attribs):
args = ", ".join("%s=None" % attr for attr in attribs)
body = "\n ".join("self.%s = %s" % (attr, attr) \
for attr in attribs)
source = ("""
class %s(object):
def __init__(self, %s):
%s
""".strip()) % (name, args, body)
#print source
code = compile(source, 'dummy', 'single')
exec code
return locals()[name]

But note that I'd immediatly fire anyone using such an abomination in
production code.
 
S

Steven Bethard

Luis said:
I've come across a code snippet in www.rubyclr.com where they show how
easy it is to declare a class compared to equivalent code in c#.
I wonder if there is any way to emulate this in Python.

The code is as follows:

Person = struct.new( :name, :birthday, :children)

How about something like::

class Person(Record):
__slots__ = 'name', 'birthday', 'children'

You can then use the class like::

person = Person('Steve', 'April 25', [])
assert person.name == 'Steve'
assert person.birthday == 'April 25'
assert not person.children

Is that what you were looking for? If so, the recipe for the Record
class is here:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502237

STeVe
 
?

=?iso-8859-1?q?Luis_M._Gonz=E1lez?=

Luis said:
I've come across a code snippet inwww.rubyclr.comwhere they show how
easy it is to declare a class compared to equivalent code in c#.
I wonder if there is any way to emulate this in Python.
The code is as follows:
Person = struct.new( :name, :birthday, :children)

How about something like::

class Person(Record):
__slots__ = 'name', 'birthday', 'children'

You can then use the class like::

person = Person('Steve', 'April 25', [])
assert person.name == 'Steve'
assert person.birthday == 'April 25'
assert not person.children

Is that what you were looking for? If so, the recipe for the Record
class is here:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502237

STeVe



Hmmm... not really.
The code above is supposed to be a shorter way of writing this:

class Person:
def __init__(self, name, birthday, children):
self.name = name
self.birthday = birthday
self.children = children

So the purpose of this question is finding a way to emulate this with
a single line and minimal typing.

There are a few problems here:
1) How to get the variable name (in this case "Person") become the
name of the class without explicity indicating it.
2) How to enter attribute names not enclosed between quotes. The only
way I can do it is by entering them as string literals.

It's not that I desperately need it, but I'm just curious about it...

Luis
 
S

Steven Bethard

Luis said:
How about something like::

class Person(Record):
__slots__ = 'name', 'birthday', 'children'

You can then use the class like::

person = Person('Steve', 'April 25', [])
assert person.name == 'Steve'
assert person.birthday == 'April 25'
assert not person.children

Is that what you were looking for? If so, the recipe for the Record
class is here:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502237
[snip]
Hmmm... not really.
The code above is supposed to be a shorter way of writing this:

class Person:
def __init__(self, name, birthday, children):
self.name = name
self.birthday = birthday
self.children = children

So the purpose of this question is finding a way to emulate this with
a single line and minimal typing.

That __init__ is exactly what was generated in my example above. So
you're mainly objecting to using two-lines? You can make it a one-liner
by writing::

class Person(Record): __slots__ = 'name', 'birthday', 'children'
1) How to get the variable name (in this case "Person") become the
name of the class without explicity indicating it.

The only things that know about their own names are class statements
(through metaclasses) so you can't really do it without a class
statement of some sort (which means you'll have to use two lines).
2) How to enter attribute names not enclosed between quotes. The only
way I can do it is by entering them as string literals.

If you're really bothered by quotes, a pretty minimal modification to
the recipe could generate the same code from:

class Person(Record): slots = 'name birthday children'

STeVe
 
B

Bjoern Schliessmann

Luis said:
I've come across a code snippet in www.rubyclr.com where they show
how easy it is to declare a class compared to equivalent code in
c#. I wonder if there is any way to emulate this in Python.

The code is as follows:

Person = struct.new( :name, :birthday, :children)

What's easy about this?

Also, this is a definition and not just a declaration.
But this above is not what I want.
I guess I should find a way to include the constructor code inside
this function, but I don't know if this is possible.

Could you please describe what exactly you want in an abstract way?
Also, I wonder if there is a way to use the variable name in order
to create a class with the same name (as in "Person"above).

Two classes with the same name?

In Python, classes have no name. They are anonymous objects which
can be bound to names.

Regards,


Björn
 
B

Bjoern Schliessmann

Bruno said:
class Toto(object):
pass

print Toto.__name__

Okay, I revoke my statement and assert the opposite.

But what's it (__name__) good for?

Regards,


Björn
 
M

Marc 'BlackJack' Rintsch

Okay, I revoke my statement and assert the opposite.

But what's it (__name__) good for?

As objects don't know to which name they are bound, that's a good way to
give some information in stack traces or when doing introspection.

Ciao,
Marc 'BlackJack' Rintsch
 
M

Michele Simionato

As objects don't know to which name they are bound, that's a good way to
give some information in stack traces or when doing introspection.

Also, the name is used by pickle to find the class of pickled
instances.

Michele Simionato
 
B

Bjoern Schliessmann

Michele said:
Also, the name is used by pickle to find the class of pickled
instances.

Mh. I suspect there's also more to it than I see now, but this
__name__ seems quite useless to me. What if I rebind the class'
name after definition? Or is it really just for some manual
introspection? If it is, it seems a bit of an overkill to me.
.... pass
....
Regards,


Björn
 
M

Marc 'BlackJack' Rintsch

Mh. I suspect there's also more to it than I see now, but this
__name__ seems quite useless to me. What if I rebind the class'
name after definition?

Then it's a way to still get the name of the definition via `__name__`.
Together with the name of the module where the definition took place which
is also available as attribute on the objects it is very useful to find
out where to look for the source code. Just see the default `repr()` of
class objects.
Or is it really just for some manual introspection? If it is, it seems a
bit of an overkill to me.

... pass
...
<class '__main__.Spam'>

What would you expect this to look like if there weren't a __name__
attribute?

Ciao,
Marc 'BlackJack' Rintsch
 
?

=?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=

Hmmm... not really.
The code above is supposed to be a shorter way of writing this:

class Person:
def __init__(self, name, birthday, children):
self.name = name
self.birthday = birthday
self.children = children

So the purpose of this question is finding a way to emulate this with
a single line and minimal typing.

I believe this is what you are looking for:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/361668

olle = attrdict(name = "Olle", birthday = date(2222, 12, 1), children = 329)
print olle.name, olle.birthday, olle.children

It is not identical to the Ruby recipe, but is IMHO better. Being able
to instantiate objects on the fly, without having to explicitly
declare the class, is a big advantage.
 
A

Arnaud Delobelle

I've come across a code snippet inwww.rubyclr.comwhere they show how
easy it is to declare a class compared to equivalent code in c#.
I wonder if there is any way to emulate this in Python.

The code is as follows:

Person = struct.new( :name, :birthday, :children)

I tried something like this, but it's nothing close to what I'd like:

def klass(table, *args):
cls = new.classobj(table, (), {})
for i in args:
setattr(cls, i, i)
return cls

But this above is not what I want.
I guess I should find a way to include the constructor code inside
this function, but I don't know if this is possible.
Also, I wonder if there is a way to use the variable name in order to
create a class with the same name (as in "Person"above).

Well, if anyone has an idea, I'd like to know...

Luis

Perhaps something like:

class Struct(object):
def __init__(self, **vals):
for slot, val in vals.iteritems():
setattr(self, slot, val)
def __repr__(self):
return "%s(%s)" % (type(self).__name__,
", ".join("%s=%s" % (slot, repr(getattr(self, slot))) for
slot in self.__slots__ if hasattr(self, slot)))

def new_struct(name, *slots):
return type(name, (Struct,), {'__slots__': slots})


Then you can do:

etc...

Of course that's if you want a c-like struct. Otherwise there's not
much point at all!
 
S

Steven Bethard

Arnaud said:
Perhaps something like:

class Struct(object):
def __init__(self, **vals):
for slot, val in vals.iteritems():
setattr(self, slot, val)
def __repr__(self):
return "%s(%s)" % (type(self).__name__,
", ".join("%s=%s" % (slot, repr(getattr(self, slot))) for
slot in self.__slots__ if hasattr(self, slot)))

def new_struct(name, *slots):
return type(name, (Struct,), {'__slots__': slots})


Then you can do:

Person(name='Jack', tel='555-132')

This does pretty much the same thing as the recipe I posted:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502237

Note that your approach requires repetition of the 'Person' and quotes
around each attribute name, which the OP complained about. The recipe at
least gets rid of the repetition of 'Person'.

You might also want to check out Raymond Hettinger's NamedTuple recipe:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/500261

STeVe
 
A

Arnaud Delobelle

Arnaud Delobelle wrote: [...]
This does pretty much the same thing as the recipe I posted:

Not at all. My new_struct create returns a new class which is similar
to a C struct (notice the __slots__). The recipe you refer to is
nothing more a class which can be initialised with some attributes. It
does not address the OP's question at all.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502237

Note that your approach requires repetition of the 'Person' and quotes
around each attribute name, which the OP complained about. The recipe at
least gets rid of the repetition of 'Person'.

The 'name' argument is not necessary. It is just here to give a user-
friendly name to the newly created class.
One could just as well write the new_struct function so that

Of course it would be impossible for the function written as above to
name the class in a user-meaningful way. The recipe you refer to does
not face this problem because it is not a method to quickly create a
new class, it is merely a class whose __init__ method allows you to
initialise some attribute at instance-creation time.

As for the quotes around the attribute names, well... Let's say that
if it was possible to do without, I don't think I would be using
python...
 
S

Steven Bethard

Arnaud said:
Arnaud Delobelle wrote: [...]
This does pretty much the same thing as the recipe I posted:

Not at all. My new_struct create returns a new class which is similar
to a C struct (notice the __slots__). The recipe you refer to is
nothing more a class which can be initialised with some attributes. It
does not address the OP's question at all.

Huh? It uses __slots__ in almost exactly the same way. If you just
s/Struct/Record in your ``new_struct`` function, you'll get essentially
the same behavior, except that if you use the recipe, you'll get an
__init__ that handles positional arguments, and displays better help::
... return type(name, (Struct,), {'__slots__': slots})
... Traceback (most recent call last):
Help on method __init__ in module __main__:

__init__(self, **vals) unbound __main__.Person method
... return type(name, (Record,), {'__slots__': slots})
... Help on method __init__:

__init__(self, name) unbound records.Person method


Maybe I'm not understanding you?

Steve
 
A

Arnaud Delobelle

Arnaud said:
Arnaud Delobelle wrote: [...]
This does pretty much the same thing as the recipe I posted:
Not at all. My new_struct create returns a new class which is similar
to a C struct (notice the __slots__). The recipe you refer to is
nothing more a class which can be initialised with some attributes. It
does not address the OP's question at all.

Huh? It uses __slots__ in almost exactly the same way.

I'm sorry I somehow got my hyperlinks mixed up and though you were
refering to

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/361668

which was mentioned by someone else on this thread. If I had seen
yours I wouldn't have posted this. So my comment on you link was
completely erroneous as, as you are pointing out, the functionality of
my code snippet and your link are very similar. Mine was only a proof
of concept bit of code, so yours is more polished.

Although I don't see the necessity of a metaclass: you could have

class Record(object):
def __init__(self, *vals):
for slot, val in zip(self.__slots__, vals):
setattr(self, slot, val)
# And the other methods

if you want positional slots initialisation. I chose keyword
arguments in mine because I though it would be a good idea to be able
not to initialise some of them at object instanciation.
 
S

Steven Bethard

Arnaud said:
[snip]
Although I don't see the necessity of a metaclass: you could have

class Record(object):
def __init__(self, *vals):
for slot, val in zip(self.__slots__, vals):
setattr(self, slot, val)
# And the other methods

if you want positional slots initialisation. I chose keyword
arguments in mine

You could certainly do it that way, but note that the one with the
metaclass not only allows *either* positional or keyword arguments, but
also displays better help messages -- using the *vals or **vals code,
help() will tell you something like:

__init__(self, **vals)

while using the metaclass-generated __init__, help() will tell you the
more informative:

__init__(self, name)

(Or whatever signature is appropriate given the __slots__.) So no, it's
not necessary, but it does have a few advantages.

STeVe
 
?

=?iso-8859-1?q?Luis_M._Gonz=E1lez?=

Arnaud Delobelle wrote: [...]
This does pretty much the same thing as the recipe I posted:

Not at all. My new_struct create returns a new class which is similar
to a C struct (notice the __slots__). The recipe you refer to is
nothing more a class which can be initialised with some attributes. It
does not address the OP's question at all.
Note that your approach requires repetition of the 'Person' and quotes
around each attribute name, which the OP complained about. The recipe at
least gets rid of the repetition of 'Person'.

The 'name' argument is not necessary. It is just here to give a user-
friendly name to the newly created class.
One could just as well write the new_struct function so that

Of course it would be impossible for the function written as above to
name the class in a user-meaningful way. The recipe you refer to does
not face this problem because it is not a method to quickly create a
new class, it is merely a class whose __init__ method allows you to
initialise some attribute at instance-creation time.

As for the quotes around the attribute names, well... Let's say that
if it was possible to do without, I don't think I would be using
python...



This is the closest we got so far to the intended result.
If there was a way to enter attributes without quotes, it would be
almost identical.
Anyway, I wonder if the code comparison in www.rubuclr.com between the
c# and ruby code is fair...
As far as I know, classes and structs are not the same thing.
In the case of that ruby example, can someone add methods later?

Luis
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top