Python ImportError Keyword Argument - python

I have the following problem.
I want to have an object class, which takes as superclass a predefined object as keyword argument.
But I'm getting the error:
ImportError: cannot import name Object
Code:
import Object
class Object:
defaultobject = Object('defaultobject', None)
def __init__(self, name, superclass = defaultobject):
self.__name = name
self.__superclass = superclass

You cannot import the module you are in. You'll have to move the Object() instantiation to after the class definition:
class Object:
defaultobject = None
def __init__(self, name, superclass=None):
self.__name = name
if superclass is None:
superclass = self.defaultobject
if superclass is None
# No default set yet, use `self` instead (it'll *be* the default)
superclass = self
self.__superclass = superclass
Object.defaultobject = Object('defaultobject', None)
You can always add more attributes to a class definition, but to create an instance of a class you first need to have defined it.
The superclass is None dance is needed, because you otherwise have a catch-22 here; you cannot create an instance of Object without setting Object.defaultobject first. Which you cannot do, because you haven't created the default yet.

This issue can be solved by removing the import library from parent class which is also imported by some of its child classes. if your child class is also using import object then removing that from parent will solve the issue.

Related

What is the best way to change the class that is called by an inherited method after class initialization in Python?

I am attempting to create a parallel class structure in two separate modules, where the methods of classes in one module e.g. source.py are registered to identically named modules in receiving.py via inheritance.
My issue is that if an inherited method in receiving.py calls another class in the module, it will point back to the class in source.py, and not in receiving.py. I understand this is expected, but how can I change which class the method points to during or after mapping, so the method in the receiving.py class will call the class from receiving.py.
Here is a schematic to help illustrate the problem. schematic
Minimally sufficient example:
source.py
class Foo:
origin = 'src'
#classmethod
def get_origin(cls):
return cls.origin
#classmethod
def get_origin_bar(cls):
return Bar.origin
class Bar:
origin = 'src'
receiving.py
class Tag:
pass
class Foo(Tag):
origin = 'rec'
class Bar(Tag):
origin = 'rec'
def register_bases(base, module):
"""
Recursive function that adds __bases__ from DataJoint Tables in base to matching classes in module.
:param base (module): source module with classes to.
:param module (module): mapping between classes and methods
"""
for name in dir(base):
base_cls = getattr(base, name)
module_cls = getattr(module, name) if hasattr(module, name) else None
if module_cls and inspect.isclass(module_cls) and issubclass(module_cls, receiving.Tag):
assert base_cls not in module_cls.__bases__, f'Class "{name}" of base already in __base__ of module.'
module_cls.__bases__ = (base_cls, *module_cls.__bases__)
register_bases(base_cls, module_cls)
import inspect
import source, receiving
# Before registering bases
receiving.Foo.get_origin()
-> AttributeError: type object 'Foo' has no attribute 'get_origin'
receiving.Foo.get_origin_bar()
-> AttributeError: type object 'Foo' has no attribute 'get_origin_bar'
# register bases
register_bases(source, receiving)
# after registering bases
receiving.Foo.get_origin()
-> 'rec'
receiving.Foo.get_origin_bar()
-> 'src'
What I need is for the last line to say 'rec', indicating that method get_origin_bar called receiving.Bar.origin instead of source.Bar.origin.

Class instance as class variable in python

I am making a class which I would like to have as a class member of a separate class so that all instances of this second class can access the first class. At the moment I have something which looks like this:
class A:
def __init__(self):
print "In Constructor!"
class B:
ClassA = ''
def __init__(self, InstanceA):
self.ClassA = InstanceA
However, I get complaints saying "str object has no attribute..." when I try and use the ClassA class variable. Is there a way to construct class B with an argument of InstanceA and then somehow set it to be a class variable? Or any other solution for that matter!
You are not assigning the class attribute in B.__init__, just setting a new instance attribute - B.ClassA is still '' (None would be a more sensible starting value, by the way).
The minimal fix is:
class B:
ClassA = None
def __init__(self, InstanceA):
self.__class__.ClassA = InstanceA # or B.ClassA = ...
However, note that this changes the class attribute every time you create a new instance.
Based on your comments, something like this may be more helpful:
class B:
ClassA = None
#classmethod
def set_class_attr(cls, instance):
cls.ClassA = instance
Which you can then use like:
B.set_class_attr(A()) # set class attribute once
b = B() # don't need to pass in new A instances when creating B instances
b.ClassA. # ...
Depending on the behaviour you want, you can check in that classmethod whether the instance has already been set and e.g. raise an error if the user tries to reset it.

Is it possible to change the name of a class (type) with a python decorator?

I'm trying to autocode 100's of database table models by decorating my Django (ORM) models (class definitions) to derive their class names from the file name. But I think my "depth of decoration" is too shallow. Do I need a function def or class definition within my __call__ method? Can it not be done with something simple like this?
# decorators.py
import os
from inspect import get_module
class prefix_model_name_with_filename(object):
'Decorator to prefix the class __name__ with the *.pyc file name'
def __init__(self, sep=None):
self.sep = sep or ''
def __call__(self, cls):
model_name = os.path.basename(getmodule(cls).__file__).split('.')[0]
setattr(cls, '__name__', model_name + self.sep + getattr(cls, '__name__'))
return cls
Example usage of the decorator
# models.py
from django.db import models
import decorators
#decorators.prefix_model_name_with_filename
class ShipMeth(models.Model):
ship_meth = models.CharField(max_length=1, primary_key=True)
The model doesn't exist in the module definition with the new name and I can't use it without it looking in the decorator class (rather than the model class) to find attributes!
>>> from sec_mirror.models import ShipMeth
>>> ShipMeth.__name__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/Hobson/.virtualenvs/dev/lib/python2.7/site-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 ShipMeth.__name__
AttributeError: 'prefix_model_name_with_filename' object has no attribute '__name__'
Do I need to decorate the module somehow?
You're using the class itself as the decorator, so only its __init__ is called. Your __call__ is never called.
Use an instance instead:
#decorators.prefix_model_name_with_filename()
About your updated question: A decorator can't change the actual name used to refer to an object in the enclosing namespace. (You can brute-force it by sticking a new name into a particular namespace, but it's up to you to ensure that the namespace you put the name into is the one where the object was originally defined.) The decorator syntax:
#deco
class Foo(object):
...
Is equivalent to
class Foo(object):
...
Foo = deco(Foo)
Note that the last line says Foo =, because the original class was defined with class Foo. You can't change that. The decorated object is always reassigned to the same name it originally had.
There are hackish ways to get around this. You can make your decorator write a new name to the global namespace, or even look at the decorated object's __module__ attribute and write a new name to that namespace. However, this isn't really what decorators are for, and it's going to make your code confusing. Decorators are for modifying/wrapping objects, not modifying the namespaces from which those objects are accessed.
Maybe that's the work for a metaclass:
import os
def cls_changer(name, parents, attrs):
model_name = os.path.basename(__file__).split('.')[0]
return type(model_name+name, parents, attrs)
class A(object):
__metaclass__ = cls_changer
pass
print A.__name__
The previous example just create new classes with the name changed but if you want your module to reflect the changes you need to this (Note my python script is named untitled0.py):
import os
def cls_changer(name, parents, attrs):
model_name = os.path.basename(__file__).split('.')[0]
res = type(model_name+name, parents, attrs)
gl = globals()
gl[model_name+name] = res
return res
class A(object):
__metaclass__ = cls_changer
pass
print A.__name__
print untitled0A
Output:
untitled0A
<class '__main__.untitled0A'>

#classmethod with Abstract Base Class

I have an Abstract Base Class and subclasses defined as follows (Python 2.7):
import abc
import MyDatabaseModule
class _DbObject(object):
__metaclass__ = abc.ABCMeta
def _GetObjectType(self):
raise NotImplementedError, "Please override in the derived class"
ObjectType = abc.abstractproperty(_GetObjectType, None)
class Entry(_DbObject):
_objectTypeID = 'ENTRY'
def _GetObjectType(self):
return MyDatabaseModule.DoesSomethingWith(self._objectTypeID)
ObjectType = property(_GetObjectType, None)
This works fine, meaning that the base class _DbObject cannot be instantiated because it has only an abstract version of the property getter method.
try:
dbObject = _DbObject()
print "dbObject.ObjectType: " + dbObject.ObjectType
except Exception, err:
print 'ERROR:', str(err)
Now I can do:
entry = Entry()
print entry.ObjectType
to get access to the ObjectType property. However, what I would like to be able to do is just:
print Entry.ObjectType
However, wherever I try to insert #classmethod, I get the error classmethod object is not callabale.
So, the magic for the way "property" works in Python is implemented using the descriptor protocol - property itself if a powerful built-in that provides a descriptor that works well for instances, not classes as you had seen.
So, you need a "class property" - the property built-in can't give you that, but the descriptor protocol can. What the descriptor protocol says is that whenever an attribute is retrieved from the class, if it is an object with a __get__ method, that method is called with "self, instance, owner" - and if it is retrieved from the class, instead of from an instance, the "instance" parameter is set to None.
BTW, as stated by #Constantinius, this does not have to do with the ABC's at all, just with you wanting a "class property".
class classproperty(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return self.func(owner)
class Entry(_DbObject):
_objectTypeID = 'ENTRY'
def _GetObjectType(cls):
return MyDatabaseModule.DoesSomethingWith(cls._objectTypeID)
ObjectType = classproperty(_GetObjectType, None)
The problem is not your ABC but the simple fact, that there is no such thing as a classproperty in python, you have to create it on your own. Actually there is a good question + answer on SO about that. It actually should be no problem using it with your ABC aswell.

Accessing Parent Class' Property From Derived Class

I'm new to python and GAE and I thought python will act as any other OO language, but apparently not. How does __init__(self): function gives me different results in the following code?
class BaseHandler(webapp.RequestHandler):
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
user = User.get_by_key_name(cookie["uid"])
return self._current_user
class SubmitHandler(BaseHandler):
template_values = dict(facebook_app_id=FACEBOOK_APP_ID)
def __init__(self):
#throws error : AttributeError: 'SubmitHandler' object has no attribute 'request'
self.template_values['current_user'] = self.current_user
def get(self):
#this one function is error free
self.template_values['current_user'] = self.current_user
How do I access the class' parent property?
If you look at your SubmitHandler class you'll notice that it indeed does not have a request attribute -- at least, none you set, and none you give the parent class a chance to set. Perhaps what you need to do is call the parentclass __init__ method before you try to access self.current_user.
As a side note, you should realize that the template_values dict you define inside the SubmitHandler class there is a class attribute, and thus shared between all instances of the class. Since you assign it something instance-specific in your __init__, you probably mean for it to be an instance attribute instead. Assign it to self.template_values in your __init__ method.
There's nothing particularly different about Python's object inheritance.
By defining __init__, you have told Python that this is all that needs to be done to initialize the object. You're therefore denying it the chance to run the superclass's initialization code. You need to call super:
def __init__(self, *args, **kwargs):
super(SubmitHandler, self).__init__(*args, **kwargs)
self.template_values['current_user'] = self.current_user
This might however not solve your problem - you're failing to take into account the possibility that self.request is initialized at another point in the program, which is why it works by the time get is called.
self.request and self.response are not set by the class constructor in webapp. They're set later, when the framework calls the handler's initialize method. You can override this, just make sure you call the parent class's initialize before doing anything else.

Categories

Resources