CPP Namespaces For Python

Hi, Please pardon me if my idea is not making sense or already exists, I'm kind of new to developing in Python but I had this idea today and I wanted to share it with you. I think a class type such as "@functionclass" may be helpful for creating functions intended to keep a list of methods in a scope. At the moment, I achieved this via writing "@classmethod" to all my functions but I think such a decorator might help clarify intent for the reader and ease the programmers' job. My regards, Alperen

Hi Alperen, Why do you need a class at all rather than just a module with some functions? Irit On Tuesday, October 6, 2020, 01:38:21 PM GMT+1, Alperen Keleş <alpkeles99@gmail.com> wrote: Hi, Please pardon me if my idea is not making sense or already exists, I'm kind of new to developing in Python but I had this idea today and I wanted to share it with you. I think a class type such as "@functionclass" may be helpful for creating functions intended to keep a list of methods in a scope. At the moment, I achieved this via writing "@classmethod" to all my functions but I think such a decorator might help clarify intent for the reader and ease the programmers' job. My regards,Alperen_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/5FE6HA... Code of Conduct: http://python.org/psf/codeofconduct/

I cannot answer for Alperen, but I commonly encounter this when writing testing code: generally I use the format: some_module.py tests/test_some_module.py where it is expected the filename to test a module is "test_module_name.py". However, within that, I might want to namespace based on the class in some_module.py. If you use something like unittest, classes are natural but if you use pytest it is unnecessary and commonly I end up with what Alperen has: marking everything as classmethod. What I have been looking for is a class/mixin/decorator that marks all methods I add as classmethods. Why bother marking as class_method? Well, I think it is bad practice where possible to have unused input in functions, even in testing code. Often I have made mistakes for example in copy-pasting and it would be caught if you look at unused variables and such matters. YMMV, but this, in some form, gets a +1 from me. On Tue, 6 Oct 2020 at 14:16, Irit Katriel via Python-ideas < python-ideas@python.org> wrote:

Hi Irit, In my case, the code structure is as below. I'm writing a city traffic simulator which includes roads and cars. Cars have different states, MovingCar, IdleCar, ParkingCar... A car can move between different states and it keeps the same information. My solution to this was, Having a different class that captures the generic functions for each state. Why writing a module does not work has 2 parts, they may be due to my insufficient experience with python but I'm switching between the states as their API's are executed. Something like the code sample below class AA: @classmethod def greet(cls, A_instance): print("Hello", A_instance.name) class BB: @classmethod def greet(cls, A_instance): print("Hi", A_instance.name) class A: def __init__(self, state, name): self.state = state self.name = name def greet(self): self.state.greet(self) def switchAA(self): self.state = AA def switchBB(self): self.state = BB if __name__ == "__main__": obj = A(AA, "alperen) obj.greet() obj.switchBB() obj.greet() The output is: Hello alperen Hi alperen I believe this minimal example captures the semantics that I'm working on. I thought that AA and BB classes may be classified as a special type of class. My regards, Alperen

cf. this relatively recent conversation on the same topic-- worth reading in entirety: https://mail.python.org/archives/list/python-ideas@python.org/thread/TAVHEKD... As I said in that conversation, in the past I have wanted to have module-like namespaces inside of modules because sometimes it makes organizational sense to not create a separate, very short, module file. Summary of how that thread turned out: There seemed to be agreement among most of the conversation participants that this would be a useful idea, and a few different syntax ideas were batted about (a decorator, totally new syntax). A few people have experimented with various ways of doing this using current python but all of the ideas anyone has come up with so far would require some kind of change to the core language to make them work. The conversation didn't go any further than that (to my knowledge). --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

I think the OP would be happy with a decorator they can just copy-paste. All it needs to do is go over the class dict and apply @classmethod to every “normal” function. Probably skip under names. On Tue, Oct 6, 2020 at 06:46 Ricky Teachey <ricky@teachey.org> wrote:
-- --Guido (mobile)

I was just working on that, although I prefer staticmethod: def allstatic(cls): for key, value in cls.__dict__.items(): if not key.startswith('__'): setattr(cls, key, staticmethod(value)) return cls @allstatic class C: def foo(a, b): print(f'{a}, {b}') C.foo('hello', 'world') C().foo('world', 'hello') It could be improved depending on the use case, for example checking for methods. Eric On 10/6/2020 10:42 AM, Guido van Rossum wrote:

NOTE 1: After writing this whole post, I realized that while you used @classmethod, what you seem to really want is a fully @staticmethod class -- certainly your example was a static method, and some other posters were talking about static method (i.e. "it's bad style to have unused parameters in a function") -- so this answer *may* be not quite write for your use case, but it does apply to the example given. And I'm having a hard time figuring out when one might want a fully classmethod class :-), so if that is what you intended, please post an example that actually uses the "cls" parameter. NOTE 2: maybe it was email client mangling, but your code was using two spaces for indentation (or were those tabs?), you really want to use four spaces to indent in Python -- trust me on this! Now the post: It's really hard to see what you are really working with with such a (necessarily) short example, but a couple notes: Cars have different states, MovingCar, IdleCar, ParkingCar...
A car can move between different states and it keeps the same information.
Why writing a module does not work has 2 parts, they may be due to my
insufficient experience with python but I'm switching between the states as their API's are executed.
you could use modules as namespaces in this case -- modules are objects, like everything else in Python, so you could do: in AA.py: def greet(A_instance): print("Hello", A_instance.name) BB.py: def greet(A_instance): print("Hello", A_instance.name) main_module.py: from . import AA, BB class A: def __init__(self, state, name): self.state = state self.name = name def greet(self): self.state.greet(self) def switchAA(self): self.state = AA def switchBB(self): self.state = BB and it should all work. But I agree, that doesn't "feel" right. However, a "state" to me sounds like a collection of static information -- could your state be stored as a collection of data, in a dict, or maybe a dataclass? are there actually different methods (actions) involved, that don't involve the state itself (i.e. self)? To follow your example:
the difference between these is the content of the message, so you could write: from dataclasses import dataclass @dataclass class State(): greeting: str AA = State(greeting="Hello") BB = State(greeting="Hi") class A: def __init__(self, state, name): self.state = state self.name = name def greet(self): print(self.state.greeting, self.name) def switchAA(self): self.state = AA def switchBB(self): self.state = BB if __name__ == "__main__": obj = A(AA, "alperen") obj.greet() obj.switchBB() obj.greet() BTW: part of how I got to this solution is the DRY principle (Don't Repeat Yourself): I looked at your AA and BB greet() methods, and it took me a second to see what was different about them. They were repeated code: the only difference was one string. You really don't need/want different classes (or different methods) if the logic is the same. But another way to do this, particularly if there IS some different logic in your different State classes, would be to forget static methods, and have the state stored in class attributes, and the logic in the methods: class State: def greet(self, A_instance): print(self.greeting, A_instance.name) class AA: greeting = "Hello" class BB: greeting = "Hi" It seems odd to have a subclass that only specifies a class attribute or two, but if you really want to use classes in this way, it will accomplish what you want. All that being said, an "all_static" decorator, as suggested by Guido and prototyped by Eric could be a reasonable way to create a collection of methods in one namespace, if indeed, they are different methods. -CHB PS: A reminder about this list -- it's really a better idea for folks fairly new to the language to start on another forum (e.g. tutor@python.org, stack overflow, etc) and ask: "how to I accomplish this"? and see what you get for answers, before you post an idea to ideas for a new language feature. -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

In Python 3 you can do this without any decorators. The following works and produces the same output: class AA: def greet(A_instance): print("Hello", A_instance.name) class BB: def greet(A_instance): print("Hi", A_instance.name) class A: def __init__(self, state, name): self.state = state self.name = name def greet(self): self.state.greet(self) def switchAA(self): self.state = AA def switchBB(self): self.state = BB if __name__ == "__main__": obj = A(AA, "alperen") obj.greet() obj.switchBB() obj.greet() -- Greg

On Tue, 6 Oct 2020 at 15:33, Alperen Keleş <alpkeles99@gmail.com> wrote:
Cars have different states, MovingCar, IdleCar, ParkingCar...
Well, IMHO the solution is quite more simple: class Car: def __init__(self): self.state = "parking" def move(self): if self.state != "moving": raise StateException("car can't move!") [...]

On Tue, Oct 6, 2020, at 02:50, Alperen Keleş wrote:
I think new syntax would be better than a decorator (or a metaclass, which for some reason never seems to get suggested for these things), because I think the feature should allow for the functions to directly access each other from the namespace's scope without requiring an attribute lookup. namespace Foo: x=1 def bar(): pass def baz() return bar() + x

On Tue, Oct 6, 2020 at 9:49 PM Random832 <random832@fastmail.com> wrote:
I think maybe discussion of the general namespace idea might be a little off topic for this read (per Guido's comments). However the metaclass below-- or something like it-- could still help with the problem? It was actually my attempt at a general namespace object in the previous namespace thread. It seemed to work ok, and it should work in this use case: import types class namespace(type): def __new__(mcls, name, bases, dct): if bases: raise TypeError("this is a namespace, not a class.") mod = types.ModuleType(dct.pop("__qualname__"), dct.pop("__doc__",None)) mod.__dict__.update(dct) return mod class ns(metaclass=namespace): class Desc: def __get__(self, obj, cls): return None d = Desc() if __name__=="__main__": assert ns.d # success: descriptor protocol broken as expected But there are probably deficiencies I have not uncovered. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

On Tue, Oct 6, 2020 at 6:47 PM Random832 <random832@fastmail.com> wrote:
A. New syntax is way too high a bar for a questionable feature. Classes full of static or class methods were a pattern at my last employer and it was unpleasant to work with. (Others at the company agreed but it was too late to change.) B. At some point we realized that metaclasses have too much power over subclasses (action at a distance) and we switched to recommending class decorators. Another problem with metaclasses is that it's a pain to combine two different metaclasses.
That could be done with a function and a function decorator. "Proof left as an exercise for the reader." :-) -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

On Tue, Oct 6, 2020, at 23:13, Guido van Rossum wrote:
I think a metaclass [well, "pseudo-metaclass", to use a term I made up for a metaclass that is not a subclass of type and/or does not return an instance of type] would be better in this case because the resulting object should not be a type. The reason I wanted different syntax was because I wanted to change how the functions inside are compiled [to allow nonlocal accesses to refer to the namespace's scope], though I think making them globals and a custom dict subclass [possibly ChainMap, haven't checked if it does everything I want] for globals makes this workable as a metaclass or decorator - either one can take all of the functions and replace them with a new function with different globals and the original function's code object.

On Wed, Oct 7, 2020 at 12:06 AM Random832 <random832@fastmail.com> wrote:
but a class decorator can return, well, anything. See the example I posted having it create a module object. I really don't know that that's a good idea, but yeah, if what you want is a essentially a namespace, then you really don't want a type. Maybe just an instance of object would work though. -CHB
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On 7/10/20 2:45 pm, Random832 wrote:
That got me thinking, and I came up with this: def submodule(f): return type(f.__name__, (), f()) @submodule def Stuff(): def f1(): print("First function") f2() def f2(): print("Second function") return locals() Stuff.f1() The only ugly part is the need for the 'return locals()', but that could probably be alleviated with a bit of bytecode hacking. -- Greg

I have no idea if this is a good idea, but Python already has modules to be namespaces for a collection of functions and values. And while a class decorator is *supposed* to return a class, it can, in fact, return anything. So you can make a decorator that converts a class definition to a module object: In [47]: def make_mod(cls): ...: mod = imp.new_module(cls.__name__) ...: for name, attr in vars(cls).items(): ...: if not name.startswith("_"): ...: setattr(mod, name, attr) ...: return mod ...: In [48]: @make_mod ...: class Fake: ...: an_attribute = "this" ...: def a_function(a,b): ...: print("a_function:", a, b) ...: In [49]: Fake.an_attribute Out[49]: 'this' In [50]: Fake.a_function(3, 4) a_function: 3 4 In [51]: type(Fake) Out[51]: module In [52]: vars(Fake) Out[52]: {'__name__': 'Fake', '__doc__': None, '__package__': None, '__loader__': None, '__spec__': None, 'an_attribute': 'this', 'a_function': <function __main__.Fake.a_function(a, b)>} I expect this will give your functions a very odd globals() though ;-) But this made me think -- we already have modules, so if we do want a "namespace" type of some sort, why not simply have syntax for making a module inline: new_module: def this(): pass x = 4 It would be kind of nice to be able to make anew module without having to have an actual file (or fake one) -CHB -CHB On Tue, Oct 6, 2020 at 11:02 PM Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

New improved version: def submodule(f): co = f.__code__ i = len(co.co_consts) b = bytes([0x64, i, 0x83, 0x0, 0x53, 0x0]) f.__code__ = co.replace( co_consts = co.co_consts + (locals,), co_code = co.co_code[:-4] + b ) return type(f.__name__, (), f()) @submodule def Stuff(): def f1(): print("First function") f2() def f2(): print("Second function") Stuff.f1() -- Greg
participants (10)
-
Alperen Keleş
-
Christopher Barker
-
Eric V. Smith
-
Greg Ewing
-
Guido van Rossum
-
Henk-Jaap Wagenaar
-
Irit Katriel
-
Marco Sulla
-
Random832
-
Ricky Teachey