我一直在通过学习一些pygame tutorials来学习Python。
在其中,我发现关键字self被广泛使用,并且主要来自Java背景,我发现我总是忘记键入self。例如,我会输入self.rect.centerx
而不是rect,因为对我来说,rect已经是该类的成员变量了。
对于这种情况,我能想到的Java并行方法是必须在所有对成员变量的引用前面加上这个前缀。
我是不是在所有的成员变量前都加上了self前缀,或者有没有一种方法可以让我避免这样做?
即使我的建议不是pythonic式的,我仍然想知道它是否可能。
我已经看了这些相关的SO问题,但它们并没有完全回答我想要的:
发布于 2009-12-31 13:57:30
Python需要指定self.这样做的结果是,即使没有完整的类定义,也不会混淆什么是成员,什么不是成员。这将导致有用的属性,例如:您不能添加意外地隐藏非成员的成员,从而破坏代码。
一个极端的例子:你可以编写一个类,而不知道它可能有什么基类,并且总是知道你是否正在访问一个成员:
class A(some_function()):
def f(self):
self.member = 42
self.method()
这是完整的代码!(some_function返回用作基数的类型。)
另一种是动态组合类的方法:
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的某些方面是显式需要的。
发布于 2018-03-16 02:55:21
之前的答案基本上都是“你不能”或“你不应该”的变体。虽然我同意后一种观点,但从技术上讲,这个问题仍然没有答案。
此外,有些人可能想要按照实际问题的路线做一些事情,这是有正当理由的。我有时遇到的一件事是冗长的数学方程式,使用长名称会使方程式难以辨认。这里有几种方法,你可以在一个固定的例子中做到这一点:
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)
基本上就是这个问题的实际要求,但我要明确的是,我认为这通常不是一个好主意。
有关更多信息,以及遍历类变量甚至函数的方法,请参阅对this question的解答和讨论。有关动态命名变量的其他方法的讨论,以及为什么这通常不是一个好主意,请参阅this blog post。
update :似乎有no way可以动态更新或更改Python3函数中的局部变量,因此calc3和类似的变体不再可能。我现在能想到的唯一兼容python3的解决方案就是使用globals
def calc4(self, x) :
# Automatically copy every class variable in globals
globals().update(self.__dict__)
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 )
再说一次,这是一种糟糕的做法。
发布于 2009-12-31 13:56:38
实际上,self
不是一个关键字,它只是Python语言中实例方法的第一个参数的常规名称。第一个参数是不能跳过的,因为它是一个方法知道它被调用在你的类的哪个实例上的唯一机制。
https://stackoverflow.com/questions/1984104
复制相似问题