1

I would like to convert a singleton-object programmatically into a Python module so that I can use the methods of this singleton-object directly by importing them via the module instead of accessing them as object attributes. By "programmatically" I mean that I do not want to have to copy-paste the class methods explicitly into a module file. I need some sort of a workaround that allows me to import the object methods into to global scope of another module.

I would really appreciate if someone could help me on this one.

Here is a basic example that should illustrate my problem:

mymodule.py

class MyClass:
"""This is my custom class"""
    def my_method(self):
        return "myValue"

singleton = MyClass()

main_as_is.py

from mymodule import MyClass

myobject = MyClass()
print(myobject.my_method())

main_to_be.py

from mymodule import my_method # or from mymodule.singleton import my_method

print(my_method())
6
  • Give us a stripped-down example of two dozen lines or so that we know exactly what you are trying to achieve. Commented May 16, 2018 at 12:20
  • 5
    Where's the benefit of doing this? Instead of writing someobj.thing you'd write somemodule.thing. Unless of course you intend to use a "star" import equivalent, but that's generally not a Good Idea. See stackoverflow.com/questions/2386714/why-is-import-bad and pythonconquerstheuniverse.wordpress.com/2011/03/28/… Commented May 16, 2018 at 12:21
  • @PM2Ring: My boss prefers procedural style programming so he asked me to do this. In fact he would like to import the methods explicitly like "from mymodule import method1, method2" ... The benefit would be that you don't have to initialize an object and that you don't have to type "someobj" each time you use a method ;) Commented May 17, 2018 at 8:29
  • 3
    You might need a new boss :P Commented May 18, 2018 at 19:30
  • 2
    What does your boss mean by "procedural style programming"? If he's opposed to OOP, I doubt he'd be very happy with a Java-style Singleton Design Pattern, which is the exact kind of thing most anti-OOP people hate. Or, if he means "not functional like Scheme" (or Haskell), using the class instead of a closure is just going to look like pointless obfuscation to him. Commented May 20, 2018 at 5:24

1 Answer 1

3

You can use the same strategy that the standard random module uses. All the functions in that module are actually methods of a "private" instance of the Random class. That's convenient for most common uses of the module, although sometimes it's useful to create your own instances of Random so that you can have multiple independent random streams.

I've adapted your code to illustrate that technique. I named the class and its instance with a single leading underscore, since that's the usual convention in Python to signify a private name, but bear in mind it's simply a convention, Python doesn't do anything to enforce this privacy.

mymodule.py

class _MyClass:
    """ This is my custom class """
    def my_method(self):
        return "myValue"

_myclass = _MyClass()
my_method = _myclass.my_method

main_to_be.py

from mymodule import my_method

print(my_method())       

output

myValue

BTW, the from mymodule import method1, method2 syntax is ok if you only import a small number of names, or it's clear from the name which module it's from (like math module functions and constants), and you don't import from many modules. Otherwise it's better to use this sort of syntax

import mymodule as mm
# Call a method from the module
mm.method1()

That way it's obvious which names are local, and which ones are imported and where they're imported from. Sure, it's a little more typing, but it makes the code a whole lot more readable. And it eliminates the possibility of name collisions.

FWIW, here's a way to automate adding all of the _myclass methods without explicitly listing them (but remember "explicit is better than implicit"). At the end of "mymodule.py", in place of my_method = _myclass.my_method, add this:

globals().update({k: getattr(_myclass, k) for k in _MyClass.__dict__ 
    if not k.startswith('__')})

I'm not comfortable with recommending this, since it directly injects items into the globals() dict. Note that that code will add all class attributes, not just methods.


In your question you talk about singleton objects. We don't normally use singletons in Python, and many programmers in various OOP languages consider them to be an anti-pattern. See https://stackoverflow.com/questions/12755539/why-is-singleton-considered-an-anti-pattern for details. For this application there is absolutely no need at all to use a singleton. If you only want a single instance of _MyClass then simply don't create another instance of it, just use the instance that mymodule creates for you. But if your boss insists that you must use a singleton, please see the example code here.

Sign up to request clarification or add additional context in comments.

10 Comments

Many thanks. The problem with this approach is that I have to assign all the methods from the class one-by-one to some local variable and thus I would still need to copy paste everything. I would like to avoid code duplication.
@Jerry Do you mean you want to avoid in "mymodule.py" having to do my_method = _myclass.my_method for each method of _myclass?
@Jerry If so, there's a way to do that, but it's a bit ugly. FWIW, the random module does explicit one-by-one assignment, see the end of the module's source code.
I agree with the fact that there is not much to gain here and that things should not be overcomplicated with some controversial Design Pattern ;) I think though that there should be a simple way to include some functionalities in an exclusively procedural module or package that were initially implemented in a OOP style without forcing the use of OOP concepts.
I guess I should not have used the term "singleton" in my problem description. In the end the only thing that this approach has in common with the Singleton Pattern is that it uses a single instance of a class to serve a specific purpose. The key difference is that this instance would not be accessed explicitly throughout the project (which I guess is what makes the Singleton Pattern a Design Pattern and which makes it prone to misuse) but it would be encapsulated inside a module.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.