What is the difference between a frame and object, and when should I modify one over the other?
我开始阅读python的+=语法,无意中发现了以下文章/答案:关于的交互式代码+=
所以我注意到帧和对象之间似乎有区别。
。
在全局框架中,它们指向同一对象,即使它们是不同的变量;如果
1 | l2 += [item] |
而是
1 | l2 = l2 + [item] |
号
然后"l2"在该行运行时成为单独的对象。我最大的问题是,您希望一个变量何时指向一个单独的对象?另外,为什么和什么时候你想让它们指向同一个物体?
任何解释或用例都将非常感谢!如果您能提到任何与数据科学相关的信息,请特别感谢:)
在编程中,有一个称为堆栈的东西。在Python中,当调用函数时,创建一个称为堆栈帧的东西。这个框架(如您在示例中看到的)基本上只是一个包含函数局部所有变量的表。
注意,定义一个函数并不会创建一个新的堆栈框架,而是调用一个函数。例如:
1 2 3 | def say_hello(): name = input('What is your name?') print('Hello, {}'.format(name)) |
你的全球框架只是一个参考:
1 | print(locals()) |
号
你会看到这样的东西:
1 | {'__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(双下划线的缩写)名称-这些名称是自动提供的,为了我们的讨论,您可以忽略它们。这给我们留下了:
1 | {'say_hello': <function say_hello at 0x101962d90>} |
。
该
1 | {'name': 'Arthur, King of the Brits'} |
这里没有邓德的名字。您还将注意到,这不会显示内存地址。如果你想知道这个值在哪里,它有一个函数。
1 2 3 4 5 6 7 8 | 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中,一切都是一个对象。试试看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | >>> 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 |
。
它们都是物体。但它们可能是不同的物体。你怎么知道?使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | >>> 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 |
注意,通过使用
1 2 3 4 5 6 7 8 9 10 11 12 | >>> 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 |
。
嗯……?等等,发生了什么事?事实证明,EDOCX1(即cpython)缓存小整数。因此,对象
需要注意的一点是,赋值操作符
1 2 3 4 5 6 7 8 9 10 11 | >>> x = 592 >>> y = 592 >>> x is y False >>> x == y True >>> x = y >>> x is y True >>> x == y True |
不管你给一个物体取了多少个别的名字,或者即使你把这个物体传给不同的帧,你仍然拥有相同的物体。
但是当您开始收集时,了解更改对象的操作和生成新对象的操作之间的区别是很重要的。一般来说,在Python中有一些不变的类型,对它们的操作将生成一个新的对象。
至于你的问题,你想什么时候改变对象,什么时候保持它们不变,实际上是看错了方向。当您想更改内容时,您需要使用可变类型;如果不想更改内容,您需要使用不可变类型。
例如,假设您有一个组,并且希望向该组添加成员。您可以使用一个可变类型(如列表)来跟踪组,使用一个不可变类型(如字符串)来表示成员。这样地:
1 2 3 4 5 6 7 8 9 10 | >>> 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'] |
。
当一个小组成员被吃掉时会发生什么?
1 2 3 4 5 | >>> del group[-2] # And there was much rejoicing >>> id(group) 4325836488 >>> group ['Sir Lancelot', 'Sir Gallahad', 'Sir Robin', 'King Arthur'] |
号
你会注意到你仍然有同一个组,只是成员变了。