Idea: Named code blocks / inline module declarations
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block. For example, block signin: def handle_new_user(): do_it() def handle_existing_user(): do_it() while True: try: signin.handle_existing_user(): except: signin.handle_new_user() do_other_stuff() At the moment, I would have to either break out into more files, or somewhat clumsily co-opt things like functions or staticmethods. I think that supporting named blocks or inline module declarations would really help me organise some of my code much better. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace. I hope this makes sense and that I'm not overlooking anything obvious. Cheers, -Tennessee
This may be a misuse of classes, but why can't you make a class and then not instantiate it? class signin: def handle(): return "this works" signin.handle() # returns "this works" On Tue, Sep 16, 2014 at 10:19 PM, Tennessee Leeuwenburg < tleeuwenburg@gmail.com> wrote:
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block.
For example,
block signin: def handle_new_user(): do_it()
def handle_existing_user(): do_it()
while True: try: signin.handle_existing_user(): except: signin.handle_new_user()
do_other_stuff()
At the moment, I would have to either break out into more files, or somewhat clumsily co-opt things like functions or staticmethods. I think that supporting named blocks or inline module declarations would really help me organise some of my code much better. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace.
I hope this makes sense and that I'm not overlooking anything obvious.
Cheers, -Tennessee
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ali Alkhatib Department of Computer Science PhD Student - Stanford University
Hi Ali, Thanks for the suggestion. I would prefer to avoid that just because it's a potential misuse of classes, and I suspect may lead to confusion for other developers. Otherwise that's exactly what I want to do. Cheers, -T On 17 September 2014 15:27, Ali Alkhatib <al2@stanford.edu> wrote:
This may be a misuse of classes, but why can't you make a class and then not instantiate it?
class signin: def handle(): return "this works"
signin.handle() # returns "this works"
On Tue, Sep 16, 2014 at 10:19 PM, Tennessee Leeuwenburg < tleeuwenburg@gmail.com> wrote:
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block.
For example,
block signin: def handle_new_user(): do_it()
def handle_existing_user(): do_it()
while True: try: signin.handle_existing_user(): except: signin.handle_new_user()
do_other_stuff()
At the moment, I would have to either break out into more files, or somewhat clumsily co-opt things like functions or staticmethods. I think that supporting named blocks or inline module declarations would really help me organise some of my code much better. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace.
I hope this makes sense and that I'm not overlooking anything obvious.
Cheers, -Tennessee
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ali Alkhatib Department of Computer Science PhD Student - Stanford University
-- -------------------------------------------------- Tennessee Leeuwenburg http://myownhat.blogspot.com/ "Don't believe everything you think"
Why is this a misuse? Classes are largely just namespaces to start with, and if you want to use them solely for that purpose, it's all there for you. If you wanted to make you intention even more obviously, you could do something like:
class NoInstance(object): ... def __new__(cls): ... raise NotImplementedError ... class signin(NoInstance): ... def handle(*args): ... print("Hello", args) ... signin() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __new__ NotImplementedError signin.handle('some','args','here') Hello ('some', 'args', 'here')
Maybe some other name than NoInstance would be better: NamespaceOnly? In any case, one helper class lets you use existing syntax exactly as you desire. On Tue, Sep 16, 2014 at 10:43 PM, Tennessee Leeuwenburg <tleeuwenburg@gmail.com> wrote:
Hi Ali,
Thanks for the suggestion. I would prefer to avoid that just because it's a potential misuse of classes, and I suspect may lead to confusion for other developers. Otherwise that's exactly what I want to do.
Cheers, -T
On 17 September 2014 15:27, Ali Alkhatib <al2@stanford.edu> wrote:
This may be a misuse of classes, but why can't you make a class and then not instantiate it?
class signin: def handle(): return "this works"
signin.handle() # returns "this works"
On Tue, Sep 16, 2014 at 10:19 PM, Tennessee Leeuwenburg <tleeuwenburg@gmail.com> wrote:
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block.
For example,
block signin: def handle_new_user(): do_it()
def handle_existing_user(): do_it()
while True: try: signin.handle_existing_user(): except: signin.handle_new_user()
do_other_stuff()
At the moment, I would have to either break out into more files, or somewhat clumsily co-opt things like functions or staticmethods. I think that supporting named blocks or inline module declarations would really help me organise some of my code much better. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace.
I hope this makes sense and that I'm not overlooking anything obvious.
Cheers, -Tennessee
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ali Alkhatib Department of Computer Science PhD Student - Stanford University
-- -------------------------------------------------- Tennessee Leeuwenburg http://myownhat.blogspot.com/ "Don't believe everything you think"
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
David Mertz <mertz@gnosis.cx> writes:
Why is this a misuse? Classes are largely just namespaces to start with, and if you want to use them solely for that purpose, it's all there for you.
I think it's a misuse of the semantic meaning of classes to use them as pure namespaces. The semantic intent conveyed by defining a class is that you're defining a class *of objects*, and therefore that the class is intended to be instantiated. The programmer reading a class definition is receiving a strong signal that there will be objects of this class in the program. To have a class and not instantiate it, merely to have a namespace, is at least misleading the reader of that code. To do this is not an error. But it is IMO a code smell. If you're defining a class and using it only as a namespace, your design is likely poor and you need to re-think it. In this case, I think Tennessee's intent is much better met using modules; those *are* semantically namespace singletons, matching the intent here and therefore much better at communicating that intent. I see no justification given here for avoiding modules if this is what's needed. -- \ Lucifer: “Just sign the Contract, sir, and the Piano is yours.” | `\ Ray: “Sheesh! This is long! Mind if I sign it now and read it | _o__) later?” —http://www.achewood.com/ | Ben Finney
On Sep 16, 2014, at 23:21, David Mertz <mertz@gnosis.cx> wrote:
Why is this a misuse?
Well, for one thing, you're relying on the fact that unbound methods are just plain functions, which was not true in 2.x and is still not described that way in the documentation. You're also ignoring the fact that the first parameter of a method should be self and the convention (enforced by the interpreter 2.x, although no longer in 3.x, and by various lint tools, and likely relied on by IDEs, etc.) that when calling an unbound method you pass an instance of the class (or a subclass) as the first argument. In short, you're going to confuse both human and automated readers. Anyone who gets how methods and descriptors work is going to be able to figure it out, but is that really sufficient for readability? Of course you could solve all of that by declaring each method @staticmethod--or by writing a metaclass or class decorator that does that for you automatically, or (if you don't care about 2.x, or about consenting adults accidentally creating an instance and discovering that the methods don't work) just writing one that does nothing except indicate to the human reader that this is a non-instantiatable class whose methods are all static.
Classes are largely just namespaces to start with, and if you want to use them solely for that purpose, it's all there for you. If you wanted to make you intention even more obviously, you could do something like:
class NoInstance(object): ... def __new__(cls): ... raise NotImplementedError ... class signin(NoInstance): ... def handle(*args): ... print("Hello", args) ... signin() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __new__ NotImplementedError signin.handle('some','args','here') Hello ('some', 'args', 'here')
Maybe some other name than NoInstance would be better: NamespaceOnly? In any case, one helper class lets you use existing syntax exactly as you desire.
On Tue, Sep 16, 2014 at 10:43 PM, Tennessee Leeuwenburg <tleeuwenburg@gmail.com> wrote:
Hi Ali,
Thanks for the suggestion. I would prefer to avoid that just because it's a potential misuse of classes, and I suspect may lead to confusion for other developers. Otherwise that's exactly what I want to do.
Cheers, -T
On 17 September 2014 15:27, Ali Alkhatib <al2@stanford.edu> wrote:
This may be a misuse of classes, but why can't you make a class and then not instantiate it?
class signin: def handle(): return "this works"
signin.handle() # returns "this works"
On Tue, Sep 16, 2014 at 10:19 PM, Tennessee Leeuwenburg <tleeuwenburg@gmail.com> wrote:
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block.
For example,
block signin: def handle_new_user(): do_it()
def handle_existing_user(): do_it()
while True: try: signin.handle_existing_user(): except: signin.handle_new_user()
do_other_stuff()
At the moment, I would have to either break out into more files, or somewhat clumsily co-opt things like functions or staticmethods. I think that supporting named blocks or inline module declarations would really help me organise some of my code much better. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace.
I hope this makes sense and that I'm not overlooking anything obvious.
Cheers, -Tennessee
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ali Alkhatib Department of Computer Science PhD Student - Stanford University
-- -------------------------------------------------- Tennessee Leeuwenburg http://myownhat.blogspot.com/ "Don't believe everything you think"
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Wed, Sep 17, 2014 at 01:51:29AM -0700, Andrew Barnert wrote:
On Sep 16, 2014, at 23:21, David Mertz <mertz@gnosis.cx> wrote:
Why is this a misuse?
Well, for one thing, you're relying on the fact that unbound methods are just plain functions, which was not true in 2.x and is still not described that way in the documentation. You're also ignoring the fact that the first parameter of a method should be self and the convention (enforced by the interpreter 2.x, although no longer in 3.x, and by various lint tools, and likely relied on by IDEs, etc.) that when calling an unbound method you pass an instance of the class (or a subclass) as the first argument.
While all this is true, one can work around it by declaring all your methods @staticmethod. But it's worse than that. By using a class, you imply inheritance and instantiation. Neither is relevant to the basic "namespace" idea. Furthermore, there's no point (in my opinion) in having this sort of namespace unless functions inside a namespace can refer to each other without caring about the name of the namespace they are in. Think of modules. Given a module a.py containing functions f and g, f can call g: def f(): return g() without writing: def f(): return a.g() Classes don't give you that, so they are not up to the job. Modules, on the other hand, give us almost exactly what is needed here. We can create module instances on the fly, and populate them. A class decorator could accept a class and return a module instance, on the fly. That would still be ugly, since @namespace class stuff: *looks* like a class even though it isn't, but it will do as a proof-of-concept. -- Steven
Thanks to everyone for the replies! I read them all with interest. The fundamental issue for me is that you shouldn't just co-opt functionality. The semantics of a class is clearly intended to be a class of objects -- and instantiatable thing which is a core part of OO design. Re-using it for named blocks really just seems like it would be massively confusing, particularly if one were to interleave the two. I also take Steve's point about the ability for functions to refer to eachother without using the full namespace. That would be another useful effect. Does anyone think this idea is worth developing further, or is it best left as an interesting discussion? On 17 September 2014 19:21, Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, Sep 17, 2014 at 01:51:29AM -0700, Andrew Barnert wrote:
On Sep 16, 2014, at 23:21, David Mertz <mertz@gnosis.cx> wrote:
Why is this a misuse?
Well, for one thing, you're relying on the fact that unbound methods are just plain functions, which was not true in 2.x and is still not described that way in the documentation. You're also ignoring the fact that the first parameter of a method should be self and the convention (enforced by the interpreter 2.x, although no longer in 3.x, and by various lint tools, and likely relied on by IDEs, etc.) that when calling an unbound method you pass an instance of the class (or a subclass) as the first argument.
While all this is true, one can work around it by declaring all your methods @staticmethod. But it's worse than that.
By using a class, you imply inheritance and instantiation. Neither is relevant to the basic "namespace" idea.
Furthermore, there's no point (in my opinion) in having this sort of namespace unless functions inside a namespace can refer to each other without caring about the name of the namespace they are in. Think of modules. Given a module a.py containing functions f and g, f can call g:
def f(): return g()
without writing:
def f(): return a.g()
Classes don't give you that, so they are not up to the job.
Modules, on the other hand, give us almost exactly what is needed here. We can create module instances on the fly, and populate them. A class decorator could accept a class and return a module instance, on the fly. That would still be ugly, since
@namespace class stuff:
*looks* like a class even though it isn't, but it will do as a proof-of-concept.
-- Steven _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- -------------------------------------------------- Tennessee Leeuwenburg http://myownhat.blogspot.com/ "Don't believe everything you think"
On 25 September 2014 12:33, Tennessee Leeuwenburg <tleeuwenburg@gmail.com> wrote:
Thanks to everyone for the replies! I read them all with interest.
The fundamental issue for me is that you shouldn't just co-opt functionality. The semantics of a class is clearly intended to be a class of objects -- and instantiatable thing which is a core part of OO design. Re-using it for named blocks really just seems like it would be massively confusing, particularly if one were to interleave the two.
The metaclass system already allows for fairly significant variations in "class" semantics. In this case, a metaclass that disallowed instantiation and bypassed the normal class lookup machinery seems entirely feasible. That doesn't seem any more fundamentally confusing than using the same syntax for normal classes, metaclasses, ABCs, enumerations, database ORM models, web framework form and view definitions, etc. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 9/17/14 1:19 AM, Tennessee Leeuwenburg wrote:
I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. Yeah, standalone function CAN be easier to test provided that you did everything possible to make the function testable. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace. So this is how I read your idea:
1. Import the necessary names from other modules if needed 2. Organize them local to the module 3. Use them by attribute loop-up as indicated by your example The idea sounds pretty cool, but first time I ask myself as a Python user is whether I find signing.xxx more appealing than writing xxxx directly. As an import mechanism, the regular import seems good enough to me. Personally, based on your examples, I should have a module named sigin. Because in advance I know I will have a bunch of functions that are logically related. These functions will be used when the user is signed in. So I will tell myself don't wait just do it now, put them into a module. When I use the module, I just import signin and in my code I just signin.handle_new_user It is also my preference to import the module rather than importing individual functions into the namespace; I want to be able to know the origin of the function as I write my code. Now, can handle_new_user be used outside of the signin context? I really doubt it. If handle_new_user is meant to run after the user is signed in, then that function will only live in 1 block. No resuse. As a macro, I think that the equivalent is probably grouping within a function (although that is not what most people think of macros do, but er, "close enough"). Just my two cents. John
On 17.09.2014 07:19, Tennessee Leeuwenburg wrote:
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block.
For example,
block signin: def handle_new_user(): do_it()
def handle_existing_user(): do_it()
while True: try: signin.handle_existing_user(): except: signin.handle_new_user()
do_other_stuff()
At the moment, I would have to either break out into more files, or somewhat clumsily co-opt things like functions or staticmethods. I think that supporting named blocks or inline module declarations would really help me organise some of my code much better. It could also provide a more seamless way to decide to break out into a new file. Once a named block got big enough, I could easily create a new file and import those functions into the same namespace.
I hope this makes sense and that I'm not overlooking anything obvious.
Change "block" to "class" and you're done :-) You can make your code even better (i.e. more OO-style and future proof), by implementing those functions as true methods and instantiating your Signin class as signin singleton. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Sep 17 2014)
Python Projects, Consulting and Support ... http://www.egenix.com/ mxODBC.Zope/Plone.Database.Adapter ... http://zope.egenix.com/ mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
2014-09-19: PyCon UK 2014, Coventry, UK ... 2 days to go 2014-09-27: PyDDF Sprint 2014 ... 10 days to go 2014-09-30: Python Meeting Duesseldorf ... 13 days to go eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/
On Wed, Sep 17, 2014 at 03:19:52PM +1000, Tennessee Leeuwenburg wrote:
I would like to be able to use named sections to organise my code, much an inline submodules, bit without using classes or functions to organise them. I would use this if I had a group of related functions which were not written in an object-oriented-style, possibly due to not needing any shared state. Rather than break these out into a new file, I would like to just be able to use internal structure to declare the relationship. I've used the keyword 'block' to indicate the start of a named block.
For example,
block signin: def handle_new_user(): do_it()
def handle_existing_user(): do_it()
I think that this is very close to what C++ calls namespaces, and I think that the Zen of Python has something to say about namespaces :-) For quite some time I've been mulling over the idea of having multiple namespaces within a single module, but my ideas haven't been advanced enough to raise here. While having dedicated syntax for it would be nice: namespace stuff: a = 2 def stuff(x): ... assert stuff.a == 2 I *think* it should be possible to abuse the class statement to get the same effect, by use of a metaclass or possibly a class decorator: @namespace class stuff: a = 2 def stuff(x): ... assert isinstance(stuff, ModuleType) assert stuff.a == 2 The hardest part, I think, is getting scoping right in the functions. What I would expect is that inside a namespace, scoping should go: local current namespace module globals built-ins so that functions inside a single namespace can refer to each other without needing to give a fully-qualified name. In other words, this sort of namespace is just like a module, but it doesn't need to be written in an external file. -- Steven
participants (9)
-
Ali Alkhatib
-
Andrew Barnert
-
Ben Finney
-
David Mertz
-
John Yeuk Hon Wong
-
M.-A. Lemburg
-
Nick Coghlan
-
Steven D'Aprano
-
Tennessee Leeuwenburg