问题:如何避免在Python中显式的“自我”?
我通过遵循一些pygame教程来学习Python 。
在其中我发现了关键字self的广泛使用,并且主要来自Java背景,我发现自己一直忘记输入self。例如,代替self.rect.centerx
我输入rect.centerx
,因为对我来说,rect已经是该类的成员变量。
Java的并行的我能想到的这种情况是有前缀成员变量的所有引用与此。
我是否在所有成员变量前面加上self前缀,还是有一种方法可以声明它们,从而避免这样做呢?
即使我的建议不是pythonic,我仍然想知道是否有可能。
我看了这些相关的SO问题,但它们并不能完全回答我的要求:
回答 0
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.>
请记住,这两个例子都是极端的,您不会每天看到它们,我也不建议您经常编写这样的代码,但是它们确实显示了明确要求自我的各个方面。
回答 1
先前的答案基本上都是“您不能”或“您不应”的变体。我同意后一种观点,但从技术上来说,这个问题尚未得到解答。
此外,出于合理的原因,有人可能想要按照实际问题的要求去做某事。我有时遇到的一件事是冗长的数学方程式,其中使用长名称会使方程式无法识别。以下是在固定示例中如何执行此操作的几种方法:
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)
基本上就是问题的实质所在,但是让我清楚一点,我认为这通常不是一个好主意。
欲了解更多信息,并通过类变量,甚至函数的方式进行迭代,看答案和讨论这个问题。有关动态命名变量的其他方法的讨论以及为什么通常这样做不是一个好主意,请参阅此博客文章。。
更新:似乎没有办法在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 )
总体而言,这将是可怕的做法。
回答 2
实际上self
不是关键字,它只是Python中实例方法的第一个参数的常规名称。而且第一个参数不能被跳过,因为它是方法知道该类的哪个实例被调用的唯一机制。
回答 3
您可以使用任何想要的名称,例如
class test(object):
def function(this, variable):
this.variable = variable
甚至
class test(object):
def function(s, variable):
s.variable = variable
但您仍然无法使用范围的名称。
我不建议您使用与自己不同的东西,除非您有令人信服的理由,因为这会使有经验的pythonista陌生。
回答 4
是的,您必须始终指定self
,因为根据python哲学,显式要比隐式好。
您还将发现使用python进行编程的方式与使用Java进行编程的方式非常不同,因此,self
由于您没有在对象内部投影所有内容,因此使用的趋势会减少。相反,您可以更多地使用模块级功能,可以更好地对其进行测试。
顺便说说。我最初讨厌它,现在讨厌相反的东西。缩进驱动的流量控制也是如此。
回答 5
“自身”是类的当前对象实例的常规占位符。当您要引用类中的对象的属性,字段或方法时,就好像在引用“自身”一样使用它。但是,为了使它简短一些,Python编程领域中的某个人开始使用“ self”,其他领域则使用“ this”,但是它们使它成为无法替换的关键字。我宁愿使用“它”来增加代码的可读性。这是Python的优点之一-您可以自由选择对象实例的占位符,而不是“自身”。自我示例:
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)
现在我们用“其”替换“自我”:
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)
现在哪个更易读?
回答 6
self是python语法的一部分,用于访问对象的成员,因此恐怕您会受其束缚
回答 7
实际上,您可以使用Armin Ronacher演讲“ 5年的坏主意”中的食谱“自卑自我”(用Google搜索)。
这是一个非常聪明的秘方,几乎所有阿明·罗纳赫(Armin Ronacher)的著作都如此,但我认为这个主意并不吸引人。我想我更愿意在C#/ Java中对此进行明确说明。
更新。链接到“坏主意食谱”:https://speakerdeck.com/mitsuhiko/5-years-of-bad-ideas?slide = 58
回答 8
是的,自我很乏味。但是,更好吗?
class Test:
def __init__(_):
_.test = 'test'
def run(_):
print _.test
回答 9
混合方法效果最好 您所有实际进行计算的类方法都应移到闭包中,并且清理语法的扩展应保留在类中。将闭包塞入类,将类像命名空间一样对待。闭包本质上是静态函数,因此甚至在类中也不需要self *。
回答 10
我认为,如果有一个“成员”语句和“全局”语句,那将更容易且更具可读性,因此您可以告诉解释器哪些是类的对象成员。