Geo*_*Geo 86 python oop language-features class
Python的内部/嵌套类使我感到困惑.有没有它们无法实现的东西?如果是这样,那是什么东西?
Azi*_*ziz 78
引自http://www.geekinterview.com/question_details/64739:
内在阶级的优点:
- 类的逻辑分组:如果一个类只对另一个类有用,那么将它嵌入该类并将两者保持在一起是合乎逻辑的.嵌套这样的"帮助类"使得它们的包更加简化.
- 增加封装:考虑两个顶级类A和B,其中B需要访问A的成员,否则这些成员将被声明为私有.通过将类B隐藏在类AA中,可以将成员声明为私有,并且B可以访问它们.另外B本身可以隐藏在外面.
- 更易读,可维护的代码:在顶级类中嵌套小类会使代码更接近于使用它的位置.
主要优势是组织.任何可以通过内部类完成的事情都可以在没有它们的情况下完成.
bob*_*nce 48
有没有它们无法实现的东西?
不.它们绝对等同于通常在顶级定义类,然后将对它的引用复制到外部类中.
我认为没有任何特殊原因嵌套类是"允许的",除了明确"禁止"它们也没有特别意义.
如果你正在寻找一个存在于外部/所有者对象生命周期内的类,并且始终引用外部类的实例 - 内部类,就像Java那样 - 那么Python的嵌套类就不是那样了.但你可以破解类似的东西:
import weakref, new
class innerclass(object):
"""Descriptor for making inner classes.
Adds a property 'owner' to the inner class, pointing to the outer
owner instance.
"""
# Use a weakref dict to memoise previous results so that
# instance.Inner() always returns the same inner classobj.
#
def __init__(self, inner):
self.inner= inner
self.instances= weakref.WeakKeyDictionary()
# Not thread-safe - consider adding a lock.
#
def __get__(self, instance, _):
if instance is None:
return self.inner
if instance not in self.instances:
self.instances[instance]= new.classobj(
self.inner.__name__, (self.inner,), {'owner': instance}
)
return self.instances[instance]
# Using an inner class
#
class Outer(object):
@innerclass
class Inner(object):
def __repr__(self):
return '<%s.%s inner object of %r>' % (
self.owner.__class__.__name__,
self.__class__.__name__,
self.owner
)
>>> o1= Outer()
>>> o2= Outer()
>>> i1= o1.Inner()
>>> i1
<Outer.Inner inner object of <__main__.Outer object at 0x7fb2cd62de90>>
>>> isinstance(i1, Outer.Inner)
True
>>> isinstance(i1, o1.Inner)
True
>>> isinstance(i1, o2.Inner)
False
Run Code Online (Sandbox Code Playgroud)
(这使用类装饰器,它是Python 2.6和3.0中的新增功能.否则你必须在类定义之后说"Inner = innerclass(Inner)".)
Jas*_*ker 27
你需要有一些东西能够理解这一点.在大多数语言中,类定义是编译器的指令.也就是说,该类是在程序运行之前创建的.在python中,所有语句都是可执行的.这意味着这句话:
class foo(object):
pass
Run Code Online (Sandbox Code Playgroud)
是一个在运行时执行的语句,就像这样:
x = y + z
Run Code Online (Sandbox Code Playgroud)
这意味着您不仅可以在其他类中创建类,还可以在任何地方创建类.考虑以下代码:
def foo():
class bar(object):
...
z = bar()
Run Code Online (Sandbox Code Playgroud)
因此,"内部阶级"的概念实际上并不是一种语言结构; 它是一个程序员构造.Guido对这里发生的事情进行了很好的总结.但实际上,基本思想是简化语言的语法.
Ed.*_*Ed. 13
在类中嵌套类:
嵌套类会使类定义膨胀,这使得查看最新情况变得更加困难.
嵌套类可以创建耦合,使测试更加困难.
在Python中,您可以在文件/模块中放置多个类,这与Java不同,因此该类仍然保持接近顶级类,甚至可以使用前缀为"_"的类名来帮助表示其他类不应该是使用它.
嵌套类可以证明有用的地方在函数内
def some_func(a, b, c):
class SomeClass(a):
def some_method(self):
return b
SomeClass.__doc__ = c
return SomeClass
Run Code Online (Sandbox Code Playgroud)
该类从函数中捕获值,允许您在C++中动态创建类似模板元编程的类
小智 8
没有他们,有什么事情是无法完成的吗?如果有,那是什么东西?
有一些事情不能没有:相关类的继承。
这是一个带有相关类A和的极简示例B:
class A(object):
class B(object):
def __init__(self, parent):
self.parent = parent
def make_B(self):
return self.B(self)
class AA(A): # Inheritance
class B(A.B): # Inheritance, same class name
pass
Run Code Online (Sandbox Code Playgroud)
这段代码导致了一个非常合理和可预测的行为:
>>> type(A().make_B())
<class '__main__.A.B'>
>>> type(A().make_B().parent)
<class '__main__.A'>
>>> type(AA().make_B())
<class '__main__.AA.B'>
>>> type(AA().make_B().parent)
<class '__main__.AA'>
Run Code Online (Sandbox Code Playgroud)
如果B是顶级类,则不能self.B()在方法中make_B写入而只会写入B(),从而失去与适当类的动态绑定。
请注意,在此构造中,您永远不应在 classA的主体中引用class B。这就是parent在 class 中引入属性的动机B。
当然,这种动态绑定可以在没有内部类的情况下重新创建,代价是对类进行繁琐且容易出错的检测。
前面显示的两种方式在功能上是相同的。然而,存在一些细微的差异,并且在某些情况下您想要选择其中一种而不是另一种。
方式一:嵌套类定义
(=“Nested class”)
class MyOuter1:
class Inner:
def show(self, msg):
print(msg)
Run Code Online (Sandbox Code Playgroud)
方式2:将模块级内部类附加到外部类
(=“引用的内部类”)
class _InnerClass:
def show(self, msg):
print(msg)
class MyOuter2:
Inner = _InnerClass
Run Code Online (Sandbox Code Playgroud)
下划线用于遵循PEP8 “内部接口(包、模块、类、函数、属性或其他名称)应该以单个前导下划线为前缀”。
下面的代码片段演示了“嵌套类”与“引用内部类”的功能相似之处;在代码检查内部类实例的类型时,它们的行为方式相同。不用说, 的m.inner.anymethod()行为与m1和类似m2
m1 = MyOuter1()
m2 = MyOuter2()
innercls1 = getattr(m1, 'Inner', None)
innercls2 = getattr(m2, 'Inner', None)
isinstance(innercls1(), MyOuter1.Inner)
# True
isinstance(innercls2(), MyOuter2.Inner)
# True
type(innercls1()) == mypackage.outer1.MyOuter1.Inner
# True (when part of mypackage)
type(innercls2()) == mypackage.outer2.MyOuter2.Inner
# True (when part of mypackage)
Run Code Online (Sandbox Code Playgroud)
下面列出了“嵌套类”和“引用内部类”的区别。它们不大,但有时您想根据这些来选择其中之一。
使用“嵌套类”可以比使用“引用内部类”更好地封装代码。模块命名空间中的类是全局变量。嵌套类的目的是减少模块中的混乱并将内部类放在外部类中。
虽然没有人*正在使用from packagename import *,但少量的模块级变量可能会很好,例如在使用具有代码完成/智能感知功能的 IDE 时。
*正确的?
Django 文档指示使用内部类 Meta作为模型元数据。class Foo(models.Model)指导框架用户编写一个with inside会更清晰一点* class Meta;
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
Run Code Online (Sandbox Code Playgroud)
而不是“写一个class _Meta,然后写一个class Foo(models.Model)” Meta = _Meta;
class _Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
class Ox(models.Model):
Meta = _Meta
horn_length = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)
使用“嵌套类”方法,代码可以读取嵌套的项目符号列表,但使用“引用内部类”方法,必须向上滚动才能看到_Meta其“子项”(属性)的定义。
如果您的代码嵌套级别增加或由于某些其他原因行很长,“引用的内部类”方法可能更具可读性。
* 当然,口味问题
这没什么大不了的,只是为了完整性:当访问内部类不存在的属性时,我们会看到略有不同的异常。继续第 2 节中给出的示例:
innercls1.foo()
# AttributeError: type object 'Inner' has no attribute 'foo'
innercls2.foo()
# AttributeError: type object '_InnerClass' has no attribute 'foo'
Run Code Online (Sandbox Code Playgroud)
这是因为type内部类的 s 是
type(innercls1())
#mypackage.outer1.MyOuter1.Inner
type(innercls2())
#mypackage.outer2._InnerClass
Run Code Online (Sandbox Code Playgroud)
我了解反对嵌套类的参数,但是在某些情况下有使用它们的情况。想象一下,我正在创建一个双向链接列表类,并且需要创建一个节点类来维护节点。我有两个选择,在DoublyLinkedList类内部创建Node类,或在DoublyLinkedList类外部创建Node类。在这种情况下,我首选第一种选择,因为Node类仅在DoublyLinkedList类内部有意义。尽管没有隐藏/封装的好处,但是有一个好处就是可以说Node类是DoublyLinkedList类的一部分。