框架和对象之间有什么区别,我应该何时修改另一个框架和对象?

时间:2016-11-16 20:23:22

标签: python python-3.x object dataframe

我开始阅读python的+ =语法并偶然发现以下帖子/答案: Interactive code about +=

所以我注意到框架和物体之间似乎存在差异。

Frames and Objects

在全局框架中,即使它们是不同的变量,它们也指向同一个对象;如果该行

l2 += [item]

l2 = l2 + [item]

然后'l2'在该行运行时成为一个单独的对象。我最大的问题是你何时想要一个变量指向一个单独的对象?另外,为什么以及何时要让它们指向同一个对象?

任何解释或用例都将不胜感激!如果您能提及与数据科学相关的任何内容,请特别感谢:)

1 个答案:

答案 0 :(得分:11)

frameobject并不代表您认为的含义。

在编程中,你有一个叫做堆栈的东西。在Python中,当你调用一个函数时,你会创建一个叫做堆栈框架的东西。这个框架(如你的例子中所示)基本上只是一个包含你函数本地变量的表格。

请注意,定义函数不会创建新的堆栈帧,它是调用函数。比如像这样:

def say_hello():
    name = input('What is your name?')
    print('Hello, {}'.format(name))

您的全局框架只会包含一个引用:say_hello。你可以通过查看本地命名空间中的内容来看到(在Python中你几乎在命名空间,范​​围和堆栈帧之间有1:1的关系):

print(locals())

你会看到这样的东西:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x1019bb320>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/private/tmp/fun.py', '__cached__': None, 'say_hello': <function say_hello at 0x101962d90>}

请注意dunder(双下划线双下划线的缩写)名称 - 这些是自动提供的,出于讨论的目的,您可以忽略它们。这让我们:

{'say_hello': <function say_hello at 0x101962d90>}

0x位是函数本身所在的内存地址。所以在这里,我们的全局堆栈/帧只包含那个值。如果您调用自己的功能,然后再次检查locals(),则会发现name不在那里。这是因为当你调用函数时,你创建了一个新的堆栈框架,并在那里分配了变量。您可以通过在函数末尾添加print(locals())来证明这一点。然后你会看到类似的东西:

{'name': 'Arthur, King of the Brits'}

这里没有dunder的名字。您还会注意到,这并未显示内存地址。如果你想知道这个价值存在的地方,那就有了它的功能。

def say_hello():
    name = input('What is your name?')
    print('hello {}'.format(name))
    print(locals())
    print(id(name))
    return name

print(id(say_hello()))

该示例在谈论框架时的含义。

但物体怎么样?好吧,在Python中,所有都是一个对象。试试吧:

>>> isinstance(3, object)
True
>>> isinstance(None, object)
True
>>> isinstance('hello', object)
True
>>> isinstance(13.2, object)
True
>>> isinstance(3j, object)
True
>>> def fun():
...  print('hello')
... 
>>> isinstance(fun, object)
True
>>> class Cool: pass
... 
>>> isinstance(Cool, object)
True
>>> isinstance(Cool(), object)
True
>>> isinstance(object, object)
True
>>> isinstance(isinstance, object)
True
>>> isinstance(True, object)
True

他们所有对象。但它们可能是不同的对象。你怎么知道?使用id

>>> id(3)
4297619904
>>> id(None)
4297303920
>>> id('hello')
4325843048
>>> id('hello')
4325843048
>>> id(13.2)
4322300216
>>> id(3j)
4325518960
>>> id(13.2)
4322300216
>>> id(fun)
4322635152
>>> id(isinstance)
4298988640
>>> id(True)
4297228640
>>> id(False)
4297228608
>>> id(None)
4297303920
>>> id(Cool)
4302561896

请注意,您还可以使用is来比较两个对象是否是相同的对象。

>>> True is False
False
>>> True is True
True
>>> 'hello world' is 'hello world'
True
>>> 'hello world' is ('hello ' + 'world')
False
>>> 512 is (500+12)
False
>>> 23 is (20+3)
True

Ehhhhh ...?等一下,那里发生了什么?好吧,事实证明,python(即CPython)caches small integers。因此,对象512与作为对象500添加到对象12的结果的对象不同。

需要注意的一件重要事情是,赋值运算符= 始终同一对象分配新名称。例如:

>>> x = 592
>>> y = 592
>>> x is y
False
>>> x == y
True
>>> x = y
>>> x is y
True
>>> x == y
True

你给对象提供了多少其他名称并不重要,或者即使你通过object around to different frames,你仍然拥有相同的对象。

但是,当您开始收集时,了解更改对象的操作与生成 new 的操作之间的区别非常重要宾语。一般来说,你在Python中有few immutable types,对它们的操作会产生一个新对象。

至于你的问题,你什么时候想要改变对象?你想什么时候保持它们一样,实际上是以错误的方式看待它。如果你想改变一些东西,你想使用一个可变类型,如果你不想改变它,你想要使用一个不可变类型。

例如,假设您有一个群组,并且您想要向该群组添加成员。您可以使用类似列表的可变类型来跟踪组,并使用不可变类型(如字符串)来表示成员。像这样:

>>> group = []
>>> id(group)
4325836488
>>> group.append('Sir Lancelot')
>>> group.append('Sir Gallahad')
>>> group.append('Sir Robin')
>>> group.append("Robin's Minstrels")
>>> group.append('King Arthur')
>>> group
['Sir Lancelot', 'Sir Gallahad', 'Sir Robin', "Robin's Minstrels", 'King Arthur']

当小组成员被吃掉时会发生什么?

>>> del group[-2]  # And there was much rejoicing
>>> id(group)
4325836488
>>> group
['Sir Lancelot', 'Sir Gallahad', 'Sir Robin', 'King Arthur']

您会注意到您仍然拥有相同的群组,只是会员已经更改。