I am new to python and I'm trying to add math module inside my class but I don't know what is the right way adding it
import math
class myClass():
#some code
or
class myClass():
import math
#some code
What is the right way the first or the second one?
Anything declared inside a class definition becomes a class variable, a module included, so by importing math within a class definition, it becomes a class variable that is accessible only via the class object or the instance object, so:
class myClass:
import math
def __init__(self, value):
self.value = value
def sqrt(self):
return math.sqrt(self.value)
print(myClass(4).sqrt())
would result in:
NameError: name 'math' is not defined
but changing the sqrt method to:
def sqrt(self):
return self.math.sqrt(self.value)
would properly output:
2.0
That said, there is usually no good reasons to import modules as class variables. In the vast majority of cases modules are imported outside the class, as global variables.
Related
In this question
How can I separate functions of class into multiple files?
the top answer suggests to use
from method_file import method
Inside a class definition to have class methods defined in separate files. However, for a class like this
my_number.py
class MyNumber:
def __init__(self):
self.x = 5
from my_method import my_method
my_method.py
def my_method(self):
print(self.x)
It would not be clear to the IDE that self refers to a MyNumber object. As a consequence code completion (for e.g. self.x) is not available in my_method. A type hint for self could solve this, i.e.
my_method.py
from my_number import MyNumber
def my_method(self: MyNumber):
print(self.x)
but this leads to a circular import.
Is there any workaround or best practice for such a situation?
There is an approach that combines a __future__ import to disregard type annotations at runtime, with a if TYPE_CHECKING clause that "imports" the code from your IDE's point of view only, so that code completion is available.
Example:
my_number.py
class MyNumber:
def __init__(self):
self.x = 5
from my_method import my_method
my_method.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from my_number import MyNumber
def my_method(self: MyNumber):
print(self.x)
With the from __future__ import annotations, we postpone the evaluation of type hints - in other words, we can type hint my_method even if we don't actually import MyNumber. This behavior was planned to be the default in Python 3.10, but it got postponed, so we need this import for now.
Now depending on your editor/IDE, you will still get a warning complaining that MyNumber isn't defined, and its methods/attributes may not show up on the autocomplete. Here's where the TYPE_CHECKING comes into play: this is simply a constant False value, which means that our clause is:
if False:
from my_number import MyNumber
In other words, we're "tricking" the IDE into thinking we're importing MyNumber, but in reality that line never executes. Thus we avoid the circular import altogether.
This might feel a little hacky, but it works :-) the whole point of the TYPE_CHECKING constant is to allow type checkers to do their job, while not actually importing code at runtime, and to do so in a clear way (Zen of Python: There should be one-- and preferably only one --obvious way to do it).
This approach has worked for me consistently in PyCharm, not sure about other IDEs/editors.
Is there any workaround or best practice for such a situation?
The best practice is not to do this. If a method implementation is specific to a class, it should be part of the class definition.
If a method is not specific to a class, it should be defined across all valid types. A Protocol is appropriate to express this :
from typing import Protocol, Any
class HasX(Protocol):
x: Any # might need a TypeVar for complex cases
def my_method(self: HasX):
print(self.x)
If a method extends a class separate of its definition, it should not be patched in. Use functools.singledispatch to externally define single dispatch functions, which are logically similar to methods:
from functools import singledispatch
from my_number import MyNumber
# not imported into MyNumber
#singledispatch
def my_method(self):
raise NotImplementedError(f"no dispatch for {type(self}")
#my_method.register
def _(self: MyNumber):
print(self.x)
Typically, the self keyword is used to represent an instance of the class. It doesn't make sense to type hint self. Second, you can't access the instance variable x via self if your function is not a method to a class that is a MyNumber object.
I would suggest two options to accomplish what you want to. You can accept a MyNumber object as a parameter to the my_method() function or you can create a new class and inherit the MyNumber class. Make sure the files are in the same directory, otherwise update the import statement in File 2.
Option #1
class MyNumber:
def __init__(self):
self.x = 5
def my_method(my_number: MyNumber):
print(my_number.x)
my_method(MyNumber())
Option #2
#my_number.py
class MyNumber:
def __init__(self):
self.x = 5
#my_method.py
from my_number import MyNumber
class MyMethod(MyNumber):
def __init__(self):
super().__init__()
def my_method(self):
print(self.x)
MyMethod().my_method()
I think you are having problems regarding object-oriented concepts in python. Your "my_method" function doesn't need the "self: MyNumber" as a parameter, in fact, you need to create an object of the MyNumber class and consequently this class will have an attribute that is the "x" since you defined the "x" in the constructor of the MyNumber class. It would look something like this:
#my_number.py
class MyNumber:
def __init__(self):
self.x = 5
#my_method.py
from my_number import MyNumber
def my_method():
mm = MyNumber()
print(mm.x)
I have two python files in one folder named firstpy. But when I am trying to import a function of python file named Sum then it gives me the error mentioned in question. The two files are:
Sum.py:
class Sum:
def doSum(a,b):
print(a+b)
Calculator.py:
from Sum import doSum
class Calculator:
doSum(4,5)
Please tell me what the error is and the solutions out there are not working for me.
You defined the method inside a class the "Sum" class, so you have to import the class, instantiate it and then you can use the method (from the class).
If you want to import only the method you have to declare it OUT of the class.
Sum.py:
#class with methods
class Sum:
def class_method(self):
print("dostuff")
#only a method
def doSum(a,b):
print(a+b)
Use pure function instead of class or make this function static:
in Sum.py
def do_sum(a, b):
# your code
Then you can import it like this: from Sum import do_sum.
Or try this:
class Sum:
#staticmethod
def do_sum(a, b):
# your code
import: from Sum import Sum and call: Sum.do_sum(args).
If you still want to use class for it, then in your Calculator.py:
from Sum import Sum
class Calculator:
def __init__(self):
self.sum = Sum()
def calculate(self, a, b):
return self.sum.do_sum(a, b)
Btw, you don't have to name your modules with a capital letter like in Java. Also, there is slightly another name conventions - not camel case, but snake case (doSum -> do_sum)
Is it fine to make a module an instance method or probaby class method so that child classes need not import them again if it is in another file and you can easily over-ride them? Also is class or instance method preferred here?
import submodule
class MyClass(object):
def __init__(self):
"""
"""
pass
def mysubmodule():
"""
Method that returns the submodule.
"""
return submobdule
If the child class is defined in the same file, there will be no need for a second import.
If the child class is defined in a different file, I fail to see the advantage of your idea. Add the import and every reader of the child class knows what the code is using.
I'm trying to call a method within a class MyClass and have its value returned.
class MyClass:
def __init__(self):
print " Class Initialized"
def gather_path(self):
self.tld_object = Tld.objects.get(id=3,FKToClient=User.pk)
return self.tld_object
How do I return the value of self.tld_object by importing my class in Python intrepreter.
I'm importing like:
from MyApp.MyClass import gather_path()
I know, this is quite basic - I'm relatively new to OOP in Python.
how do I then call this method to return the value of return self.tld_object within gather_path() method?
It depends on what you're trying to do, but typically, I think the code importing your class would look like this:
from MyApp import MyClass
my_instance = MyClass()
value = my_instance.gather_path()
The value variable will now contain tld_object's value.
If you don't want to instantiate MyClass in order to call get_path(), you need to make get_path() either a class or static method.
From your example, it's not clear that you need to set self.tld_object, since you're just returning it from gather_path() anyway, unless other methods are relying on that state under the hood. If you are, though, it would be better practice to declare it in __init__, even if you set it to None. Alternatively, if all instances of MyClass are going to use the same value of tld_object, you could make it a class variable, and just declare it outside of any method, like so:
class MyClass:
tld_object = Tld.objects.get(id=3,FKToClient=User.pk)
def gather_path(self):
return self.tld_object
Not sure how much of that is relevant to your needs, it's a bit hard to tell from the given example. If I were writing this (given what you've said so far), I'd do the following:
class MyClass:
def __init__(self):
self.tld_object = Tld.objects.get(id=3,FKToClient=User.pk)
# Maybe raise an exception or something if self.tld_object doesn't get set right
# Example of how to access tld_object from another method
def print_tld_object(self):
print self.tld_object
If you need to reach tld_object from outside the class, you would do the following in the other module:
from MyApp import MyClass
my_instance = MyClass()
tld = my_instance.tld_object
I am having trouble with this setup mainly because I am not sure what I actually want in order to solve this problem.
This is the setup
- main.py
- lib
- __init__.py
- index.py
- test.py
__init__.py has this code
import os
for module in os.listdir(os.path.dirname(__file__)+"/."):
if module == '__init__.py' or module[-3:] != '.py':
continue
__import__(module[:-3], locals(), globals())
del module
main.py has this code as of now
from lib.index import *
print User.__dict__
index.py has this code
class User(object):
def test(self):
return "hi"
pass
test.py has this code
class User(object):
def tes2(self):
return "hello"
When I execute main.py it successfully prints the method test from index.py but what I am trying to do is figure out a way where I can just create a file in the lib folder where that while has only one function in the format
class User(object):
def newFunction(self):
return abc
and this function should automatically be available for me in main.py
I am sure that this is not a hard thing to do but I honestly don't know what I want (what to search for to solve this) which is preventing me from researching the solution.
You can use a metaclass to customize class creation and add functions defined elsewhere:
import types
import os
import os.path
import imp
class PluginMeta(type):
def __new__(cls, name, bases, dct):
modules = [imp.load_source(filename, os.path.join(dct['plugindir'], filename))
for filename in os.listdir(dct['plugindir']) if filename.endswith('.py')]
for module in modules:
for name in dir(module):
function = getattr(module, name)
if isinstance(function, types.FunctionType):
dct[function.__name__] = function
return type.__new__(cls, name, bases, dct)
class User(metaclass=PluginMeta):
plugindir = "path/to/the/plugindir"
def foo(self):
print "foo"
user = User()
print dir(user)
Then in the plugin files, just create functions not classes:
def newFunction(self, abc):
self.abc = abc
return self.abc
And the metaclass will find them, turn them into methods, and attach them to your class.
Classes are objects, and methods are nothing more than attributes on class-objects.
So if you want to add a method to an existing class, outside the original class block, all that is is the problem of adding an attribute to an object, which I would hope you know how to do:
class User(object):
pass
def newFunction(self):
return 'foo'
User.newFunction = newFunction
agf's metaclass answer is basically a nifty automatic way of doing this, although it works by adding extra definitions to the class block before the class is created, rather than adding extra attributes to the class object afterwards.
That should be basically all you need to develop a framework in which things defined in one module are automatically added to a class defined elsewhere. But you still need to make a number of design decisions, such as:
If your externally-defined functions need auxiliary definitions, how do you determine what's supposed to get added to the class and what was just a dependency?
If you have more than one class you're extending this way, how do you determine what goes in which class?
At what point(s) in your program does the auto-extension happen?
Do you want to say in your class "this class has extensions defined elsewhere", or say in your extensions "this is an extension to a class defined elsewhere", or neither and somewhere bind extensions to classes externally from both?
Do you need to be able to have multiple versions of the "same" class with different extensions active at the same time?
A metaclass such as proposed by agf can be a very good way of implementing this sort of framework, because it lets you put all the complex code in one place while still "tagging" every class that doesn't work the way classes normally work. It does fix the answers to some of the questions I posed above, though.
here a working code we used in a project, I'm not sure it's the best way but it worked and there is almost no additional code to add to other files
cpu.py:
from cpu_base import CPU, CPUBase
import cpu_common
import cpu_ext
cpu_base.py:
def getClass():
return __cpu__
def setClass(CPUClass):
global __cpu__
__cpu__ = CPUClass
__classes__.append(CPUClass)
def CPU(*kw):
return __cpu__(*kw)
class CPUBase:
def __init__(self):
your_init_Stuff
# optionally a method classname_constructor to mimic __init__ for each one
for c in __classes__:
constructor = getattr(c, c.__name__ + '_constructor', None)
if constructor is not None:
constructor(self)
setClass(CPUBase)
cpu_common.py:
from cpu_base import getClass, setClass
class CPUCommon(getClass()):
def CPUCommon_constructor(self):
pass
setClass(CPUCommon)
cpu_ext.py:
from cpu_base import getClass, setClass
class CPUExt(getClass()):
pass
setClass(CPUExt)
to use the class import CPU from cpu.py