如何从内部类访问外部类?

2025-02-12 10:04:00
admin
原创
72
摘要:问题描述:我遇到了这样的情况......class Outer(object): def some_method(self): # do something class Inner(object): def __init__(self): ...

问题描述:

我遇到了这样的情况......

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            self.Outer.some_method()    # <-- this is the line in question

我如何Outer从类中访问该类的方法Inner


解决方案 1:

您正在尝试从内部类实例访问外部类实例。因此,只需使用工厂方法构建内部实例并将外部实例传递给它。

class Outer(object):

    def createInner(self):
        return Outer.Inner(self)

    class Inner(object):
        def __init__(self, outer_instance):
            self.outer_instance = outer_instance
            self.outer_instance.somemethod()

        def inner_method(self):
            self.outer_instance.anothermethod()

解决方案 2:

嵌套类的方法不能直接访问外部类的实例属性。

请注意,即使创建了内部类的实例,也不一定存在外部类的实例。

事实上,通常建议不要使用嵌套类,因为嵌套并不意味着内部类和外部类之间存在任何特定的关系。

解决方案 3:

也许我疯了,但这确实看起来很容易——关键是让你的内部类成为外部类的方法......

def do_sthg(self):
    ...

def mess_around(self):

    outer_class_self = self

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.do_sthg()

另外......“self”仅按惯例使用,因此您可以这样做:

def do_sthg(self):
    ...

def mess_around(outer_class_self):

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.do_sthg()

可能有人会反对说你不能从外部类之外创建这个内部类……但事实并非如此:

class Bumblebee():

    def do_sthg(self):
        print "sthg"
    
    def give_me_an_inner_class(outer_class_self):

        class Mooble():
            def do_sthg_different(self):
                print "something diff
"
                outer_class_self.do_sthg()
        return Mooble
    

然后,在几英里之外的某个地方:

blob = Bumblebee().give_me_an_inner_class()()
blob.do_sthg_different()    

甚至稍微推一下船并扩展这个内部类(注意:要开始super()工作,您必须将 的类签名更改Moobleclass Mooble(object))。

class InnerBumblebeeWithAddedBounce(Bumblebee().give_me_an_inner_class()):
    def bounce(self):
        print "bounce"
    
    def do_sthg_different(self):
        super(InnerBumblebeeWithAddedBounce, self).do_sthg_different()
        print "and more different"
    

ibwab = InnerBumblebeeWithAddedBounce()    
ibwab.bounce()
ibwab.do_sthg_different()

之后

mrh1997 提出了一个关于使用此技术实现的内部类的非公共继承的有趣观点。但解决方案似乎非常简单:

class Fatty():
    def do_sthg(self):
        pass
    
    class InnerFatty(object):
        pass
            
    def give_me_an_inner_fatty_class(self):
        class ExtendedInnerFatty(Fatty.InnerFatty):
            pass
        return ExtendedInnerFatty
                
fatty1 = Fatty()
fatty2 = Fatty()

innerFattyClass1 = fatty1.give_me_an_inner_fatty_class()
innerFattyClass2 = fatty2.give_me_an_inner_fatty_class()

print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))

解决方案 4:

我发现了这一点。

调整以适合您的问题:

class Outer(object):
    def some_method(self):
        # do something

    class _Inner(object):
        def __init__(self, outer):
            outer.some_method()
    def Inner(self):
        return _Inner(self)

我相信你可以以某种方式为此写一个装饰器或类似的东西

相关:python 内部类的用途是什么?

解决方案 5:

迟到了几年......但为了扩展@mike rodent的精彩答案,我在下面提供了我自己的例子,显示了他的解决方案有多么灵活,以及为什么它应该是(或应该)被接受的答案。

Python 3.7

class Parent():

    def __init__(self, name):
        self.name = name
        self.children = []

    class Inner(object):
        pass

    def Child(self, name):
        parent = self
        class Child(Parent.Inner):
            def __init__(self, name):
                self.name = name
                self.parent = parent
                parent.children.append(self)
        return Child(name)



parent = Parent('Bar')

child1 = parent.Child('Foo')
child2 = parent.Child('World')

print(
    # Getting its first childs name
    child1.name, # From itself
    parent.children[0].name, # From its parent
    # Also works with the second child
    child2.name,
    parent.children[1].name,
    # Go nuts if you want
    child2.parent.children[0].name,
    child1.parent.children[1].name
)

print(
    # Getting the parents name
    parent.name, # From itself
    child1.parent.name, # From its children
    child2.parent.name,
    # Go nuts again if you want
    parent.children[0].parent.name,
    parent.children[1].parent.name,
    # Or insane
    child2.parent.children[0].parent.children[1].parent.name,
    child1.parent.children[1].parent.children[0].parent.name
)


# Second parent? No problem
parent2 = Parent('John')
child3 = parent2.Child('Doe')
child4 = parent2.Child('Appleseed')

print(
    child3.name, parent2.children[0].name,
    child4.name, parent2.children[1].name,
    parent2.name # ....
)

输出:

Foo Foo World World Foo World
Bar Bar Bar Bar Bar Bar Bar
Doe Doe Appleseed Appleseed John

再次,这是一个非常精彩的回答,向你致敬,迈克!

解决方案 6:

您可以使用元类轻松访问外部类:创建外部类后,检查任何类的属性字典(或应用您需要的任何逻辑 - 我的只是简单的例子)并设置相应的值:

import six
import inspect


# helper method from `peewee` project to add metaclass
_METACLASS_ = '_metaclass_helper_'
def with_metaclass(meta, base=object):
    return meta(_METACLASS_, (base,), {})


class OuterMeta(type):
    def __new__(mcs, name, parents, dct):
        cls = super(OuterMeta, mcs).__new__(mcs, name, parents, dct)
        for klass in dct.values():
            if inspect.isclass(klass):
                print("Setting outer of '%s' to '%s'" % (klass, cls))
                klass.outer = cls

        return cls


# @six.add_metaclass(OuterMeta) -- this is alternative to `with_metaclass`
class Outer(with_metaclass(OuterMeta)):
    def foo(self):
        return "I'm outer class!"

    class Inner(object):
        outer = None  # <-- by default it's None

        def bar(self):
            return "I'm inner class"


print(Outer.Inner.outer)
>>> <class '__main__.Outer'>
assert isinstance(Outer.Inner.outer(), Outer)

print(Outer().foo())
>>> I'm outer class!
print(Outer.Inner.outer().foo())
>>> I'm outer class!
print(Outer.Inner().outer().foo())
>>> I'm outer class!
print(Outer.Inner().bar())
>>> I'm inner class!

使用这种方法,您可以轻松地将两个类绑定并相互引用。

解决方案 7:

我根据这个问题的另一个答案中的一个好主意,创建了一些 Python 代码来从其内部类中使用外部类。我认为它很短、简单且易于理解。

class higher_level__unknown_irrelevant_name__class:
    def __init__(self, ...args...):
        ...other code...
        # Important lines to access sub-classes.
        subclasses = self._subclass_container()
        self.some_subclass = subclasses["some_subclass"]
        del subclasses # Free up variable for other use.

    def sub_function(self, ...args...):
        ...other code...

    def _subclass_container(self):
        _parent_class = self # Create access to parent class.
        class some_subclass:
            def __init__(self):
                self._parent_class = _parent_class # Easy access from self.
                # Optional line, clears variable space, but SHOULD NOT BE USED
                # IF THERE ARE MULTIPLE SUBCLASSES as would stop their parent access.
                #  del _parent_class
        class subclass_2:
            def __init__(self):
                self._parent_class = _parent_class
        # Return reference(s) to the subclass(es).
        return {"some_subclass": some_subclass, "subclass_2": subclass_2}

主要代码,“生产就绪”(无注释等)。请记住将尖括号(例如<x>)中的每个值全部替换为所需的值。

class <higher_level_class>:
    def __init__(self):
        subclasses = self._subclass_container()
        self.<sub_class> = subclasses[<sub_class, type string>]
        del subclasses

    def _subclass_container(self):
        _parent_class = self
        class <sub_class>:
            def __init__(self):
                self._parent_class = _parent_class
        return {<sub_class, type string>: <sub_class>}

此方法的工作原理说明(基本步骤):

  1. 创建一个名为的函数_subclass_container作为包装器来访问变量self,即对更高级别类的引用(从函数内部运行的代码)。

1. 创建一个名为的变量`_parent_class`,它是对此函数变量的引用`self`,其子类`_subclass_container`可以访问(避免与`self`子类中的其他变量发生名称冲突)。
2. 将子类/子类作为字典/列表返回,以便调用该`_subclass_container`函数的代码可以访问里面的子类。
  1. __init__更高级别类内的函数中(或其他需要的地方),将函数返回的子类接收_subclass_container到变量中subclasses

  2. 将存储在变量中的子类分配subclasses给上级类的属性。

一些让场景变得更容易的技巧:

使将子类分配给更高级别类的代码更容易复制,并可以在从更高级别类派生的功能已 __init__ 发生改变的类中使用:

在主代码第12行之前插入:

def _subclass_init(self):

然后将主代码的第 5-6 行插入到该函数中,并用以下代码替换第 4-7 行:

self._subclass_init(self)

当子类数量较多或未知时,可以将子类分配给更高级别的类。

将第 6 行替换为以下代码:

for subclass_name in list(subclasses.keys()):
    setattr(self, subclass_name, subclasses[subclass_name])

此解决方案有用且无法获取更高级别的类名的示例场景:

创建一个名为“a”的类(class a:)。它有需要访问它(父类)的子类。一个子类称为“x1”。代码在此子类中a.run_func()运行。

然后创建另一个类,名为“b”,派生自类“a”(class b(a):)。此后,一些代码运行b.x1()(调用派生子类 b 的子函数“x1”)。此函数运行a.run_func(),调用类“a”的函数“run_func”,而不是其父类“b”的函数“run_func”(应该如此),因为在类“a”中定义的函数被设置为引用类“a”的函数,因为那是它的父类。

这会导致问题(例如,如果函数a.run_func已被删除),并且不重写类中的代码的唯一解决方案a.x1x1使用更新的代码重新定义从类“a”派生的所有类的子类,这显然很困难并且不值得。

解决方案 8:

您的意思是使用继承,而不是像这样嵌套类?您所做的在 Python 中毫无意义。

您可以Outer通过Outer.some_method在内部类的方法中引用来访问 的 some_method,但这不会像您预期的那样工作。例如,如果您尝试这样做:

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            Outer.some_method()

...初始化对象时会收到 TypeError Inner,因为Outer.some_method期望接收一个Outer实例作为其第一个参数。(在上面的例子中,您基本上是尝试将其some_method作为类方法调用Outer。)

解决方案 9:

另一种可能性:

class _Outer (object):
    # Define your static methods here, e.g.
    @staticmethod
    def subclassRef ():
        return Outer

class Outer (_Outer):
    class Inner (object):
        def outer (self):
            return _Outer

        def doSomething (self):
            outer = self.outer ()
            # Call your static mehthods.
            cls = outer.subclassRef ()
            return cls ()

解决方案 10:

我们可以做的是将外部类的 self 变量作为类参数传递给内部类,然后在外部 init 下初始化内部类,并将外部自身传递给内部

class Outer:
    def __init__(self):
        self.somevalue=91
        self.Inner=self.Inner(self)
    def SomeMethod(self):
        print('This is Something from Outer Class')

    class Inner:
        def __init__(self,Outer)
            self.SomeMethod=Outer.SomeMethod
            self.somevalue=Outer.somevalue
    
        def SomeAnotherMethod(self):
            print(self.somevalue)
            self.SomeMethod()        

>>>f=Outer()
>>>f.Inner.SomeAnotherMethod() 
91
This is Something from Outer Class

现在运行此功能后,它就可以工作了

解决方案 11:

扩展@tsnorri 的合理想法,即外部方法可能是一种静态方法:

class Outer(object):

    @staticmethod
    def some_static_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            self.some_static_method()    # <-- this will work later

    Inner.some_static_method = some_static_method

现在,当实际调用该线路时,它应该可以工作了。

上述代码的最后一行给 Inner 类提供了一个静态方法,它是 Outer 静态方法的克隆。


这利用了 Python 的两个特性,即函数是对象,作用域是文本。

通常,本地范围引用(文本)当前函数的本地名称。

...或者在我们的例子中是当前Inner。因此,外部类(和)定义的“本地”对象some_static_method可在该定义中直接引用。

解决方案 12:

感谢@mike-rodent的精彩回答,也感谢@tre-x。

根据您的做法,三级类嵌套定义及相互调用的示例如下。

# [0 - CLASSDEBUG_TEST, 1 - ONELINEND_SYSEXIT]
_DF = (True, True)

class rootcls_stackoverflow_q2024566_a60908562(object):
    # https://stackoverflow.com/a/60908562

    def __init__(self):
        pass
    
    class innercls(object):        
        pass

    def print_hi(self):
        print(f"hi rootcls")
    
    def call_innercls_function(self):
        parent = self.innercls_parent("Barbar")
        parent.print_hi()
        child = parent.innercls_child("Foofoo")
        child.print_hi()

        util = self.innercls_util()
        util.get_current_format_time()
        util.get_python_interpreter_path()
    
    def innercls_util(self):
        rootcls = self
        class innercls_util(rootcls.innercls):
            def get_current_format_time(self):
                import time
                time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                print(time_str)
                return time_str

            def get_python_interpreter_path(self):
                import sys
                pypath_interpreter = sys.executable
                print(pypath_interpreter)
                return pypath_interpreter
            
        return innercls_util()    # Be sure to include parentheses

    def innercls_parent(self, name):
        rootcls = self
        class innercls_parent(rootcls.innercls):
            def __init__(self, name):
                self.name = name
                self.children = []
            
            def print_hi(self):
                print(f"hi {self.name} of innercls_parent")
            
            def call_rootcls_function(self):
                print(f"call root class function:", end = " ")
                rootcls.print_hi()
            
            def innercls_child(self, name, rootcls=rootcls):
                rootcls = rootcls
                parentcls = self
                class innercls_child(rootcls.innercls):
                    def __init__(self, name):
                        self.name = name
                        self.parent = parentcls
                        parentcls.children.append(self)
                    
                    def print_hi(self):
                        print(f"hi {self.name} of innercls_child")
                    
                    def call_parentcls_function(self):
                        parentcls.print_hi()

                    def call_rootcls_function(self):
                        print(f"call root class function:", end = " ")
                        rootcls.print_hi()
                return innercls_child(name)
        return innercls_parent(name)
    
    def innercls_test(self):
        rootcls = self
        class innercls_test(rootcls.innercls):
            def __init__(self):
                pass

            def test_doit(self):
                parent = rootcls.innercls_parent("Bar")
                child1 = parent.innercls_child("Foo")
                child2 = parent.innercls_child("World")

                print(
                    child1.name,
                    parent.children[0].name,

                    child2.name,
                    parent.children[1].name,

                    child2.parent.children[0].parent.children[1].parent.name,
                    child1.parent.children[1].parent.children[0].parent.name
                )

                rootcls.print_hi()
                rootcls.call_innercls_function()

                parent.print_hi()
                parent.call_rootcls_function()

                child1.print_hi()
                child2.print_hi()
        return innercls_test()
if ('_DF' in locals() or '_DF' in globals()) and _DF[0]: 
    instance_rootcls = rootcls_stackoverflow_q2024566_a60908562()
    instance_innercls_test = instance_rootcls.innercls_test()
    instance_innercls_test.test_doit()
if ('_DF' in locals() or '_DF' in globals()) and _DF[1]:
    import sys; print(); sys.exit(0)

解决方案 13:

您可以创建一个类来装饰内部类。在本例中为 @inner。

因为这是一个装饰器:Outer.A = inner(Outer.A)。一旦您的代码需要 Outer.A,就会执行inner.__get__方法,该方法返回原始类 (A) 并在其上设置新属性:A.owner = Outer。

在这种情况下,类 A 中的类方法可以在处def add(cls, y=3)使用新属性。owner`return cls.owner.x + y + 1`

该行setattr(owner, name, self.inner)破坏了描述符,因为owner.name => Outer.A => A不再是内部类的实例。

希望这有帮助。

    class inner:
    
        def __init__(self, inner):
            self.inner = inner
    
        def __get__(self, instance, owner):
            print('__get__ method executed, only once... ')
            name = self.inner.__name__
            setattr(self.inner, 'owner', owner) 
            setattr(owner, name, self.inner) # breaks descriptor
            return self.inner #returns Inner
    
    class Outer:
        x = 1
    
        @inner
        class A:
    
            @classmethod
            def add(cls, y=3):
                return cls.owner.x + y + 1
    
    print(Outer.A.add(0)) # First time executes inner.__get__ method
    print(Outer.A.add(0)) # Second time not necessary.

    >> __get__ method executed, only once... 
    >> 2
    >> 2

解决方案 14:

可以通过将外部类对象解析为内部类来实现。

class Outer():

    def __init__(self,userinput):
        self.userinput = userinput
    
    
    def outer_function(self):
        self.a = self.userinput + 2


    class Inner():

        def inner_function(self):
            self.b = self.a + 10

定义完之后,需要运行该函数

m = Outer(3)
m.outer_function()
print (m.a)
#this will output 5

现在它有了外部类的变量。然后,它需要运行内部类函数。

m.Inner.inner_function(m)

外部类的对象m被解析到内部类的函数中(括号内),现在内部类函数正在从外部类访问self.a。

print (m.b)
#this will output 15

解决方案 15:

class Outer():
    class Inner():
        def __init__(self, o):
            self._outer=o
        def demo(self):
            print("I am the inner class and I call the outer class now")
            self._outer.whoami()

    def __init__(self):
        self._inner=Outer.Inner(self)

    def whoami(self):
        print("I am the outer class")

    def demo(self):
        self._inner.demo()

myOuter=Outer()
myOuter.demo()

解决方案 16:

这太简单了:

输入:

class A:
    def __init__(self):
        pass

    def func1(self):
        print('class A func1')

    class B:
        def __init__(self):
            a1 = A()
            a1.func1()

        def func1(self):
            print('class B func1')

b = A.B()
b.func1()

输出

A 类函数1

B 类功能1

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用