Python, Django, Storing a class name to later instantiate an object? - python

I'm trying to store my_app.path.to.my_class in a database
I'm going use this to instantiate the appropriate class object using from django.utils.module_loading import import_string
I'm worried this scheme doesn't handle well the situation where I need to change the module name, or path. would there be a better scheme to handle this?
second, in order to store the class name for a class object, I think there's a way to get the fully qualified name for the class somehow.
i.e. Is there a way for me to generate the fully_qualified_class_name below?
class FooShipping(object):
fully_qualified_class_name = 'store.shipping.foo_shipping.FooShipping'

You can use the globals dictionary to do this:
MyClass = globals()[fully_qualified_class_name]
then initialize an object using that class:
my_object = MyClass()

Related

How to Invoke parametrized Constructor if class name Dynamically Identified in Python

I am new in Python before I have only Java experience , In python I need to invoked parameter constructor while I have many class and class name identifies on runtime so I need to create that class Object with constructor and as well method. with static it is working fine. for java I can use class.forName(class_name). I tried with importlib, string to class but did not work.
Excample:
class A
def _init_(self,name):
self.name = name
def some_method(self):
print('method print',self.name)
Expectation: want to achieve-
instance = A('instance A')
instance.some_method()
in the above code class A will be identified on Run time and similar many class we have and above code I need to implement dynamically, how can achieve this.
If classes are in another file, use getattr
import module_with_my_classes
x = getattr(module_with_my_classes, 'A')
If you are in the file as the class definitions, use globals
x = globals()['A']
# x is a A instance

Simplest way to find a class by a string in python

getattr(importlib.import_module(__name__), "Some Class")
This is my method.
But this is redundant.
Is there a simpler method?
I use django and I'm trying to pass a dict of model to other class whose name is same as model name.
Roughly, this is my code.
I want to do this without if statement.
instance_list = []
obj_list = [a,b,c,d]
for obj in obj_list:
dic = model_to_dict(obj)
if 'Soccer' == obj.__class__.__name__:
instance_list.append(Soccer(dic))
elif 'Tennis' == obj.__class__.__name__:
instance_list.append(Tennis(dic))
Another way to get something (not necessarily a class) from the current module by name:
this_module = sys.modules[__name__]
cls = getattr(this_module, "SomeClass")
If the point is to have a module function that returns a class from the same module by it's name, you could indeed rewrite it in a much less convoluted way:
# mymodule.py
class Foo(object):
pass
def get_class(name):
return globals()[name]
# main.py
import mymodule
print(mymodule.get_class("Foo"))
Note that depending on your use case it might be safer to use an explicit dict of classes that are allowed to be looked up by mymodule.get_class(). You may really want to consider this option if the class name comes from user inputs and you know exactly which classes should be allowed.
Also note that for Django models classes you could also use apps.get_model(app_name, model_name) which lets you get models from any app.

Access parent object from submodule

I'm writing a module for accessing some data from a local SQLite Database, and would like the end-user functionality to work like this:
import pyMyDB
myDBobj = pyMyDB.MyDB( '/path/to/DB/file' ) # Instance of the class MyDB
User has simply created an object that connects to a database.
Then, depending on the need, I want to have different submodules the user can access to work on the data from the database. For example, Driving provides certain functions while Walking provides others, which I'd love to be accessed like so:
result = myDBobj.Driving.GetTachometerReading()
or
result = myDBobj.Walking.GetShoeType()
My question is about how to make the submodules Driving & Walking have access to the parent Object (not just the Parent module's class/functions, but the instantiated object).
If I make my file heirarchy something like this:
pyMyDB/
__init__.py # imports the below modules as so:
MyDB_class.py # imported as *, contains MyDB class definition
Driving.py # imported normally via `import Driving`
Walking.py # imported normally
where __init__.py imports MyDB_class.py (which contains the Database class) and also imports Driving/Walking.py, then
the user can do pyMyDB.Driving.some_func(), but some_func() won't actually have access to an instantiated MyDB object, right?
Has anyone come across a way to have the sub-modules access the instantiated object?
Here is my current solution. It seems overly complicated.
First, I have to use an additional globals.py file to overcome circular module imports (Like this hint).
In the Driving module I make a new class called Drv, which is used to make a duplicate of the MyDBobj, but also has the extra methods I want, such as Driving.GetTachometerReading().
Driving.py:
class DrvClass( MyDB ):
def __init__(self, MyDBobj):
self.attribute1 = MyDBobj.attr1
self.attribute2 = MyDBobj.attr2
.... # copy all attribute values!
def GetTachometerReading(self):
.... #some function here
Then, to accomplish the sub-indexing (MyDBobj.Driving.GetTach()), from within the Driving.py module, I add a Driving() method to the MyDB class via
def temp_driving(self):
return DrvClass( self ) # pass the MyDBobj
MyDB.Driving = temp_driving # add the above method to the MyDB class
So now a user can do: MyDBobj.Driving().GetTachometerReading(), where MyDBobj.Driving() returned the new DrvClass object that has the new GetTachometer() function. I don't like the fact that I must call Driving() as a function.
What do you think - is there a better/simpler way?
Btw the reason I want the MyDB class to be separate is because our access methods may change, without changing the analysis functions (Driving/Walking), or vice-versa. Thus I don't want to just add the MyDB access techniques directly to separate Driving & Walking modules.
Thanks in advance for your sage advice!
I think I might use a different access approach on the client side. If the clients used a protocol like this:
result = myDBobj.Driving_GetTachometerReading()
then it's straightforward to add this name into the class in the sub-module Driving.py:
import pyMyDB
def GetTachometerReading(self):
# self will be the MyDB instance
pyMyDB.MyDB.Driving_GetTachometerReading = GetTachometerReading
However, if you are set on your approach then I think it could be improved.As it is, you create a new instance of Driving for every call to a Driving function which is not good. However, we do need to create an instance when the MyDB itself is instantiated. Yet that seems tricky because at that time we don't seem to know which sub-modules to include. I have fixed that by having each sub-module inject a list of its methods into MyDB. Like this:
pyMyDB:
import functools
class MyDB(object):
submodule_methods = {}
def __init__(self):
for k,v in self.submodule_methods.items():
self.__dict__[k] = SubmodulePointer(self,v)
self.db_stuff = "test"
class SubmodulePointer(object):
def __init__(self,db,methods):
self.db = db
for name,func in methods.items():
self.__dict__[name] = functools.partial(func,db)
Then for each of the sub-modules, eg Driving we do:
import pyMyDB
def GetTachometerReading(self):
# self here is the db instance, as if this was a method on the db
print(self.db_stuff)
pyMyDB.MyDB.submodule_methods["Driving"] = {"GetTachometerReading":GetTachometerReading}
Then the client can just do:
import pyMyDB
import Driving
m = pyMyDB.MyDB()
m.Driving.GetTachometerReading()
As you wanted. A simpler approach, with a slightly more conventional style would be to make Driving a class of its own:
pyMyDB:
import functools
class MyDB(object):
submodule_classes = []
def __init__(self):
for c in self.submodule_classes:
self.__dict__[c.__name__] = c(self)
self.db_stuff = "test"
Then for each of the sub-modules, eg Driving we do:
import pyMyDB
class Driving(object):
def __init__(self,db):
self.db = db
def GetTachometerReading(self):
# self here is the Driving instance,
# but we have access to the db
print(self.db.db_stuff)
pyMyDB.MyDB.submodule_classes.append(Driving)
This means that the methods in the Driving class don't look like methods on MyDB but that could be an advantage. I'm not sure if that was something you wanted.

Is it possible in Python to make a set of methods of a class dependent on input of constructor?

I am reading this Genshi Tutorial and see there the following example:
from formencode import Schema, validators
class LinkForm(Schema):
username = validators.UnicodeString(not_empty=True)
url = validators.URL(not_empty=True, add_http=True, check_exists=False)
title = validators.UnicodeString(not_empty=True)
As far as I understand this example, we create a new class that inherits Schema class and this class contain three methods: username, url, title. However, I am not sure about the last because before I only saw methods created with def.
Anyway, my question is not about that. I would like to know if it is possible to make the definition of the class dynamic. For example, sometimes I do not want url or title to be in the class. It seems to be doable (I just use if and assign a value to url only if-statement is satisfied.
But what if I do not know in advance what fields I would like to have in the form? For example, now I have username, url and title. But what if later I would like to have city or age. Can I do something like that:
from formencode import Schema, validators
class LinkForm(Schema):
__init__(self, fields):
for field in fields:
condition = fields[field]
field = validators.UnicodeString(condition)
I think it will not work. Is there a work around in this case?
Yes, you can add methods to an instance dynamically. No, you can't do what you want.
You can bind methods to the instance in the initializer. Unfortunately what you have there are descriptors and those must be bound to the class.
I would go the other way round—first define all form fields that might be used, and delete unneeded ones later.
Provided that you have:
from formencode import Schema, validators
class LinkForm(Schema):
username = validators.UnicodeString(not_empty=True)
url = validators.URL(not_empty=True, add_http=True, check_exists=False)
title = validators.UnicodeString(not_empty=True)
you could do either this:
def xy():
my_form = LinkForm()
del my_form.url
…
… or this:
def xy():
class CustomLinkForm(LinkForm):
pass
if …:
del CustomLinkForm.url
…
Disclaimer: I am not familiar with FormEncode, so it might depend on its inner workings which of these two versions actually works.
of course you can have a constructor with some arguments after self and these arguments will be the value for some members of your class if you have for instance
__init__(self, fields):
self.fields = []
for field in fields:
self.fields = self.fields + field
see this in Dive into Python
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
Classes can (and should) have doc strings too, just like modules and
functions.
init is called immediately after an instance of the
class is created. It would be tempting but incorrect to call this the
constructor of the class. It's tempting, because it looks like a
constructor (by convention, init is the first method defined for
the class), acts like one (it's the first piece of code executed in a
newly created instance of the class), and even sounds like one (“init”
certainly suggests a constructor-ish nature). Incorrect, because the
object has already been constructed by the time init is called,
and you already have a valid reference to the new instance of the
class. But init is the closest thing you're going to get to a
constructor in Python, and it fills much the same role.
The first
argument of every class method, including init, is always a
reference to the current instance of the class. By convention, this
argument is always named self. In the init method, self refers to
the newly created object; in other class methods, it refers to the
instance whose method was called. Although you need to specify self
explicitly when defining the method, you do not specify it when
calling the method; Python will add it for you automatically.
init methods can take any number of arguments, and just like
functions, the arguments can be defined with default values, making
them optional to the caller. In this case, filename has a default
value of None, which is the Python null value.
Note that in the later example you learn how to deal with inherited class, calling __init()__ for this inherited class.
To answer your not-a-question about class or instance variables, see this
Variables defined in the class definition are class variables; they
are shared by all instances. To create instance variables, they can be
set in a method with self.name = value. Both class and instance
variables are accessible through the notation “self.name”, and an
instance variable hides a class variable with the same name when
accessed in this way. Class variables can be used as defaults for
instance variables, but using mutable values there can lead to
unexpected results. For new-style classes, descriptors can be used to
create instance variables with different implementation details.

Addressing instance name string in __init__(self) in Python

I am doing something like this:
class Class(object):
def __init__(self):
self.var=#new instance name string#
How do I make the __ init __ method of my instance to use the instance name string for 'c'? Say in case:
c=Class()
I want c.var equal to 'c'.
Thanks for your replies, I am implementing persistence and Class is persistent object's class. I want __ init __ to add an entry to the database when:
c=Class()
Then, suppose:
del c
Later on:
c=Class()
sholuld create an instance using data from database if there already is an entry 'c', otherwise create new entry.
Thanks for your replies, I am implementing persistence and Class is persistent object's class. I want __ init __ to add an entry to the database when:
c=Class()
Then, suppose:
del c
Later on:
c=Class()
sholuld create an instance using data from database if there already is an entry 'c', otherwise create new entry.
Python doesn't have variables, it has objects and names. When you do
c = Class()
you're doing two things:
Creating a new object of type Class
Binding the object to the name c in the current scope.
The object you created doesn't have any concept of a "variable name" -- If later you do
a = c
then the same object is accessible in exactly the same way using the names a and c. You can delete the name a, and the object would still exist.
If the objects you create need to have a name, the best way is to pass it to them explicitly,
class Class(object):
def __init__(self, name):
self.name = name
var = Class('var')
You can't do this. The reason for this is that the object of the class is created first, and only afterwards is this object bound to the name of the instance.
You can't (short of incredible hacks like examining the stack frame and inspecting the bytecode). There may not even be a name, or there could be multiple such names. What should be given for the following code fragments for instance:
l = [Class(), Class()]
a=b=c=d=Class()
I don't think this would be possible because the assignment to the variable of your new instance occours after the object is fully constructed and initialized and so you don't know the variable name it will be assigned to within init method
To persist data objects you need to use the database record's unique ID.
pesudo code because I don't know what database module you're using
import db # assume this is your db module
class Class(object):
def __init__(self):
self.id = None
self.name = None
def get_by_id(self, id):
records = db.execute('select * from table where id=%s' % str(id))
if records:
self.id = records[0]['id']
self.name = records[0]['name']
def save(self):
db.execute('update table set name=%s where id=%s' % (self.name, str(self.id)))
Again, this is pseudo code, the string injection technique I'm using is NOT advised as its fairly insecure, its just there to illustrate how to persist using classes with a db.
I am unaware of a way to access a variable's name programmatically without using deep reflection and a debugger. I do not think the information is available at runtime.
If you want to give instances a (unique?) name, you should probably make the initializer accept an extra argument.
def __init__(self, name):
self.name = name
And the caller should pass in the appropriate name:
c = Class("c")
This is a scope issue, you can't do what you're asking. Because c would be declared outside your class' scope, your instance is unaware of what its been named in code.
Perhaps if you can provide a broader explanation of what you're trying to accomplish a better solution can be suggested.
That isn't possible. You seem to be confusing variables and objects.
In any case there may well not be a variable:
e.g.
foo(Class())
Class().arbitraryMethod()
Or multiple:
a = b = Class()
I have the same thought several years ago. This is somekind of neat feature, but the language creator doesn't provide it. And I thought they are all fool to not discover this great feature.
But then come to think about that. I think the logic is impossible. say:
class Class(object):
def __init__(self):
self.instance_name.move() # self.instance_name refer to var
def move(self):
print "move"
var = Class()
now if the var is an array is that possible too ?
var[0] = Class() # i think it will get confused a bit
that's what i think of, i don't think that assigning the instance into itself is possible. and in some language I just sent the instance string into the object then using eval to execute the function

Categories

Resources