2009-02-13 27 views
104

dinamik olarak nasıl yüklenir Bir Python sınıfının bir dizesi verilir, ör. my_package.my_module.MyClass, yüklemek için en iyi yol nedir?Bir Python sınıfı

Başka bir deyişle, Java'da eşdeğer Class.forName()'u arıyorum, Python'da işlev. Google App Engine'de çalışması gerekiyor.

Tercihen bu bir dize olarak sınıfın FQN kabul eden bir fonksiyon olması ve sınıfın bir başvuru verir olacaktır: piton belgelerine

my_class = load_class('my_package.my_module.MyClass') 
my_instance = my_class() 
+0

Bir değişkene de sınıf referansı. – pjesi

+1

Bu, aşağıdakilerin bir kopyası gibi görünüyor: http://stackoverflow.com/questions/452969/does-python-have-an-equivalent-to-java-class-forname – cdleary

+0

Doğru bir kopyadır, bulmak için teşekkürler – pjesi

cevap

139

, burada istiyorum fonksiyonu var: bir paket dizesindeki ilk nokta geçmiş bir şey her ithalat sen modülün bir niteliktir, çünkü

def my_import(name): 
    components = name.split('.') 
    mod = __import__(components[0]) 
    for comp in components[1:]: 
     mod = getattr(mod, comp) 
    return mod 

basit __import__ çalışmaz nedeni im Taşıma işlemi. Böylece, böyle bir şey çalışmaz:

my_import('foo.bar.baz.qux') 

Veya örneğin durumunda:

klass = my_import('my_package.my_module.my_class') 
some_object = klass() 

__import__('foo.bar.baz.qux') 

Yukarıdaki fonksiyon şöyle demelisiniz

EDIT: Bu konuda biraz eğlendim. Ne temelde yapmak isteyen konum şudur: Bir boş fromlist varsa

from my_package.my_module import my_class 

yukarıdaki fonksiyon gereklidir. Böylece, uygun çağrı aşağıdaki gibi olacaktır:

mod = __import__('my_package.my_module', fromlist=['my_class']) 
klass = getattr(mod, 'my_class') 
+0

eğrisi yerine my_import'u ('my_package.my_module.my_class') denedim ancak hiçbir modülün my_class'ı bulunmasını sağlayın. Aramadan sonra sınıfı almak için gettattr'i kullanabiliyorsam Howe – pjesi

+0

Bu gariptir. İlk noktayı geçen her şey getattr kullanılarak çağrılır. Bir fark olmamalı. –

+1

Bunu anladım. Gönderi düzenlemesine bakın. –

-3
module = __import__("my_package/my_module") 
the_class = getattr(module, "MyClass") 
obj = the_class() 
+5

Bunun, __import__ işlevindeki bir hata nedeniyle çalıştığını unutmayın. Dosya yolları, __import__ işlevinde * kullanılmamalı ve python 2.6 ve üzeri çalışmaz: http://docs.python.org/whatsnew/2.6.html#porting-to-python-2-6 –

+0

ile "." "/" – Nick

25
def import_class(cl): 
    d = cl.rfind(".") 
    classname = cl[d+1:len(cl)] 
    m = __import__(cl[0:d], globals(), locals(), [classname]) 
    return getattr(m, classname) 
+5

Bu temiz çözüm! Kullanmayı düşünebilirsiniz: '(modulename, classname) = cl.rsplit ('.', 2)' – vdboor

+0

Bu harika) Farklı sınıflara sahip putiller paketi yaratmıştım, ayrıca sınıf ithal ediyordum. İsterseniz, o paketten kullanabilirsiniz. – Stan

+4

@vdboor 'rsplit ('.', 1)'? –

47
import importlib 

module = importlib.import_module('my_package.my_module') 
my_class = getattr(module, 'MyClass') 
my_instance = my_class() 
+0

çalışmıyor. import_module, sınıf olmayan bir modülü içe aktarır. – Xuan

+7

Modülü dinamik olarak içe aktardıktan sonra, –

+0

modülü üzerinden sınıfa erişebilirsiniz. Cevabımı daha kısa ve öz bir şekilde düzenledim. Bu, Python'da bir sınıf yüklemenin en iyi yoludur. –

72

Kendi rulo istemiyorsanız, tam olarak bunu yapar pydoc modülünde mevcut bir fonksiyonu vardır:

from pydoc import locate 
my_class = locate('my_package.my_module.MyClass') 

burada listelenen diğerlerine göre bu yaklaşımın avantajı locatesağlanan noktalı yolda herhangi piton nesne değil, j bulacaksınız olmasıdır doğrudan bir modül içinde bir nesne. Örneğin. my_package.my_module.MyClass.attr.

def locate(path, forceload=0): 
    """Locate an object by name or dotted path, importing as necessary.""" 
    parts = [part for part in split(path, '.') if part] 
    module, n = None, 0 
    while n < len(parts): 
     nextmodule = safeimport(join(parts[:n+1], '.'), forceload) 
     if nextmodule: module, n = nextmodule, n + 1 
     else: break 
    if module: 
     object = module 
    else: 
     object = __builtin__ 
    for part in parts[n:]: 
     try: 
      object = getattr(object, part) 
     except AttributeError: 
      return None 
    return object 

O pydoc.safeimport fonksiyonu dayanır: Onların tarifi ne meraklı iseniz

, burada fonksiyon.

"""Import a module; handle errors; return None if the module isn't found. 

If the module *is* found but an exception occurs, it's wrapped in an 
ErrorDuringImport exception and reraised. Unlike __import__, if a 
package path is specified, the module at the end of the path is returned, 
not the package at the beginning. If the optional 'forceload' argument 
is 1, we reload the module from disk (unless it's a dynamic extension).""" 
+1

Bu cevabı destekledim. BTW, burada da sadece bu için pydoc ithal tuhaf görünüyor güvenli bir şekilde var kodu: https://github.com/python/cpython/blob/aa8ea3a6be22c92e774df90c6a6ee697915ca8ec/Lib/pydoc.py#L288 – brianray

+0

Ben de bu cevabı kadar bastı Bu, tüm ilgili cevapların en iyisidir. –

+0

boş bir init işlevi tanımlamanız gerekir def __init __ (self, get_response = None): pass –

-2

Google App Engine yılında import_string adında bir webapp2 işlevi vardır edilir: Burada bunun için dokümanlar bulunmaktadır.Daha fazla bilgi için bkz: Eğer bir işleyici veya dize kullanabilirsiniz ya nerede Örneğin Bunun için https://webapp-improved.appspot.com/api/webapp2.html

Yani,

import webapp2 
my_class = webapp2.import_string('my_package.my_module.MyClass') 

webapp2.Route kullanılır.

1

Tamam, benim için işe yaradı yolu (Python 2.7 kullanıyorum) 'dir:

Sonra
a = __import__('file_to_import', globals(), locals(), ['*'], -1) 
b = a.MyClass() 

b sınıfının bir örneğidir 'Sınıfım'

Ben atamak gerekiyor
İlgili konular