문자열을 Python 클래스 개체로 변환하시겠습니까?
Python 함수에 대한 사용자 입력으로 문자열을 지정하면 현재 정의된 네임스페이스에 해당 이름의 클래스가 있다면 클래스 객체를 가져오고 싶습니다.기본적으로 다음과 같은 결과를 얻을 수 있는 기능을 구현하고 싶습니다.
class Foo:
pass
str_to_class("Foo")
==> <class __main__.Foo at 0x69ba0>
이게, 정말 가능한 일인가요?
이것은 동작할 수 있습니다.
import sys
def str_to_class(classname):
return getattr(sys.modules[__name__], classname)
경고:
eval()
임의의 Python 코드를 실행하는 데 사용할 수 있습니다.사용해서는 안 됩니다.eval()
신뢰할 수 없는 문자열로.(신뢰할 수 없는 문자열에 대한 Python's eval() 보안 참조)
이게 제일 간단해 보여요.
>>> class Foo(object):
... pass
...
>>> eval("Foo")
<class '__main__.Foo'>
다음과 같은 작업을 수행할 수 있습니다.
globals()[class_name]
수업을 원하십니까?Baz
모듈 내에 있습니다.foo.bar
Python 2.7에서는,importlib.import_module()
이렇게 하면 Python 3으로 쉽게 전환할 수 있습니다.
import importlib
def class_for_name(module_name, class_name):
# load the module, will raise ImportError if module cannot be loaded
m = importlib.import_module(module_name)
# get the class, will raise AttributeError if class cannot be found
c = getattr(m, class_name)
return c
Python < 2.7의 경우:
def class_for_name(module_name, class_name):
# load the module, will raise ImportError if module cannot be loaded
m = __import__(module_name, globals(), locals(), class_name)
# get the class, will raise AttributeError if class cannot be found
c = getattr(m, class_name)
return c
용도:
loaded_class = class_for_name('foo.bar', 'Baz')
장고가 이걸 어떻게 처리하는지 봤어요
django.sys.loading에는 이 기능이 있습니다.
def import_string(dotted_path):
"""
Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import failed.
"""
try:
module_path, class_name = dotted_path.rsplit('.', 1)
except ValueError:
msg = "%s doesn't look like a module path" % dotted_path
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
module = import_module(module_path)
try:
return getattr(module, class_name)
except AttributeError:
msg = 'Module "%s" does not define a "%s" attribute/class' % (
module_path, class_name)
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
다음과 같이 사용할 수 있습니다.import_string("module_path.to.all.the.way.to.your_class")
import sys
import types
def str_to_class(field):
try:
identifier = getattr(sys.modules[__name__], field)
except AttributeError:
raise NameError("%s doesn't exist." % field)
if isinstance(identifier, (types.ClassType, types.TypeType)):
return identifier
raise TypeError("%s is not a class." % field)
구식 및 신식 클래스가 모두 정확하게 처리됩니다.
문자열로 만든 클래스를 가져오려면 사전에 저장(또는 적절한 단어, 참조)해야 합니다.따라서 더 높은 수준의 클래스 이름을 지정하고 원치 않는 클래스가 노출되는 것을 방지할 수 있습니다.
예를 들어, Python에서 배우 클래스가 정의되어 사용자 입력으로 다른 일반 클래스가 도달하는 것을 피하고 싶은 게임입니다.
또 다른 접근법(아래 예시와 같이)은 완전히 새로운 클래스를 만듭니다.dict
위. 이것은 다음과 같습니다.
- 복수의 클래스 홀더를 보다 쉽게 편성할 수 있도록 한다(배우 클래스용과 음향 타입용).
- 보유자와 보유 중인 클래스 모두를 더 쉽게 수정할 수 있도록 한다.
- 또한 클래스 메서드를 사용하여 dict에 클래스를 추가할 수 있습니다. (아래 추상화는 실제로 필요하지 않지만, 단지...을 위한 것입니다.'정보')를 참조해 주세요.
예:
class ClassHolder:
def __init__(self):
self.classes = {}
def add_class(self, c):
self.classes[c.__name__] = c
def __getitem__(self, n):
return self.classes[n]
class Foo:
def __init__(self):
self.a = 0
def bar(self):
return self.a + 1
class Spam(Foo):
def __init__(self):
self.a = 2
def bar(self):
return self.a + 4
class SomethingDifferent:
def __init__(self):
self.a = "Hello"
def add_world(self):
self.a += " World"
def add_word(self, w):
self.a += " " + w
def finish(self):
self.a += "!"
return self.a
aclasses = ClassHolder()
dclasses = ClassHolder()
aclasses.add_class(Foo)
aclasses.add_class(Spam)
dclasses.add_class(SomethingDifferent)
print aclasses
print dclasses
print "======="
print "o"
print aclasses["Foo"]
print aclasses["Spam"]
print "o"
print dclasses["SomethingDifferent"]
print "======="
g = dclasses["SomethingDifferent"]()
g.add_world()
print g.finish()
print "======="
s = []
s.append(aclasses["Foo"]())
s.append(aclasses["Spam"]())
for a in s:
print a.a
print a.bar()
print "--"
print "Done experiment!"
그러면 다음 정보가 반환됩니다.
<__main__.ClassHolder object at 0x02D9EEF0>
<__main__.ClassHolder object at 0x02D9EF30>
=======
o
<class '__main__.Foo'>
<class '__main__.Spam'>
o
<class '__main__.SomethingDifferent'>
=======
Hello World!
=======
0
1
--
2
6
--
Done experiment!
그것들로 할 수 있는 또 다른 재미있는 실험은 피클을 절이는 방법을 추가하는 것이다.ClassHolder
그럼 지금까지의 모든 수업에서 절대 빠지지 않을 거예요:^)
업데이트: 데코레이터를 줄임말로 사용할 수도 있습니다.
class ClassHolder:
def __init__(self):
self.classes = {}
def add_class(self, c):
self.classes[c.__name__] = c
# -- the decorator
def held(self, c):
self.add_class(c)
# Decorators have to return the function/class passed (or a modified variant thereof), however I'd rather do this separately than retroactively change add_class, so.
# "held" is more succint, anyway.
return c
def __getitem__(self, n):
return self.classes[n]
food_types = ClassHolder()
@food_types.held
class bacon:
taste = "salty"
@food_types.held
class chocolate:
taste = "sweet"
@food_types.held
class tee:
taste = "bitter" # coffee, ftw ;)
@food_types.held
class lemon:
taste = "sour"
print(food_types['bacon'].taste) # No manual add_class needed! :D
네, 할 수 있어요.클래스가 글로벌 이름 공간에 있다고 가정하면 다음과 같은 작업이 수행됩니다.
import types
class Foo:
pass
def str_to_class(s):
if s in globals() and isinstance(globals()[s], types.ClassType):
return globals()[s]
return None
str_to_class('Foo')
==> <class __main__.Foo at 0x340808cc>
임의의 코드 실행이나 바람직하지 않은 사용자가 전달한 이름의 관점에서 허용 가능한 함수/클래스 이름 목록을 가질 수 있으며, 입력이 목록의 이름과 일치하면 eval'd가 됩니다.
PS: 알아요...좀 늦었네요...나중에 이걸 우연히 발견하는 사람을 위한 거예요
저는 importlib을 사용하는 것이 가장 효과적이었습니다.
import importlib
importlib.import_module('accounting.views')
Import하는 python 모듈에 문자열 도트 표기가 사용됩니다.
언급URL : https://stackoverflow.com/questions/1176136/convert-string-to-python-class-object
'programing' 카테고리의 다른 글
라이브러리를 사용하지 않고 jwt 토큰을 javascript로 디코딩하는 방법은 무엇입니까? (0) | 2022.09.18 |
---|---|
존재하지 않는 MySQL 가입 (0) | 2022.09.18 |
reactjs를 사용하여 원시 html 렌더링 (0) | 2022.09.18 |
phpmailer: "응답처" 주소만 사용하여 회신합니다. (0) | 2022.09.18 |
PHP simpleXML 포맷된 방법으로 파일을 저장하는 방법 (0) | 2022.09.18 |