Python module and object names clash - python

Please consider the following Python modules excerpts:
foo.py:
class Foo:
(...)
bar.py:
import foo
foo = foo.Foo()
The variable foo, which was a module object, is overwritten with a Foo object.
I know that I can use other names for the object, e.g.:
foobar = foo.Foo()
but semantically it makes more sense in my code to have it called foo, since it will be the only instance.
(I tried to workaround this by dropping classes and using modules only, but I went back to using classes because using modules only had "robustness" problems.)
This is kind of a philosophical question, but what is the "right" way of handling this potential object/module names clash?

In my opinion there is nothing wrong with what you are currently doing, but to make it more clear for everyone reading the code I would suggest changing your code to something like the following:
import foo as foo_mod
foo = foo_mod.Foo()
Or alternatively:
from foo import Foo
foo = Foo()
This prevents the name clash so it will be more obvious that the variable foo in your module is not going to refer to the module of the same name.

I've also been favoring the following style nowadays:
import foo
my_foo = foo.Foo()
I prefer this because it keeps module names untouched, and those are are more global and sacred than local variables.

This pattern doesn't seem to bother peeps who use Flask + Celery,
from celery import Celery
def make_celery(app):
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
...
Obviously, the correct way to create an instance of this class is stalk = Celery() (hehe)

Related

Import a Python module without adding it to the local namespace

What I'd like to do
I'd like to import a Python module without adding it to the local namespace.
In other words, I'd like to do this:
import foo
del foo
Is there a cleaner way to do this?
Why I want to do it
The short version is that importing foo has a side effect that I want, but I don't really want it in my namespace afterwards.
The long version is that I have a base class that uses __init_subclass__() to register its subclasses. So base.py looks like this:
class Base:
_subclasses = {}
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls._subclasses[cls.__name__] = cls
#classmethod
def get_subclass(cls, class_name):
return cls._subclasses[class_name]
And its subclasses are defined in separate files, e.g. foo_a.py:
from base import Base
class FooA(Base):
pass
and so on.
The net effect here is that if I do
from base import Base
print(f"Before import: {Base._subclasses}")
import foo_a
import foo_b
print(f"After import: {Base._subclasses}")
then I would see
Before import: {}
After import: {'FooA': <class 'foo_a.FooA'>, 'FooB': <class 'foo_b.FooB'>}
So I needed to import these modules for the side effect of adding a reference to Base._subclasses, but now that that's done, I don't need them in my namespace anymore because I'm just going to be using Base.get_subclass().
I know I could just leave them there, but this is going into an __init__.py so I'd like to tidy up that namespace.
del works perfectly fine, I'm just wondering if there's a cleaner or more idiomatic way to do this.
If you want to import a module without assigning the module object to a variable, you can use importlib.import_module and ignore the return value:
import importlib
importlib.import_module("foo")
Note that using importlib.import_module is preferable over using the __import__ builtin directly for simple usages. See the builtin documenation for details.

Use module as class instance in Python

TL; DR
Basically the question is about hiding from the user the fact that my modules have class implementations so that the user can use the module as if it has direct function definitions like my_module.func()
Details
Suppose I have a module my_module and a class MyThing that lives in it. For example:
# my_module.py
class MyThing(object):
def say():
print("Hello!")
In another module, I might do something like this:
# another_module.py
from my_module import MyThing
thing = MyThing()
thing.say()
But suppose that I don't want to do all that. What I really want is for my_module to create an instance of MyThing automatically on import such that I can just do something like the following:
# yet_another_module.py
import my_module
my_module.say()
In other words, whatever method I call on the module, I want it to be forwarded directly to a default instance of the class contained in it. So, to the user of the module, it might seem that there is no class in it, just direct function definitions in the module itself (where the functions are actually methods of a class contained therein). Does that make sense? Is there a short way of doing this?
I know I could do the following in my_module:
class MyThing(object):
def say():
print("Hello!")
default_thing = MyThing()
def say():
default_thing.say()
But then suppose MyThing has many "public" methods that I want to use, then I'd have to explicitly define a "forwarding" function for every method, which I don't want to do.
As an extension to my question above, is there a way to achieve what I want above, but also be able to use code like from my_module import * and be able to use methods of MyThing directly in another module, like say()?
In module my_module do the following:
class MyThing(object):
...
_inst = MyThing()
say = _inst.say
move = _inst.move
This is exactly the pattern used by the random module.
Doing this automatically is somewhat contrived. First, one needs to find out which of the instance/class attributes are the methods to export... perhaps export only names which do not start with _, something like
import inspect
for name, member in inspect.getmembers(Foo(), inspect.ismethod):
if not name.startswith('_'):
globals()[name] = member
However in this case I'd say that explicit is better than implicit.
You could just replace:
def say():
return default_thing.say()
with:
say = default_thing.say
You still have to list everything that's forwarded, but the boilerplate is fairly concise.
If you want to replace that boilerplate with something more automatic, note that (details depending on Python version), MyThing.__dict__.keys() is something along the lines of ['__dict__', '__weakref__', '__module__', 'say', '__doc__']. So in principle you could iterate over that, skip the __ Python internals, and call setattr on the current module (which is available as sys.modules[__name__]). You might later regret not listing this stuff explicitly in the code, but you could certainly do it.
Alternatively you could get rid of the class entirely as use the module as the unit of encapsulation. Wherever there is data on the object, replace it with global variables. "But", you might say, "I've been warned against using global variables because supposedly they cause problems". The bad news is that you've already created a global variable, default_thing, so the ship has sailed on that one. The even worse news is that if there is any data on the object, then the whole concept of what you want to do: module-level functions that mutate a shared global state, carries with it most of the problems of globals.
Not Sure why this wouldn't work.
say = MyClass().say()
from my_module import *
say
>>Hello!

Is it possible to import a class defined inside a function?

There is a class from a 3rd party system that I'd like to sub-class for my own purposes, but it's defined within a function, like so:
def foo():
class Bar():
return Bar
If I try to import it just with from x import bar, I get ImportError: cannot import name 'Bar'. Is it possible (or wise) to import Bar? Perhaps the original coder put the class inside the function specifically to prevent others from using it directly?
The class I'm trying to get is CookieSession, defined inside BaseCookieSessionFactory, which can be found here:
http://docs.pylonsproject.org/projects/pyramid/en/master/_modules/pyramid/session.html
It already does 90% of what I want, and it seems like it would be a waste to implement my own from scratch, since I would just be copy-pasting much of the code.
Edit:
Following the advice in Chepner's answer, I sub-classed it by building my own factory function:
from pyramid.session import SignedCookieSessionFactory
def MySessionFactory(secret, [other args here...]):
#implementer(ISession)
class MySession(SignedCookieSessionFactory(secret)):
...
return MySession
You can't import it, because it doesn't exist until foo is actually called. However, it appears that foo simply defines the function and returns a reference to it. In that case, you just need something like
from otherfile import foo
Bar = foo()
x = Bar() # create an instance of Bar

python import nested classes shorthand

How to import nested package using the "as" shorthand?
This question is similar to importing a module in nested packages only the nesting is within the same .py file, not across folders.
In foo.py (All python files are in the same package, and are version 3.4):
class Foo:
class Bar:
...
I can access these subclasses in another .py file:
from . import foo
...
bar = foo.Foo.Bar()
What I would like to do:
from . import foo.Foo.Bar as Bar # DOES NOT WORK: "unresolved reference" error.
...
bar = Bar() # saves typing.
bar2 = Bar()
...
Is there a way to do this?
There is little point in nesting Python classes; there is no special meaning attached to doing so other than nesting the namespaces. There rarely is any need to do so. Just use modules instead if you need to produce additional namespaces.
You cannot directly import a nested class; you can only import module globals, so Foo in this case. You'd have to import the outer-most class and create a new reference:
from .foo import Foo
Bar = Foo.Bar
del Foo # remove the imported Foo class again from this module globals
The del Foo is entirely optional. The above does illustrate why you'd not want to nest classes to begin with.

Python Module Initialization

Is it bad practice to initialize the objects in the module, in the module code?
in Module.py:
class _Foo(object):
def __init__(self):
self.x = 'Foo'
Foo = _Foo()
Than in user code, you could:
>>> from Module import Foo
>>> print Foo.x
'Foo'
>>>
...without having to initialize the Foo class in the user code. Of course, only useful if you don't need arguments to initialize the object.
Is there a reason not to do this?
Typically, you only want to run the minimum necessary to have your module usable. This will have an overall effect on performance (loading time), and can also make debugging easier.
Also, usually more than one instance will be created from any given class.
Having said that, if you have good reasons (such as only wanting one instance of a class), then certainly initialize it at load time.
I do this sometimes, when it's really convenient, but I tend to do foo = Foo(). I really dislike the idea of making the class appear private, and making the instance available as Foo. As a developer using your code I'd find that pretty disconcerting.

Categories

Resources