Muszę wziąć argument w postaci ciągu znaków i utworzyć obiekt klasy nazwanej w tym ciągu w Pythonie. W Javie użyłbym Class.forName().newInstance()
. Czy istnieje odpowiednik w Pythonie?
Dzięki za odpowiedzi. Aby odpowiedzieć tym, którzy chcą wiedzieć, co robię: Chcę użyć argumentu wiersza poleceń jako nazwy klasy i utworzyć jej instancję. Właściwie programuję w Jythonie i tworzę instancje klas Java, stąd Java-ność tego pytania. getattr()
działa świetnie. Dzięki wielkie.
java
python
class
instantiation
Jason
źródło
źródło
importlib.import
aby zapoznać się z przykładem użycia , które zostało przeniesione z pythona 3 do 2.7 ( docs.python.org/2/library/importlib.html )Odpowiedzi:
Odbicie w Pythonie jest dużo łatwiejsze i znacznie bardziej elastyczne niż w Javie.
Polecam przeczytanie tego poradnika
Nie ma bezpośredniej funkcji (o której wiem), która pobiera w pełni kwalifikowaną nazwę klasy i zwraca klasę, jednak masz wszystkie elementy potrzebne do jej zbudowania i możesz je połączyć.
Jedna rada: nie próbuj programować w stylu Java, gdy jesteś w Pythonie.
Jeśli potrafisz wyjaśnić, co próbujesz zrobić, może pomożemy Ci znaleźć bardziej pytoniczny sposób zrobienia tego.
Oto funkcja, która robi to, co chcesz:
Możesz użyć wartości zwracanej przez tę funkcję, tak jakby była ona samą klasą.
Oto przykład użycia:
Jak to działa?
Używamy
__import__
do importowania modułu, który zawiera klasę, co wymagało, abyśmy najpierw wyodrębnili nazwę modułu z w pełni kwalifikowanej nazwy. Następnie importujemy moduł:W tym przypadku
m
będzie odnosić się tylko do modułu najwyższego poziomu,Na przykład, jeśli twoja klasa mieszka w
foo.baz
module,m
będzie to moduł.foo
Możemy łatwo uzyskać odniesienie do
foo.baz
usinggetattr( m, 'baz' )
Aby dostać się z modułu najwyższego poziomu do klasy, należy rekurencyjnie użyć
gettatr
na częściach nazwy klasyPowiedz na przykład, że jeśli nazwa klasy to
foo.baz.bar.Model
, robimy to:Oto, co dzieje się w tej pętli:
Na końcu pętli
m
będzie odniesienie do klasy. Oznacza to, żem
jest to właściwie klasa sama w sobie, możesz na przykład:źródło
__import__
istnieje. Projekty takie jak Django, które wykonują magię ładowania modułów, używają jej przez cały czas. Niezła odpowiedź.get_class = lambda name: reduce(getattr, name.split('.')[1:], __import__(name.partition('.')[0]))
. Chociaż „object.from_name” może być lepszą nazwą. Przykłady: get_class ('decimal.Decimal'), get_class (nazwa_modułu).Zakładając, że zajęcia są w Twoim zakresie:
Inaczej:
Edycja: Uwaga, nie możesz nadać getattr nazwy takiej jak „foo.bar”. Musisz to podzielić według. i wywołaj getattr () na każdym elemencie od lewej do prawej. To poradzi sobie z tym:
źródło
attrs = 'foo.bar.baz'.split('.'); fooBar = reduce(getattr, attrs[1:], __import__(attrs[0]))
module, _, attrs = 'foo.bar.baz'.partition('.'); fooBar = reduce(getattr, attrs, __import__(module))
Stosowanie
źródło
Jeszcze inna realizacja.
źródło
if module_name
LBYL jest dość redudant, ponieważ błąd pojawi się, jeśli po prostu usunąć te linie to:ValueError: Empty module name
.Wygląda na to, że podchodzisz do tego od środka, a nie od początku. Co tak naprawdę próbujesz zrobić? Znalezienie klasy skojarzonej z danym ciągiem znaków jest środkiem do celu.
Jeśli wyjaśnisz swój problem, który może wymagać Twojej własnej mentalnej refaktoryzacji, może pojawić się lepsze rozwiązanie.
Na przykład: Czy próbujesz załadować zapisany obiekt na podstawie jego nazwy typu i zestawu parametrów? Python pisze to unpickling i powinieneś spojrzeć na moduł pikle . I chociaż proces odbierania przebiega dokładnie tak, jak opisujesz, nie musisz martwić się, jak to działa wewnętrznie:
źródło
Znajduje się w standardowej bibliotece Pythona jako unittest.TestLoader.loadTestsFromName. Niestety metoda wykonuje dodatkowe czynności związane z testami, ale ten pierwszy ha wygląda na nadający się do ponownego użycia. Edytowałem go, aby usunąć funkcjonalność związaną z testem:
źródło
Musiałem pobrać obiekty dla wszystkich istniejących klas w
my_package
. Więc importuję wszystkie niezbędne klasy domy_package
plików__init__.py
.Więc moja struktura katalogów jest następująca:
A mój
__init__.py
wygląd wygląda tak:Następnie tworzę taką funkcję:
Gdzie
module_name = 'my_package'
sprawdź dokument: https://docs.python.org/3/library/inspect.html#inspect.getmembers
źródło