Python 类中的 self.variables

9 投票
3 回答
23856 浏览
提问于 2025-04-18 18:55

我开始学习Python的类已经有一段时间了,但在使用类里面的self.variables时,有些地方我不太明白。我在网上查了资料,但没找到答案。我不是程序员,只是个Python爱好者。

这里有一个简单的类的例子,有两种定义方式:

1) 第一种方式:

class Testclass:
    def __init__(self, a,b,c):
        self.a = a
        self.b = b
        self.c = c
    def firstMethod(self):
        self.d = self.a + 1
        self.e = self.b + 2
    def secondMethod(self):
        self.f = self.c + 3
    def addMethod(self):
        return self.d + self.e + self.f

myclass = Testclass(10,20,30)
myclass.firstMethod()
myclass.secondMethod()
addition = myclass.addMethod()

2) 第二种方式:

class Testclass:
    def __init__(self, a,b,c):
        self.a = a
        self.b = b
        self.c = c
    def firstMethod(self):
        d = self.a + 1
        e = self.b + 2
        return d,e
    def secondMethod(self):
        f = self.c + 3
        return f
    def addMethod(self, d, e, f):
        return d+e+f

myclass = Testclass(10,20,30)
d, e = myclass.firstMethod()
f= myclass.secondMethod()
addition = myclass.addMethod(d,e,f)

让我困惑的是,这两种方式哪种是有效的?

是应该总是在方法里面把我们以后要用的变量定义为self.variables(这样它们在类里面就是全局的),然后在类的其他方法中调用它们(这就是上面代码的第一种方式)?还是说更好的是不把变量定义为self.variables,而是直接定义为普通变量,然后在方法结束时返回它们,然后在其他方法中作为参数“重新引入”它们(这就是上面代码的第二种方式)?

补充说明一下,我不想在init方法里面定义self.d、self.e、self.f或者d、e、f这些变量。我想在其他方法里面定义它们,就像上面的代码所示。抱歉之前没有提到这一点。

3 个回答

1

在没有具体和有意义的例子之前,你很难对这种问题得出结论,因为这要看你想做的事情的具体情况。

不过,在你的第一个例子中,firstMethod()secondMethod() 实际上是多余的。它们的存在没有任何意义,只是为了计算一些 addMethod() 需要用到的值。更糟糕的是,为了让 addMethod() 能正常工作,用户必须先调用这两个看起来毫无关系的函数,这显然是设计不好的。如果这两个方法真的有一些有意义的功能,那可能会有道理(但可能也没有),但在没有真实例子的情况下,这就是不好的设计。

你可以把第一个例子替换成:

class Testclass:
    def __init__(self, a,b,c):
        self.a = a
        self.b = b
        self.c = c

    def addMethod(self):
        return self.a + self.b + self.c + 6

myclass = Testclass(10,20,30)
addition = myclass.addMethod()

第二个例子类似,只不过 firstMethod()secondMethod() 实际上是有用的,因为它们返回了一些值。如果你有理由需要这些值,而不是仅仅为了传给 addMethod(),那么这可能就有意义。如果没有理由,那你可以像我刚才那样定义 addMethod(),完全不需要这两个额外的函数,这样两个例子之间就没有区别了。

但在没有具体例子的情况下,这一切都显得很不令人满意。现在我们只能说这是一个稍微有点傻的类。

一般来说,在面向对象编程中,对象是数据(实例变量)和行为(方法)的集合。如果一个方法不访问实例变量,或者不需要访问它们,那么它通常应该是一个独立的函数,而不应该放在类里面。偶尔有些情况下,类或静态方法不访问实例变量是有意义的,但一般来说,你应该倾向于使用独立函数。

1

编辑:

如果你想在执行 addMethod 之后保留对象里面的值,比如说你想再次调用 addMethod,那么就用第一种方法。如果你只是想用这个类里面的一些内部值来执行 addMethod,那就用第二种方法。

7

这两种方法都是有效的。哪种方法更合适完全取决于具体情况。

比如说:

  • 你是从哪里“真正”获取 a、b、c 的值
  • 你是否想/需要多次使用它们
  • 你是否想/需要在类的其他方法中使用它们
  • 这个类代表什么
  • a、b 和 c 真的是类的“固定”属性,还是说它们依赖于外部因素?

在你下面评论中的例子里:

假设 a、b、c 依赖于一些外部变量(例如 a = d+10,b = e+20,c = f+30,其中 d、e、f 在实例化类时提供:myclass = Testclass("hello",d,e,f))。是的,假设我也想在类的其他方法中使用 a、b、c(或者 self.a、self.b、self.c)这些变量。

所以在这种情况下,“正确”的方法主要取决于你是否期望 a、b、c 在类实例的生命周期中发生变化。例如,如果你有一个类,其中属性(a、b、c)几乎不会变化,但你经常使用派生属性(d、e、f),那么一次性计算并存储它们是有意义的。这里有个例子:

class Tiger(object):
    def __init__(self, num_stripes):
        self.num_stripes = num_stripes
        self.num_black_stripes = self.get_black_stripes()
        self.num_orange_stripes = self.get_orange_stripes()
    def get_black_stripes(self):
        return self.num_stripes / 2
    def get_orange_stripes(self):
        return self.num_stripes / 2

big_tiger = Tiger(num_stripes=200)
little_tiger = Tiger(num_stripes=30)

# Now we can do logic without having to keep re-calculating values
if big_tiger.num_black_stripes > little_tiger.num_orange_stripes:
    print "Big tiger has more black stripes than little tiger has orange"

这个方法很好,因为每只老虎的条纹数量是固定的。如果我们把例子改成一个实例经常变化的类,那么我们的方法也会改变:

class BankAccount(object):
    def __init__(self, customer_name, balance):
        self.customer_name = customer_name
        self.balance = balance
    def get_interest(self):
        return self.balance / 100

my_savings = BankAccount("Tom", 500)
print "I would get %d interest now" % my_savings.get_interest()
# Deposit some money
my_savings.balance += 100
print "I added more money, my interest changed to %d" % my_savings.get_interest()

在这个(有点牵强的)例子中,银行账户的余额经常变化——因此将利息存储在 self.interest 变量中没有意义——每次余额变化时,利息金额也会变化。所以每次需要使用它时计算利息是更合理的。

你可以采取一些更复杂的方法来同时获得这两者的好处。例如,你可以让你的程序“知道”利息与余额相关联,然后它会暂时记住利息值,直到余额变化(这是一种缓存形式——我们使用更多的内存,但节省了一些 CPU 计算)。

与原问题无关

关于如何声明你的类的一点说明。如果你使用的是 Python 2,最好让你自己的类继承自 Python 内置的对象类:

class Testclass(object):
    def __init__(self, printHello):

参考 NewClassVsClassicClass - Python Wiki: Python 3 默认使用新式类,所以如果使用 Python 3,你不需要显式地继承自对象。

撰写回答