Oop 不是';t类成员变量和全局变量一样糟糕?
我们都知道,由于使用了全局变量,以下代码很糟糕:Oop 不是';t类成员变量和全局变量一样糟糕?,oop,global-variables,member,member-variables,Oop,Global Variables,Member,Member Variables,我们都知道,由于使用了全局变量,以下代码很糟糕: a = 3.14 def inc(): global a a += 1 inc() b = a 这太糟糕了,在python中,人们不得不故意声明global来“打破”禁令。但是,以面向对象的名义,下面的代码为什么是合理的: class A: def __init__(self): self.a = 3.14 def inc(self): self.a += 1 A_instance = A() A_ins
a = 3.14
def inc():
global a
a += 1
inc()
b = a
这太糟糕了,在python中,人们不得不故意声明global来“打破”禁令。但是,以面向对象的名义,下面的代码为什么是合理的:
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
A_instance = A()
A_instance.inc()
b = A_instance.a
在类实例的范围内,成员变量不是简单地与全局变量相同吗?“self”基本上允许任何成员函数不受限制地访问所有变量,无论其必要性如何,这使得它非常有状态,容易出错,并且难以读取(基本上是全局变量的所有不好的特性)
我们还知道,清洁和更好的方法是:
def inc(_a):
return _a+1
a = 3.14
b = inc(a)
因此函数inc()至少是无状态的,并且具有可预测的行为。使用类并使其尽可能无状态的最佳实践是什么?或者根据定义,OO是否总是有状态的,并且必须在没有类的情况下进行函数式编程?我还听人说@static方法很愚蠢,破坏封装,应该避免…现在之所以认为
self
的概念不算坏的做法,是因为如果要创建一个类,该类中的所有内容都应该以某种方式关联,通常是通过\uuuu init\uuuu
dunder方法初始化的类属性。基本上,如果您要创建一个类,那么应该有某种链接,一个类全局,如果您愿意的话,它是类属性
通常的想法是,像这样用self创建类
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
这并不是人们经常看到的事情,而是人们选择了在许多人看来更干净、更可预测的方式
class A:
def __init__(self, a):
self.a = a
def inc(self):
self.a += 1
通过这种方式,当您声明类实例时,您可以更好地控制实际存在的内容,因此类实例是用变量声明的
A_instance = A(3.14) #a will be 3.14 in this instance
B_instance = A(3.142) #a will be 3.142 in this instance
等等。
在\uuuu init\uuuu
函数外部声明但在类内部声明的类变量,其本身有很大的不同,如下所示
class A:
a = 22/7
def __init__(self):
....
class A:
a = 22/7
def __init__(self, item):
self.item = item
A_instance = A(3.14)
B_instance = A(5)
有了它,a将成为整个类(不是实例而是类本身)的全局变量。那看起来像什么
class A:
a = 22/7
def __init__(self):
....
class A:
a = 22/7
def __init__(self, item):
self.item = item
A_instance = A(3.14)
B_instance = A(5)
虽然A_实例
和B_实例
完全不同,A_实例。项
将等于3.14,而B_实例。项
将等于5,这两个项都将类变量A
作为22/7
因此,类变量在该类的所有实例中保持一致/相同,除非它被主动更改
关键是,如果你要创建一个类,它应该有特定的变量,这些变量相互交织,影响所有特定的函数组,这些是你在类方法中使用的函数。如果使用得当,
self
在类中的使用是正确的。现在,self
的概念不被认为是不好的做法的原因是,如果你要创建一个类,那么该类中的所有内容都应该以某种方式相关,而这种方式通常是错误的类实例通过\uuuu init\uuuu
dunder方法初始化的类属性。基本上,如果您要创建一个类,那么应该有某种链接,一个类全局,如果您愿意的话,它是类属性
通常的想法是,像这样用self创建类
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
这并不是人们经常看到的事情,而是人们选择了在许多人看来更干净、更可预测的方式
class A:
def __init__(self, a):
self.a = a
def inc(self):
self.a += 1
通过这种方式,当您声明类实例时,您可以更好地控制实际存在的内容,因此类实例是用变量声明的
A_instance = A(3.14) #a will be 3.14 in this instance
B_instance = A(3.142) #a will be 3.142 in this instance
等等。
在\uuuu init\uuuu
函数外部声明但在类内部声明的类变量,其本身有很大的不同,如下所示
class A:
a = 22/7
def __init__(self):
....
class A:
a = 22/7
def __init__(self, item):
self.item = item
A_instance = A(3.14)
B_instance = A(5)
有了它,a将成为整个类(不是实例而是类本身)的全局变量。那看起来像什么
class A:
a = 22/7
def __init__(self):
....
class A:
a = 22/7
def __init__(self, item):
self.item = item
A_instance = A(3.14)
B_instance = A(5)
虽然A_实例
和B_实例
完全不同,A_实例。项
将等于3.14,而B_实例。项
将等于5,这两个项都将类变量A
作为22/7
因此,类变量在该类的所有实例中保持一致/相同,除非它被主动更改
关键是,如果你要创建一个类,它应该有特定的变量,这些变量相互交织,影响所有特定的函数组,这些是您在类方法中使用的函数,因此在类中使用
self
是正确的,如果使用得当这取决于您是否需要保存状态。如果您确实需要保存状态,那么它需要保存在某个地方。类允许您将状态与操作该状态的方法一起保存,并强制执行一个类本地作用域,该类本地作用域比在全局作用域中存储状态更不容易出错
作为一个具体的例子,我最近为一个森林模拟实现了一个树类。与树关联的一个重要变量是它的年龄。树的树龄应该存放在哪里?将其存储在树类内比存储在树类外更有意义
如果保护树的年龄不被类外的代码操纵是重要的,那么我可以使用Python优秀的@property
语法来实现这一目的,或者更直接地通过Python\u varname
变量命名约定来实现
在类中,是的,树的年龄对其他方法是可见的,但这是一个相对狭窄的范围,如果您的类是按照面向对象的设计原则编写的,则肯定与全局范围不同。这取决于您是否需要保存状态。如果您确实需要保存状态,那么它需要