Python 状态与无状态的属性和优势是什么?

Python 状态与无状态的属性和优势是什么?,python,oop,haskell,functional-programming,state,Python,Oop,Haskell,Functional Programming,State,我从各种来源了解到,作为一个状态被定义为以下内容: “程序关于存储输入的条件” '程序中任何给定时间的内存位置的内容 执行' 但是,然后我查看了无状态的特征是什么(例如“Haskell是无状态的”): “当应用程序不依赖于其状态时” “无法更改物理状态” '相同输入的相同输出-内存中的地址始终保持不变' '方法不依赖于实例及其对应实例 变量的 现在,我一定误解了(模糊的?)以前的定义,因为FP语言肯定与“无状态”模型同时存储输入??或者这仅仅是关于函数的求值而不是数据的变异 嗯,在阅读

我从各种来源了解到,作为一个状态被定义为以下内容:

  • “程序关于存储输入的条件”
  • '程序中任何给定时间的内存位置的内容 执行'
但是,然后我查看了无状态的特征是什么(例如“Haskell是无状态的”):

  • “当应用程序不依赖于其状态时”
  • “无法更改物理状态”
  • '相同输入的相同输出-内存中的地址始终保持不变'
  • '方法不依赖于实例及其对应实例 变量的
现在,我一定误解了(模糊的?)以前的定义,因为FP语言肯定与“无状态”模型同时存储输入??或者这仅仅是关于函数的求值而不是数据的变异


嗯,在阅读了关于它在程序验证、调试和并发性中的使用之后,我有点明白这种模型有时是强大的

但当我接着读到如何:

  • “它消除了一整类与竞争相关的多线程错误 条件“
  • 更具表现力的代码(不管是什么?)
  • “静态评估……可用于有利地指导计算机的 位置[在tic-tac-toe游戏树中](或者静态输入完全是另一个问题?)

因此,我还想知道能够在迭代编程语言中操纵状态的优势,许多论坛都给出了这样的例子,比如通过调用add()改变一个人的“年龄”将如何使“年龄”变量在其范围之外发生变异

也许是我缺乏面向对象编程的经验,但在更广泛的应用程序中使用状态的确切优势是什么


如果可以给出任何示例代码,请尝试将Python/Haskell作为这些相反学科的对比代表?我在阅读其他语言方面的专长似乎阻碍了我对其他帖子解释的理解。

< P>如果你考虑一个没有任何状态的程序,程序不能读取外部状态(例如,检查系统时间),那就意味着任何功能,除了哪些值可以作为参数传递外,我们无法区分任何不同的情况,因为不可能存在不同的情况

对于这类程序,运行时实际上是冗余的,因为优化编译器可以静态地导出任何结果输出。它本质上相当于写出一个大的数学方程。您可以解决它,但“运行程序”的想法是多余的,因为它具有程序本身固有的无法更改的输出

显然,这与大多数程序不同,即使是那些可能被描述为“无状态”的程序。通常存在一些最小类型的状态,例如最初传递给程序的输入。例如,假设一个程序输出一个数字K的平方根的前N位数字。该程序现在有一个初始状态,但除了知道N和K是什么之外,该程序不需要跟踪程序级状态,例如一周中的哪一天,用户是否喜欢MDY vs DMY date格式等。然而,由于程序几乎肯定涉及某种动态循环以查找N个数字,因此它需要某种与循环相关联的状态(例如迭代编号)

因此,当代码被称为“无状态”时,它不是100%的承诺,而是代码依赖于状态的程度的一种限定符

那么这里的优势和劣势是什么呢?代码越依赖于状态,就越有可能执行程序员不期望的操作。记住,状态是运行时固有的东西。但我们不在运行时编写代码。我们可以尝试想象可能发生的所有不同的运行时状态,但这很快就会失控

例子 下面是同一个python程序以有状态与无状态方式的示例

有状态的

import math

angle_type = 'radians'

def cosecant(x):
    if angle_type == 'radians':
        return 1/math.sin(x)
    elif angle_type == 'degrees':
        return 1/math.sin(x*math.pi/180)
    else:
        raise NotImplementedError('cosecant is not implemented for angle type', angle_type)
======================重新启动:F:/Documents/Python/stateless.py=================
>>>余割(1)
1.1883951057781212
>>>余割_度(1)
57.298688498550185
>>>余割旋转(1)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
余割旋转(1)
名称错误:未定义名称“余割旋转”
>>> 
这个例子可能看起来很奇怪,但同样的原理和陷阱延伸到更复杂的程序。我们可以看到在这里使用state是如何导致问题的。考虑<代码>状态。Py < /代码>。一个问题是,调用
cosecant
的人不一定知道angle\u type的当前状态,他们必须在每次使用
cosecant
之前进行设置,以确保它将执行用户希望它执行的操作。由于程序员往往不喜欢重复自己,因此有人可能会在程序开始时声明
mymathlib.angle\u type='degrees'
,并假设其他任何东西都不会改变它。例如,如果您以度为单位工作,但随后调用的子例程将角度类型更改为弧度,并且在完成后不会更改为度

如果程序的其他部分正在更改它,那么程序员必须在每次调用它之前有效地将值设置为所需的值。即使如此,如果代码在多个线程上运行,也不能保证当您将
angle\u type
设置为
'degrees'
时,另一个线程在执行
cosecant
调用之前不会立即将其设置为其他线程(竞争条件)

在程序的无状态版本中,所有这些问题都消失了。费用是多少?现在我们有2个不同的函数,而不是1个。为什么我
================== RESTART: F:/Documents/Python/stateful.py ==================
>>> cosecant(1)
1.1883951057781212
>>> angle_type = 'degrees'
>>> cosecant(1)
57.298688498550185
>>> angle_type = 'turns'
>>> cosecant(1)
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    cosecant(1)
  File "F:/Documents/Python/stateful.py", line 11, in cosecant
    raise NotImplementedError('cosecant is not implemented for angle type', angle_type)
NotImplementedError: ('cosecant is not implemented for angle type', 'turns')
>>> 
import math

def cosecant(x):
    return 1/math.sin(x)

def cosecant_degrees(x):
    return 1/math.sin(x*math.pi/180)
================= RESTART: F:/Documents/Python/stateless.py =================
>>> cosecant(1)
1.1883951057781212
>>> cosecant_degrees(1)
57.298688498550185
>>> cosecant_turns(1)
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    cosecant_turns(1)
NameError: name 'cosecant_turns' is not defined
>>>