如何避免在python中出现显式的”self”?

How to avoid explicit 'self' in Python?

我一直在学习Python,学习了一些PyGame教程。

在那里我发现了大量的关键字自我,并且来自一个主要的Java背景,我发现我总是忘记键入自我。例如,我将键入rect.centerx,而不是self.rect.centerx,因为在我看来,rect已经是类的成员变量。

Java并行我可以想到,这种情况下,必须用这个方法对所有成员变量进行前缀。

我是一直在给所有成员变量加上self前缀,还是有一种方法可以声明它们以避免不得不这样做?

即使我建议的不是Python,我还是想知道是否可能。

我已经看了这些相关的问题,但它们并不能完全回答我的要求:

  • python-为什么在类中使用"self"?
  • 为什么需要将"self"参数显式地放入Python方法中?


python需要指定self。结果是,即使没有看到完整的类定义,对于什么是成员,什么不是成员也不会有任何混淆。这会导致有用的属性,例如:不能添加意外隐藏非成员的成员,从而破坏代码。

一个极端的例子:您可以编写一个类,而不必知道它可能拥有什么基类,并且始终知道您是否正在访问一个成员:

1
2
3
4
class A(some_function()):
  def f(self):
    self.member = 42
    self.method()

这就是完整的代码!(某些函数返回用作基的类型。)

另一种方法,其中类的方法是动态组合的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class B(object):
  pass

print B()
# <__main__.B object at 0xb7e4082c>

def B_init(self):
  self.answer = 42
def B_str(self):
  return"<The answer is %s.>" % self.answer
# notice these functions require no knowledge of the actual class
# how hard are they to read and realize that"members" are used?

B.__init__ = B_init
B.__str__ = B_str

print B()
# <The answer is 42.>

记住,这两个例子都是极端的,你不会每天都看到它们,我也不建议你经常写这样的代码,但是它们确实清楚地显示了自我被明确要求的方面。


实际上,self不是一个关键字,它只是按照惯例为python中实例方法的第一个参数指定的名称。第一个参数不能被跳过,因为它是一个方法唯一的机制,可以知道调用它的类的哪个实例。


例如,您可以使用您想要的任何名称

1
2
3
class test(object):
    def function(this, variable):
        this.variable = variable

甚至

1
2
3
class test(object):
    def function(s, variable):
        s.variable = variable

但是您仍然需要为作用域使用一个名称。

我不建议你用与自己不同的东西,除非你有一个令人信服的理由,因为这会使有经验的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
28
29
30
31
32
33
34
35
36
37
import numpy as np
class MyFunkyGaussian() :
    def __init__(self, A, x0, w, s, y0) :
        self.A = float(A)
        self.x0 = x0
        self.w = w
        self.y0 = y0
        self.s = s

    # The correct way, but subjectively less readable to some (like me)
    def calc1(self, x) :
        return (self.A/(self.w*np.sqrt(np.pi))/(1+self.s*self.w**2/2)
                * np.exp( -(x-self.x0)**2/self.w**2)
                * (1+self.s*(x-self.x0)**2) + self.y0 )

    # The correct way if you really don't want to use 'self' in the calculations
    def calc2(self, x) :
        # Explicity copy variables
        A, x0, w, y0, s = self.A, self.x0, self.w, self.y0, self.s
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

    # Probably a bad idea...
    def calc3(self, x) :
        # Automatically copy every class vairable
        for k in self.__dict__ : exec(k+'= self.'+k)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

g = MyFunkyGaussian(2.0, 1.5, 3.0, 5.0, 0.0)
print(g.calc1(0.5))
print(g.calc2(0.5))
print(g.calc3(0.5))

第三个例子——即使用for k in self.__dict__ : exec(k+'= self.'+k)基本上就是问题的实质所在,但我要明确指出的是,我认为这通常不是一个好主意。

有关更多信息和迭代类变量甚至函数的方法,请参阅这个问题的答案和讨论。有关动态命名变量的其他方法的讨论,以及为什么这通常不是一个好主意,请参阅此博客文章。


是的,根据Python的哲学,必须始终指定self,因为显式优于隐式。

您还可以发现,在Python中编程的方式与Java编程的方式有很大不同,因此使用EDCOX1(0)的方法往往会减少,因为您不会在对象内部投射所有的东西。相反,您更多地使用模块级功能,这可以更好地测试。

顺便说一句。起初我讨厌它,现在我讨厌相反的东西。对于缩进驱动流控制也是如此。


"self"是类的当前对象实例的常规占位符。当您希望引用类中对象的属性、字段或方法时,就使用它,就像引用"本身"。但是为了缩短时间,Python编程领域的一些人开始使用"self",其他领域使用"this",但他们将其作为一个不能替换的关键字。我宁愿用"it"来提高代码的可读性。这是Python中的一个优点——您可以自由地为对象实例选择自己的占位符,而不是"self"。自我举例:

1
2
3
4
5
6
7
8
9
10
11
class UserAccount():    
    def __init__(self, user_type, username, password):
        self.user_type = user_type
        self.username = username            
        self.password = encrypt(password)        

    def get_password(self):
        return decrypt(self.password)

    def set_password(self, password):
        self.password = encrypt(password)

现在我们用"它"替换"自我":

1
2
3
4
5
6
7
8
9
10
11
class UserAccount():    
    def __init__(its, user_type, username, password):
        its.user_type = user_type
        its.username = username            
        its.password = encrypt(password)        

    def get_password(its):
        return decrypt(its.password)

    def set_password(its, password):
        its.password = encrypt(password)

现在哪个更可读?


self是访问对象成员的python语法的一部分,因此我担心您会一直使用它。


实际上,你可以使用Armin Ronacher演示"5年的坏主意"(Google IT)中的"隐式自我"配方。

这是一个非常聪明的食谱,几乎来自阿敏·罗纳赫的所有东西,但我不认为这个想法很有吸引力。我想我更喜欢在C/JAVA中显式的。

更新。链接到"坏主意食谱":https://speakerdeck.com/mituhiko/5-years-of-bad-ideas?幻灯片=58


是的,自我是乏味的。但是,这样更好吗?

1
2
3
4
5
6
7
class Test:

    def __init__(_):
        _.test = 'test'

    def run(_):
        print _.test


自:自我地狱-更有状态的功能。

...a hybrid approach works best. All of your class methods that actually
do computation should be moved into closures, and extensions to clean up syntax should be kept in classes. Stuff the closures into classes, treating the class much like a namespace. The closures are essentially static functions, and so do not require selfs*, even in the class...