Python : 클래스가 중첩되어 있는지 확인하십시오
-
11-07-2019 - |
문제
유형을 매개 변수로 가져 오는 Python 메소드가 있다고 가정합니다. 주어진 유형이 중첩 클래스인지 확인할 수 있습니까?
예 :이 예에서 :
def show_type_info(t):
print t.__name__
# print outer class name (if any) ...
class SomeClass:
pass
class OuterClass:
class InnerClass:
pass
show_type_info(SomeClass)
show_type_info(OuterClass.InnerClass)
전화를 원합니다 show_type_info(OuterClass.InnerClass)
또한 내부 클래스는 외부 외부 내부에 정의되어 있음을 보여줍니다.
해결책
Afaik, 수업과 다른 정보가 주어지면 중첩 된 수업인지 아닌지 알 수 없습니다. 하지만, 여기를 봐 데코레이터를 사용하여이를 결정하는 방법.
문제는 중첩 클래스가 단순히 외부 클래스의 속성 인 일반 클래스라는 것입니다. 당신이 예상 할 수있는 다른 솔루션은 아마 그렇지 않을 것입니다. inspect.getmro
, 예를 들어, 외부 클래스가 아닌 기본 클래스 만 제공합니다.
또한 중첩 클래스는 거의 필요하지 않습니다. 나는 그것이 당신이 하나를 사용하고 싶은 유혹을 느낀 각 경우에서 그것이 좋은 접근법인지 여부를 강력하게 재고 할 것입니다.
다른 팁
내부 클래스는 파이썬에서 특별한 특수 기능을 제공하지 않습니다. 정수 나 문자열 속성과 다르지 않은 클래스 객체의 속성 일뿐입니다. 외부 클래스/내부 등급 예제는 다음과 같이 정확하게 다시 작성할 수 있습니다.
class OuterClass(): pass
class InnerClass(): pass
OuterClass.InnerClass= InnerClass
Innerclass는 다른 클래스 내에서 선언되었는지 여부를 알 수 없습니다. 왜냐하면 그것은 단지 평범한 가변 바인딩이기 때문입니다. 바운드 방법을 주인 '자기'에 대해 알리는 마법은 여기에 적용되지 않습니다.
John이 게시 한 링크의 Innerclass Decorator Magic은 흥미로운 접근 방식이지만 나는 그것을 사용하지 않을 것입니다. 각 외부 객체에 대해 생성하는 클래스를 캐시하지 않으므로 Outerinstance.innerclass를 호출 할 때마다 새 내부를 얻을 수 있습니다.
>>> o= OuterClass()
>>> i= o.InnerClass()
>>> isinstance(i, o.InnerClass)
False # huh?
>>> o.InnerClass is o.InnerClass
False # oh, whoops...
또한 getAttr/setattr을 사용하여 내부 클래스에서 외부 클래스 변수를 이용할 수 있도록하는 Java 동작을 복제하는 방식은 매우 끔찍하며 실제로 불필요합니다 (더 많은 pythonic 방법은 i .__ 외부 __. attr art를 명시 적으로 부르는 것입니다).
실제로 중첩 된 클래스는 다른 클래스와 다르지 않습니다. 단지 최상위 네임 스페이스 (다른 클래스 내부) 외에 다른 곳에서 정의됩니다. 설명을 "중첩"에서 "비 탑 레벨"으로 수정하면 필요한 것에 충분히 가까워 질 수 있습니다.
예 :
import inspect
def not_toplevel(cls):
m = inspect.getmodule(cls)
return not (getattr(m, cls.__name__, []) is cls)
이것은 일반적인 경우에는 효과가 있지만 정의 후 클래스의 이름이 바뀌거나 조작되는 상황에서 원하는 것을 수행하지 않을 수 있습니다. 예를 들어:
class C: # not_toplevel(C) = False
class B: pass # not_toplevel(C.B) = True
B=C.B # not_toplevel(B) = True
D=C # D is defined at the top, but...
del C # not_toplevel(D) = True
def getclass(): # not_toplevel(getclass()) = True
class C: pass
답변 해 주셔서 감사합니다.
메타 클라스를 사용 하여이 가능한 솔루션을 발견했습니다. 나는 실제 필요보다 장애를 위해 더 많은 일을했으며, Python 3에는 적용 할 수없는 방식으로 이루어졌습니다.
어쨌든이 솔루션을 공유하고 싶습니다. 여기에 게시하고 있습니다.
#!/usr/bin/env python
class ScopeInfo(type): # stores scope information
__outers={} # outer classes
def __init__(cls, name, bases, dict):
super(ScopeInfo, cls).__init__(name, bases, dict)
ScopeInfo.__outers[cls] = None
for v in dict.values(): # iterate objects in the class's dictionary
for t in ScopeInfo.__outers:
if (v == t): # is the object an already registered type?
ScopeInfo.__outers[t] = cls
break;
def FullyQualifiedName(cls):
c = ScopeInfo.__outers[cls]
if c is None:
return "%s::%s" % (cls.__module__,cls.__name__)
else:
return "%s.%s" % (c.FullyQualifiedName(),cls.__name__)
__metaclass__ = ScopeInfo
class Outer:
class Inner:
class EvenMoreInner:
pass
print Outer.FullyQualifiedName()
print Outer.Inner.FullyQualifiedName()
print Outer.Inner.EvenMoreInner.FullyQualifiedName()
X = Outer.Inner
del Outer.Inner
print X.FullyQualifiedName()
당신이 직접 설정하지 않으면, 나는 수업이 중첩되어 있는지 판단 할 방법이 있다고 생각하지 않습니다. 어쨌든 파이썬 클래스는 네임 스페이스로 사용할 수 없거나 최소한 쉽지 않기 때문에 가장 좋은 방법은 단순히 다른 파일을 사용하는 것입니다.
Python 3.3부터 새로운 속성이 있습니다 __qualname__
, 클래스 이름뿐만 아니라 외부 클래스의 이름도 제공합니다.
샘플에서 이것은 다음과 같습니다.
assert SomeClass.__qualname__ == 'SomeClass'
assert OuterClass.InnerClass.__qualname__ == 'OuterClass.InnerClass'
만약에 __qualname__
수업의 '는' '가 포함되어 있지 않습니다. 외부 클래스입니다!