Set variable as type of class

2019-08-22 01:55发布

问题:

I am trying to figure out how I can pass a variable as the declaration type (object) for a class in Python 3.

Example:

#class defintion
class TestClass(Document):
    test = IntField()

me = MongoEngine(app)
testInstance = TestClass(me.Document) # How do i pass the Document variable

I tried passing an instance of the MongoEngine variable as a variable to the TestClass but this isn't working properly?

回答1:

I think you need to structure your class slightly different. Don't put Document in the class definition as if the TestClass is a subclass of Document. In stead, declare the class as standard (object), and define an __init__ where you can pass a variable which can be used by the instance of the class after initiation:

class TestClass(object):

    def __init__(self, my_document):
        self.document = my_document
        # at this point  the self.document variable
        # is the same as the variable passed
        # when initiating the instance of the class

    def show_document(self):
        # do something with your document
        print(self.document)

me = MongoEngine(app)

# this will call __init__() passing the variable
test_instance = TestClass(me.Document)

# now do something with the class intance
test_instance.show_document()

[EDIT based on comment]

OP's comment:

Looking at the type(test_instance), Its not the same as a MongoEngine.Document. I am hoping to create a class of type 'Document' and pass in an instance of that type?

You can create classes which would take a parent class as object in the class definition. As I do not know MongoEngine I will make an example with list

A class defined as follows, will behave perfectly like a list, but if you do a type() it will come back as MyList:

class MyList(list):

    def __init__(self, *args, **kwargs):
        super(MyList, self).__init__(*args, **kwargs)

    def my_extra_function(self):
        print('hello world')

You can easily see this when using this class, first look at it as a list:

my_instance = MyList([1, 2, 3])

print(my_instance)
print(my_instance[::-1])

this will behave as if it was a list.

But when you do a type(), it will not return the same as list:

print(type(list))
print(type(list()))
print(type(MyList()))
print(type(my_instance))

output:

<class 'type'>
<class 'list'>
<class '__main__.MyList'>
<class '__main__.MyList'>

So even when you try to create a class with the MongoEngine.Document as parent object, the type() will still show you your own defined class.

class MyClass(MongoEngine.Document):

    def __init__(self, *args, **kwargs):
        super(MyClass, self).__init__(*args, **kwargs)

my_instance = MyClass('something')

If you do a type(my_instance) it will return your custom class, and not the parent object type.

Not sure how MongoEngine works, and if you can actually do something like this, so YMMV.

You can change the name type() is returning, by doing the following in my example class. Setting the self.__class__ in the __init__(). Like this:

class MyList(list):

    def __init__(self, *args, **kwargs):
        super(MyList, self).__init__(*args, **kwargs)
        self.__class__ = type('list', (list,),{})

    def my_extra_function(self):
        print('hello world', self)

my_instance = MyList([1, 2, 3])

print(type(list))
print(type(list()))
print(type(MyList()))
print(type(my_instance))

output:

<class 'type'>
<class 'list'>
<class '__main__.list'>
<class '__main__.list'>

If this trick works for MongoEngine.Document I do not know.