How does Python handle imported subclasses? - python

I am working on a project that requires me to build several classes and subclasses in one file, and use them in a second file. I would like to ask how Python handles importing the first file into the second.
For instance, if i have a file my_classes.py:
class Myclass(object):
pass
class Mysubclass(myclass):
pass
will using the following code work:
from my_classes import Myclass
print Mysubclass
(where the print command is just an example of using Mysubclass), or do I need to import Mysubclass explicitly?
Thanks in advance!

This won't work. Python import statement doesn't care about subclasses. Actually, it doesn't care about anything. It does precisely what you tell it to do. "Explicit is better than implicit" is a popular saying in Python circles.
Here:
from my_classes import Myclass
You told Python to import only Myclass.
This will import both classes:
from my_classes import Myclass, Mysubclass
You can read how Python import works here.

Your subclass will not be available if you do it like this. You must import every object by itself.
Here a quick example
test_class.py
class MyClass(object):
def init(self):
print self.class
class MySubClass(MyClass):
def __init__(self):
print self.__class__
test_class_import.py
from test_class import MyClass
MyClass()
MySubClass()
##output##
<class 'test_class.MyClass'>
Traceback (most recent call last):
File "test_class2.py", line 4, in <module>
MySubClass()
NameError: name 'MySubClass' is not defined
but
from test_class import MyClass, MySubClass
MyClass()
MySubClass()
##output##
<class 'test_class.MyClass'>
<class 'test_class.MySubClass'>

Every module has a namespace.
A namespace is a mapping from variable names to values (Python objects).
The statement
import my_classes
makes the my_classes namespace accessible from the current module by placing the variable name my_classes in the current module's namespace. You can then access values from my_classes with the syntax
my_classes.variable
So, for example:
import my_classes
print my_classes.Mysubclass
print my_classes.MyClass
If that is too much typing, I suggest
import my_classes as MC
print MC.Mysubclass
print MC.MyClass
you could also do
from my_classes import Mysubclass, MyClass
but this form of import is discouraged by some Python experts.
from my_classes import Mysubclass, MyClass
loads the entire module my_class but only
places the variable names Mysubclass and MyClass in the current module's namespace. They point to the same values as do the variables of the same name in the my_classes namespace. You don't get access to anything else from the my_class module's namespace.

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.

Can staticmethod be imported?

there are many examples of staticmethod in a class with caller in one file. this works fine. but i have tried to save the class with staticmethod in a single file and import it from caller. this then throws the error "AttributeError: 'module' object has no attribute methodname"
i am using python2.7.
used exact example from Static methods in Python?
import MyClass
# belwo class is saved in a saparate file named MyClass.py
# class MyClass(object):
# #staticmethod
# def the_static_method(x):
# print(x)
MyClass.the_static_method(2) # outputs 2
# if via import, we have the error: AttributeError: 'module' object has no attribute 'the_static_method'
In your example, since the name of the python file (MyClass.py) is the same as the class name, Python will assume you are referring to the module MyClass(which is your file) instead of the class MyClass. One suggestion is to change your first line import MyClass to from MyClass import MyClass. Then it should work. It's generally better to follow the Python naming convention recommended here https://softwareengineering.stackexchange.com/questions/308972/python-file-naming-convention

Importing a module for all methods of an instance in Python3

I encountered a problem whilst importing a module in a Python3 class:
I am importing a module in the __init__ method of my class. It works fine in this method, however is there a way to use this module again in another method? I tried saving the module into a self. variable, still doesn't work.
Of course I could import it again inside the method, but I would rather import the module for all of my methods, since most of them need it.
I'll give you some example code below:
class Example(object)
def __init__(self):
import moduleName as module
module.function() # works perfectly
# Trying to save module for the whole instance:
self.module = module
def method(self):
module.function() # Does not recognize module
self.module.function() # Does not recognize attribute either
I'd be happy if someone could help me with this:)
I don't know if in python we can save a module in a variable. I attempt to declare the import at class level, but the code doesn't work.
I python the function are first-citizen so we can save function in a variable. You should save the function you need in variables when you are in __init__():
import module as mod
mod.function()
self.function = mod.function
After a while...
You can load a module dinamically, but to this you have to import the module importlib. This is the code:
import importlib
class MyClass:
def __init__(self):
self.module = importlib.import_module("module")
self.module.function()
def func(self):
self.module.function()
c = MyClass()
c.func()
There is also the imp module.

Python import in __init__()

I need to have an import in __init__() method (because i need to run that import only when i instance the class).
But i cannot see that import outside __init__(), is the scope limited to__init__? how to do?
Imported names are bound to the current scope, so an import inside a function binds to a local name only.
If you absolutely have to import something in __init__ that then needs to be globally avaliable, mark the imported name as global first:
>>> def foo():
... global sys
... import sys
...
>>> sys
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'sys' is not defined
>>> foo()
>>> sys
<module 'sys' (built-in)>
but this usually leads to strange and wonderfully difficult to locate bugs. Don't do that, just make your imports at module scope instead.
If you need the imported name within other class methods, you could also assign the imported name to a instance variable:
class Foo(object):
def __init__(self):
import os
self.join = os.path.join
but again, that's not the best practice to use.
You can just import it again other places that you need it -- it will be cached after the first time so this is relatively inexpensive.
Alternatively you could modify the current global namespaces with something like globals()['name'] = local_imported_module_name.
EDIT: For the record, although using the globals() function will certainly work, I think a "cleaner" solution would be to declare the module's name global and then import it, as several other answers have mentioned.
The import statement makes the imported names only available to the current scope. An import foo inside your __init__ creates a foo which is only visible within the __init__ method.
You could either add the import foo to any method which needs to access the module or if you find yourself writing the import over an over again use the global keyword to import it to the module scope.
class Wayne(object):
def __init__(self):
global foo
import foo
If you want the result of your import to be visible to other objects of the class, you would need to assign the resulting object from your import to a class or instance variable
For example:
>>> class Foo(object):
... def __init__(self):
... import math
... self.bar = math.pi
... def zoo(self):
... return self.bar
...
>>> a = Foo()
>>> a.zoo()
3.141592653589793

Child class doesn't recognize module imports of parent class?

I've got two classes in two different modules:
animal.py
monkey.py
animal.py:
import json
class Animal(object):
pass
monkey:
import animal
class Monkey(animal.Animal):
def __init__(self):
super(Monkey, self).__init__()
# Do some json stuff...
When I try to instantiate a Monkey, I get a
NameError: global name 'json' is not defined
But I'm importing json in the defining module of the super class, so why wouldn't it be loaded?
It is loaded, but its name is not available in the scope of monkey.py.
You could type animal.json to get at it (but why would you), or just type
import json
in monkey.py as well. Python will ensure that the module is not loaded twice.
Well, python imports do not function as C #include pre-processor directive. They import the module to the namespace of the importing module only and not to the global namespace. So, you're gonna have to import json in each and every module you intend to use it.

Categories

Resources