Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #49253 > unrolled thread
| Started by | Tim <jtim.arnold@gmail.com> |
|---|---|
| First post | 2013-06-26 06:09 -0700 |
| Last post | 2013-06-27 09:40 -0700 |
| Articles | 14 — 6 participants |
Back to article view | Back to comp.lang.python
class factory question Tim <jtim.arnold@gmail.com> - 2013-06-26 06:09 -0700
Re: class factory question Peter Otten <__peter__@web.de> - 2013-06-26 15:39 +0200
Re: class factory question Tim <jtim.arnold@gmail.com> - 2013-06-26 07:08 -0700
Re: class factory question Peter Otten <__peter__@web.de> - 2013-06-26 16:46 +0200
Re: class factory question Tim <jtim.arnold@gmail.com> - 2013-06-26 08:05 -0700
Re: class factory question Joshua Landau <joshua.landau.ws@gmail.com> - 2013-06-26 16:17 +0100
Re: class factory question Peter Otten <__peter__@web.de> - 2013-06-26 17:40 +0200
Re: class factory question Joshua Landau <joshua.landau.ws@gmail.com> - 2013-06-27 00:20 +0100
Re: class factory question Fábio Santos <fabiosantosart@gmail.com> - 2013-06-27 00:35 +0100
Re: class factory question Joshua Landau <joshua.landau.ws@gmail.com> - 2013-06-27 14:16 +0100
Re: class factory question Tim <jtim.arnold@gmail.com> - 2013-06-27 06:37 -0700
Re: class factory question Dave Angel <davea@davea.name> - 2013-06-27 09:48 -0400
Re: class factory question Irmen de Jong <irmen.NOSPAM@xs4all.nl> - 2013-06-27 17:56 +0200
Re: class factory question Tim <jtim.arnold@gmail.com> - 2013-06-27 09:40 -0700
| From | Tim <jtim.arnold@gmail.com> |
|---|---|
| Date | 2013-06-26 06:09 -0700 |
| Subject | class factory question |
| Message-ID | <138ce5a8-1b4c-49d4-8005-d5f4642dcb97@googlegroups.com> |
I am extending a parser and need to create many classes that are all subclassed from the same object (defined in an external library). When my module is loaded I need all the classes to be created with a particular name but the behavior is all the same. Currently I have a bunch of lines like this:
class Vspace(Base.Command): pass
class Boldpath(Base.Command): pass
There are a bunch of lines like that.
Is there a better way? Something like
newclasses = ['Vspace', 'Boldpath', ... ]
for name in newclasses:
tmp = type(name, (Base.Command,) {})
tmp.__name__ = name
Is there a more pythonic way?
thanks,
--Tim
[toc] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-06-26 15:39 +0200 |
| Message-ID | <mailman.3890.1372253972.3114.python-list@python.org> |
| In reply to | #49253 |
Tim wrote:
> I am extending a parser and need to create many classes that are all
> subclassed from the same object (defined in an external library). When my
> module is loaded I need all the classes to be created with a particular
> name but the behavior is all the same. Currently I have a bunch of lines
> like this:
>
> class Vspace(Base.Command): pass
> class Boldpath(Base.Command): pass
>
> There are a bunch of lines like that.
> Is there a better way? Something like
>
> newclasses = ['Vspace', 'Boldpath', ... ]
> for name in newclasses:
> tmp = type(name, (Base.Command,) {})
> tmp.__name__ = name
>
> Is there a more pythonic way?
What is your objection against that approach?
By the way, I don't think you need
> tmp.__name__ = name
[toc] | [prev] | [next] | [standalone]
| From | Tim <jtim.arnold@gmail.com> |
|---|---|
| Date | 2013-06-26 07:08 -0700 |
| Message-ID | <5d6aa501-58f6-4d8f-8bf5-53d95ff9264e@googlegroups.com> |
| In reply to | #49256 |
On Wednesday, June 26, 2013 9:39:12 AM UTC-4, Peter Otten wrote:
> Tim wrote:
> > I am extending a parser and need to create many classes that are all
> > subclassed from the same object (defined in an external library). When my
> > module is loaded I need all the classes to be created with a particular
> > name but the behavior is all the same. Currently I have a bunch of lines
> > like this:
> >
> > class Vspace(Base.Command): pass
> > class Boldpath(Base.Command): pass
> >
> > There are a bunch of lines like that.
> > Is there a better way? Something like
> >
> > newclasses = ['Vspace', 'Boldpath', ... ]
> > for name in newclasses:
> > tmp = type(name, (Base.Command,) {})
> > tmp.__name__ = name
> >
> > Is there a more pythonic way?
>
> What is your objection against that approach?
> By the way, I don't think you need
> > tmp.__name__ = name
I am not completely understanding the type function I guess. Here is an example from the interpreter:
In [1]: class MyClass(object):
...: pass
...:
In [2]: type('Vspace', (MyClass,), {})
Out[2]: __main__.Vspace
In [3]: x = Vspace()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
C:\Python27\Scripts\<ipython-input-3-a82f21420bf3> in <module>()
----> 1 x = Vspace()
NameError: name 'Vspace' is not defined
In [4]: Vspace = type('Vspace', (MyClass,), {})
In [5]: x = Vspace()
In [6]: type(x)
Out[6]: __main__.Vspace
I don't understand how to make `Vspace` usable for creating instances later (line 3) when I just call `type`; that is why I thought adding the `__name__` attribute would work. Hmm, now I know that doesn't work either:
In [8]: del Vspace
In [9]: m = type('Vspace', (MyClass,), {})
In [10]: m.__name__ = 'Vspace'
In [11]: x = Vspace()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
C:\Python27\Scripts\<ipython-input-11-a82f21420bf3> in <module>()
----> 1 x = Vspace()
NameError: name 'Vspace' is not defined
In [11]: m
Out[12]: __main__.Vspace
Maybe this is too much trouble just to save a few lines (~50) of code.
thanks,
--Tim
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-06-26 16:46 +0200 |
| Message-ID | <mailman.3892.1372258032.3114.python-list@python.org> |
| In reply to | #49258 |
Tim wrote:
> I am not completely understanding the type function I guess. Here is an
> example from the interpreter:
>
> In [1]: class MyClass(object):
> ...: pass
> ...:
> In [2]: type('Vspace', (MyClass,), {})
> Out[2]: __main__.Vspace
> In [3]: x = Vspace()
>
---------------------------------------------------------------------------
> NameError Traceback (most recent call
> last) C:\Python27\Scripts\<ipython-input-3-a82f21420bf3> in <module>()
> ----> 1 x = Vspace()
>
> NameError: name 'Vspace' is not defined
No, you are not understanding how Python namespaces work ;)
To get a Vspace in the global namespace you'd have to bind that name
Vspace = type(...)
which defeats your plan of mass creation of such names. The clean way to
cope with the situation is to use a dict:
classnames = ["Vspace", ...]
classes = {name: type(name, ...) for name in classnames}
Then you can access the Vspace class with
classes["Vspace"]
If that is inconvenient for your usecase you can alternatively update the
global (module) namespace:
globals().update((name, type(name, ...) for name in classnames)
For example:
>>> class A(object): pass
...
>>> globals().update((n, type(n, (A,), {})) for n in ["Beta", "Gamma"])
>>> Beta
<class '__main__.Beta'>
>>> issubclass(Beta, A)
True
[toc] | [prev] | [next] | [standalone]
| From | Tim <jtim.arnold@gmail.com> |
|---|---|
| Date | 2013-06-26 08:05 -0700 |
| Message-ID | <097e7b8e-d075-4145-986e-19d07cf007e0@googlegroups.com> |
| In reply to | #49261 |
On Wednesday, June 26, 2013 10:46:55 AM UTC-4, Peter Otten wrote:
> Tim wrote:
> > I am not completely understanding the type function I guess. Here is an
> > example from the interpreter:
>
> No, you are not understanding how Python namespaces work ;)
> To get a Vspace in the global namespace you'd have to bind that name
> Vspace = type(...)
>
> which defeats your plan of mass creation of such names. The clean way to
> cope with the situation is to use a dict:
>
> classnames = ["Vspace", ...]
> classes = {name: type(name, ...) for name in classnames}
>
> Then you can access the Vspace class with
> classes["Vspace"]
>
> If that is inconvenient for your usecase you can alternatively update the
> global (module) namespace:
> globals().update((name, type(name, ...) for name in classnames)
>
> For example:
> >>> class A(object): pass
> ...
> >>> globals().update((n, type(n, (A,), {})) for n in ["Beta", "Gamma"])
> >>> Beta
> <class '__main__.Beta'>
> >>> issubclass(Beta, A)
> True
Thank you for that great explanation. That is exactly what I needed to know!
What a fantastic group this is.
--Tim
[toc] | [prev] | [next] | [standalone]
| From | Joshua Landau <joshua.landau.ws@gmail.com> |
|---|---|
| Date | 2013-06-26 16:17 +0100 |
| Message-ID | <mailman.3893.1372259876.3114.python-list@python.org> |
| In reply to | #49258 |
On 26 June 2013 15:46, Peter Otten <__peter__@web.de> wrote:
> The clean way to
> cope with the situation is to use a dict:
>
> classnames = ["Vspace", ...]
> classes = {name: type(name, ...) for name in classnames}
>
> Then you can access the Vspace class with
>
> classes["Vspace"]
>
> If that is inconvenient for your usecase you can alternatively update the
> global (module) namespace:
>
> globals().update((name, type(name, ...) for name in classnames)
>
> For example:
>
>>>> class A(object): pass
> ...
>>>> globals().update((n, type(n, (A,), {})) for n in ["Beta", "Gamma"])
>>>> Beta
> <class '__main__.Beta'>
>>>> issubclass(Beta, A)
> True
I would say if a dict isn't good, there are still some cases where you
might not want to use globals.
I _might_ do:
import sys
from types import ModuleType
# As before
newclasses = ['Vspace', 'Boldpath', "and so on", "and yes, these all
become variables"]
little_classes = {name: type(name, (int,), {}) for name in newclasses}
# Make a module
module_for_little_classes = ModuleType("module_for_little_classes",
"All the things")
module_for_little_classes.__dict__.update(little_classes)
# Hack it in there!
sys.modules["module_for_little_classes"] = module_for_little_classes
# Now we can undo all
import module_for_little_classes as mlc
mlc.Vspace
mlc.Boldpath
...
# And undo all our hard work avoiding globals():
from module_for_little_classes import *
Vspace
Boldpath
So, why avoid globals()?
1) Linters don't like globals()
2) Urm... it's ugly?
3) Ur.......
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-06-26 17:40 +0200 |
| Message-ID | <mailman.3896.1372261260.3114.python-list@python.org> |
| In reply to | #49258 |
Joshua Landau wrote:
> I would say if a dict isn't good, there are still some cases where you
> might not want to use globals.
>
> I _might_ do:
> # Make a module
> module_for_little_classes = ModuleType("module_for_little_classes",
> "All the things")
> module_for_little_classes.__dict__.update(little_classes)
Hm, from within module_for_little_classes that is globals(). To illustrate:
>>> import __main__ as main
>>> globals() is main.__dict__
True
Also, I'd spell module.__dict__ vars(module).
That said I agree that it's a good idea to use a dedicated module (not
necessarily created on the fly) for those dynamically generated classes.
[toc] | [prev] | [next] | [standalone]
| From | Joshua Landau <joshua.landau.ws@gmail.com> |
|---|---|
| Date | 2013-06-27 00:20 +0100 |
| Message-ID | <mailman.3907.1372288868.3114.python-list@python.org> |
| In reply to | #49258 |
On 26 June 2013 16:40, Peter Otten <__peter__@web.de> wrote:
> Joshua Landau wrote:
>
>> I would say if a dict isn't good, there are still some cases where you
>> might not want to use globals.
>>
>> I _might_ do:
>
>> # Make a module
>> module_for_little_classes = ModuleType("module_for_little_classes",
>> "All the things")
>> module_for_little_classes.__dict__.update(little_classes)
>
> Hm, from within module_for_little_classes that is globals(). To illustrate:
>
>>>> import __main__ as main
>>>> globals() is main.__dict__
> True
Yes, that's true - but the point wasn't not to use "globals the
function", but not to use *this* global scope.
> Also, I'd spell module.__dict__ vars(module).
Again, good catch. Definitely that.
> That said I agree that it's a good idea to use a dedicated module (not
> necessarily created on the fly) for those dynamically generated classes.
[toc] | [prev] | [next] | [standalone]
| From | Fábio Santos <fabiosantosart@gmail.com> |
|---|---|
| Date | 2013-06-27 00:35 +0100 |
| Message-ID | <mailman.3909.1372290126.3114.python-list@python.org> |
| In reply to | #49253 |
[Multipart message — attachments visible in raw view] — view raw
On 26 Jun 2013 14:14, "Tim" <jtim.arnold@gmail.com> wrote:
>
> I am extending a parser and need to create many classes that are all
subclassed from the same object (defined in an external library). When my
module is loaded I need all the classes to be created with a particular
name but the behavior is all the same. Currently I have a bunch of lines
like this:
>
> class Vspace(Base.Command): pass
> class Boldpath(Base.Command): pass
>
> There are a bunch of lines like that.
> Is there a better way? Something like
>
> newclasses = ['Vspace', 'Boldpath', ... ]
> for name in newclasses:
> tmp = type(name, (Base.Command,) {})
> tmp.__name__ = name
>
> Is there a more pythonic way?
> thanks,
> --Tim
>
I would say The Most Pythonic Way is to use the class declarations as you
are doing now. Explicit is better than implicit, or so the zen says.
It will be better for tools as well. I'd like to see code completion work
on dynamically created classes like that (unless you use __all__ to list
them.).
And, are you really looking for classes here? If you just want to create
different names with different identities, you could consider using plain
old strings or object() to do that.
[toc] | [prev] | [next] | [standalone]
| From | Joshua Landau <joshua.landau.ws@gmail.com> |
|---|---|
| Date | 2013-06-27 14:16 +0100 |
| Message-ID | <mailman.3928.1372339429.3114.python-list@python.org> |
| In reply to | #49253 |
On 26 June 2013 14:09, Tim <jtim.arnold@gmail.com> wrote:
> I am extending a parser and need to create many classes that are all subclassed from the same object (defined in an external library). When my module is loaded I need all the classes to be created with a particular name but the behavior is all the same. Currently I have a bunch of lines like this:
>
> class Vspace(Base.Command): pass
> class Boldpath(Base.Command): pass
>
> There are a bunch of lines like that.
> Is there a better way? Something like
>
> newclasses = ['Vspace', 'Boldpath', ... ]
> for name in newclasses:
> tmp = type(name, (Base.Command,) {})
> tmp.__name__ = name
>
> Is there a more pythonic way?
I've just realised -- why on earth are you doing this? Surely there's
a better way than having 50 identical classes. :/
[toc] | [prev] | [next] | [standalone]
| From | Tim <jtim.arnold@gmail.com> |
|---|---|
| Date | 2013-06-27 06:37 -0700 |
| Message-ID | <63f9338f-5809-4101-8d11-d0f8266f5818@googlegroups.com> |
| In reply to | #49321 |
On Thursday, June 27, 2013 9:16:50 AM UTC-4, Joshua Landau wrote:
> On 26 June 2013 14:09, Tim wrote:
>
> > I am extending a parser and need to create many classes that are all subclassed from the same object (defined in an external library). When my module is loaded I need all the classes to be created with a particular name but the behavior is all the same. Currently I have a bunch of lines like this:
> >
> > class Vspace(Base.Command): pass
> > class Boldpath(Base.Command): pass
> >
> > There are a bunch of lines like that.
> > Is there a better way? Something like
> > newclasses = ['Vspace', 'Boldpath', ... ]
> > for name in newclasses:
> > tmp = type(name, (Base.Command,) {})
> > tmp.__name__ = name
> >
> > Is there a more pythonic way?
>
> I've just realised -- why on earth are you doing this? Surely there's
> a better way than having 50 identical classes. :/
The reason is that I'm using a parser that creates a DOM from a LaTeX file. The plasTeX package (http://plastex.sourceforge.net/) provides the library to accomplish that. The parser needs to know how to consume some custom-defined tokens (like \Vspace, \Boldpath, etc). The behavior for these is all the same so they're subclassed from one base class, but they need to have these particular names so the parser knows how to consume them when encountered in the source file. That is, for every custom command the parser encounters, it looks for a class of that name in order to tokenize it.
I agree that this is an abnormal circumstance and normally I would just subclass in the normal way. But I think this situation is different enough that it is okay to break a convention.
thanks for thinking about this.
--Tim
[toc] | [prev] | [next] | [standalone]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2013-06-27 09:48 -0400 |
| Message-ID | <mailman.3929.1372340928.3114.python-list@python.org> |
| In reply to | #49323 |
On 06/27/2013 09:37 AM, Tim wrote:
> On Thursday, June 27, 2013 9:16:50 AM UTC-4, Joshua Landau wrote:
>> On 26 June 2013 14:09, Tim wrote:
>>
>>> I am extending a parser and need to create many classes that are all subclassed from the same object (defined in an external library). When my module is loaded I need all the classes to be created with a particular name but the behavior is all the same. Currently I have a bunch of lines like this:
>>>
>>> class Vspace(Base.Command): pass
>>> class Boldpath(Base.Command): pass
>>>
>>> There are a bunch of lines like that.
>>> Is there a better way? Something like
>>> newclasses = ['Vspace', 'Boldpath', ... ]
>>> for name in newclasses:
>>> tmp = type(name, (Base.Command,) {})
>>> tmp.__name__ = name
>>>
>>> Is there a more pythonic way?
>>
>> I've just realised -- why on earth are you doing this? Surely there's
>> a better way than having 50 identical classes. :/
>
> The reason is that I'm using a parser that creates a DOM from a LaTeX file. The plasTeX package (http://plastex.sourceforge.net/) provides the library to accomplish that. The parser needs to know how to consume some custom-defined tokens (like \Vspace, \Boldpath, etc). The behavior for these is all the same so they're subclassed from one base class, but they need to have these particular names so the parser knows how to consume them when encountered in the source file. That is, for every custom command the parser encounters, it looks for a class of that name in order to tokenize it.
>
> I agree that this is an abnormal circumstance and normally I would just subclass in the normal way. But I think this situation is different enough that it is okay to break a convention.
>
> thanks for thinking about this.
> --Tim
>
I don't think you broke the convention, that parser did.
--
DaveA
[toc] | [prev] | [next] | [standalone]
| From | Irmen de Jong <irmen.NOSPAM@xs4all.nl> |
|---|---|
| Date | 2013-06-27 17:56 +0200 |
| Message-ID | <51cc60a9$0$15863$e4fe514c@news.xs4all.nl> |
| In reply to | #49325 |
On 27-6-2013 15:48, Dave Angel wrote:
>> The behavior for these is all the same so they're subclassed
>> from one base class, but they need to have these particular names so the parser knows
>> how to consume them when encountered in the source file. That is, for every custom
>> command the parser encounters, it looks for a class of that name in order to tokenize it.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How does it look for a class?
Can you perhaps override the way it looks for a class of that name?
So that you can instead return something sensible rather than having to define one of 50
almost identical classes...
Irmen
[toc] | [prev] | [next] | [standalone]
| From | Tim <jtim.arnold@gmail.com> |
|---|---|
| Date | 2013-06-27 09:40 -0700 |
| Message-ID | <33f10362-b943-4a70-85e9-53358009412a@googlegroups.com> |
| In reply to | #49333 |
On Thursday, June 27, 2013 11:56:24 AM UTC-4, Irmen de Jong wrote: > On 27-6-2013 15:48, Dave Angel wrote: > >> The behavior for these is all the same so they're subclassed > >> from one base class, but they need to have these particular names so the parser knows > >> how to consume them when encountered in the source file. That is, for every custom > >> command the parser encounters, it looks for a class of that name in order to tokenize it. > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > How does it look for a class? > Can you perhaps override the way it looks for a class of that name? > So that you can instead return something sensible rather than having to define one of 50 > almost identical classes... > Irmen hmm, the package author describes inheriting like I was doing in the first place. With a parser, I really don't know any better way but then I'm not a parsing expert. I will delve into the code and try to get a better handle on how the parser finds the definitions it needs in order to tokenize the input. thanks! --Tim
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web