简体   繁体   中英

python3: convert string to type

I have a set of classes A , B , C in a "front end" package p1 . They all inherit from p1.X .

I have another set of classes A , B , C in a "back end" package p2 . They all inherit from p2.Y .

In p1.X , I set one backend, so that p1.A uses p2.A as backend, p1.B uses p2.B , etc. This mapping is done based on the class name in an inherited method.

Now, I suceed to have, for example, backend = "p2.A" (string), but when I try to eval this, python doesn't knows about p2 , even if this is imported earlier.

What did I do wrong? Should I import inside the eval? Should like spaghetti code... Do you have a better idea?

Thanks.

PS: I currently have something like this in the "parent" p1.X class, which is awful, but good to clarify what I want:

def getBackendClass(self):
    myClass = ... # (class without package name)
    if myClass == "A":
           return p2.A
    elif myClass == "B":
           return p2.B
    ...

Little hacky solution, but should work, and is not hardcoded.

p2.py:

class Y(object):
    @classmethod
    def fromString(cls, s):
        cls_name = s.split(".")[1]
        for c in cls.__subclasses__():
            if c.__name__() == cls_name:
                return c()
        raise ValueError("%s not found in subclasses" % s)

Perhaps you mean something like this? Whenever the backend_class attribute is fetched it will call it's __get__ method and return the result of that call. The BackendClassFetcher is known as a non-data descriptor.

package1/m1.py

from . import p2

class BackendClassFetcher:
    def __get__(self, obj, objtype):
        return getattr(p2, objtype.__name__)

class Parent:
    backend_class = BackendClassFetcher()    
class A(Parent): pass
class B(Parent): pass
class C(Parent): pass

for cls in [A,B,C]:
    obj = cls()
    print(cls, cls.backend_class, obj.backend_class)

package1/m2.py

class Parent: pass
class A(Parent): pass
class B(Parent): pass
class C(Parent): pass

You can use import_module . Documentation

sample:

from importlib import import_module

path = "p2.A"
cls_name = path.split('.')[-1]
module_path = ".".join(path.split('.')[:-1])

module = import_module(module_path)
cls = getattr(module, cls_name)

Good luck.

Thanks a lot. I've made a mix of all your answers, leading the following code in the front end:

import backend

class Parent:
    @property
    def backend_class(self):
        return getattr(backend, self.__class__.__name__)

class A(Parent):
    pass

if __name__ == "__main__":
    instance = A()
    backendInstance = instance.backend_class()

Comment about cython: the backend must be imported, not cimported, even if "pure cython" cdef classes/ cpdef methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM