__setitem__ 在 Python 中为 Point(x,y) 类实现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15774804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
__setitem__ implementation in Python for Point(x,y) class
提问by John Berry
I'm trying to make a Point class in python. I already have some of the functions, like __ str__ , or __ getitem__ implemented, and it works great. The only problem I'm facing is that my implementation of the __ setitem__ does not work, the others are doing fine.
我正在尝试在 python 中创建一个 Point 类。我已经实现了一些函数,比如 __ str__ 或 __ getitem__ ,而且效果很好。我面临的唯一问题是我对 __ setitem__ 的实现不起作用,其他人都做得很好。
Here is my Point class, and the last function is my __ setitem__:
这是我的 Point 类,最后一个函数是我的 __ setitem__:
class point(object):
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return "point(%s,%s)"%(self.x,self.y)
def __getitem__(self,item):
return (self.x, self.y)[item]
def __setitem__(self,x,y):
[self.x, self.y][x]=y
it should work like this:
它应该像这样工作:
p=point(2,3)
p[0]=1 #sets the x coordinate to 1
p[1]=10 #sets the y coordinate to 10
(Am I even right, should the setitem work like this?) Thanks!
(我什至是对的,setitem 应该像这样工作吗?)谢谢!
采纳答案by unutbu
Let self.dataand only self.datahold the coordinate values.
If self.xand self.ywere to also store these values there is a chance self.dataand self.xor self.ywill not get updated consistently.
让self.data且只self.data保存坐标值。如果self.x并且self.y还要存储这些值,则有可能self.data并且self.x或self.y不会一致地更新。
Instead, make xand ypropertiesthat look up their values from self.data.
相反,要x和y性质,从查找它们的值self.data。
class Point(object):
def __init__(self,x=0,y=0):
self.data=[x, y]
def __str__(self):
return "point(%s,%s)"%(self.x,self.y)
def __getitem__(self,item):
return self.data[item]
def __setitem__(self, idx, value):
self.data[idx] = value
@property
def x(self):
return self.data[0]
@property
def y(self):
return self.data[1]
The statement
该声明
[self.x, self.y][x]=y
is interesting but problematic. Let pick it apart:
很有趣但有问题。让我们拆开看看:
[self.x, self.y]causes Python to build a new list, with values self.xand self.y.
[self.x, self.y]导致 Python 构建一个新列表,其中包含值self.x和self.y。
somelist[x]=ycauses Python to assign value yto the xth index of somelist. So this new list somelistgets updated. But this has no effect on self.data, self.xor self.y. That is why your original code was not working.
somelist[x]=y使 Python 为y的x第 th 个索引赋值somelist。所以这个新列表somelist得到更新。但这对self.data,self.x或没有影响self.y。这就是为什么您的原始代码不起作用的原因。
回答by abarnert
Let's strip this down to the bare minimum:
让我们把它精简到最低限度:
x, y = 2, 3
[x, y][0] = 1
print(x)
This will print out 2.
这将打印出来2。
Why?
为什么?
Well, [x, y]is a brand-new list containing two elements. When you do reassign its first member to 1, that just changes the brand-new list, so its first element is now 1instead of 2. It doesn't turn the number 2into the number 1.
嗯,[x, y]是一个包含两个元素的全新列表。当您将其第一个成员重新分配给1时,只会更改全新的列表,因此它的第一个元素现在是1而不是2。它不会将 number2变成 number 1。
Since your code is essentially identical to this, it has the same problem. As long as your variables have immutable values, you can't mutate the variables.
由于您的代码与此基本相同,因此它具有相同的问题。只要您的变量具有不可变值,您就不能改变这些变量。
You couldfix it by doing something like this:
您可以通过执行以下操作来修复它:
x, y = [2], [3]
[x, y][0][0] = 1
print(x[0])
Now you'll get 1.
现在你会得到1.
Why? Well, [x, y]is a new list with two elements, each of which is a list. You're not replacing its first element with something else, you're replacing the first element of its first element with something else. But its first element is the same list as x, so you're also replacing x's first element with something else.
为什么?嗯,[x, y]是一个包含两个元素的新列表,每个元素都是一个列表。你不是用别的东西替换它的第一个元素,你是用别的东西替换它的第一个元素的第一个元素。但是它的第一个元素与 相同x,因此您还用x其他元素替换了的第一个元素。
If this is a bit hard to keep straight in your head… well, that's usually a sign that you're doing something you probably shouldn't be. (Also, the fact that you're using xfor a parameter that means "select xor y" and yfor a parameter that means "new value" makes it a whole lot more confusing…)
如果这有点难以在你的脑海中保持清晰......好吧,这通常表明你正在做一些你可能不应该做的事情。(此外,您使用x的参数表示“选择x或y”,y而参数表示“新值”的事实使它变得更加混乱……)
There are many simpler ways to do the same thing:
有许多更简单的方法可以做同样的事情:
- Use an
if/elsestatement instead of trying to get fancy. - Use a single
listinstead of two integer values:self.values[x] = y. (That's unutbu's answer.) - Use a
dictinstead of two integer values:self.values['xy'[x]] = y. - Use
setattr(self, 'xy'[x], y). - Use a
namedtupleinstead of trying to build the same thing yourself.
- 使用
if/else语句而不是试图花哨。 - 使用单个
list而不是两个整数值:self.values[x] = y. (这是 unutbu 的答案。) - 使用 a
dict而不是两个整数值:self.values['xy'[x]] = y. - 使用
setattr(self, 'xy'[x], y). - 使用 a
namedtuple而不是尝试自己构建相同的东西。
回答by Michael Pratt
What's happening in setitem is it builds a temporary list, sets the value, then throws away this list without changing self.x or self.y. Try this for __setitem__:
setitem 中发生的事情是它构建一个临时列表,设置值,然后在不更改 self.x 或 self.y 的情况下丢弃此列表。试试这个__setitem__:
def __setitem__(self,coord,val):
if coord == 0:
self.x = val
else:
self.y = val
This is quite an abuse of __setitem__, however... I'd advise figuring out a different way of setting the x/y coordinates if possible. Using p.x and p.y is going to be much faster than p[0] and p[1] pretty much no matter how you implement it.
__setitem__然而,这是对 的滥用......如果可能的话,我建议找出一种不同的方式来设置 x/y 坐标。无论您如何实现,使用 px 和 py 都将比 p[0] 和 p[1] 快得多。
回答by jBrushFX
This works in python 2.6 i guess it works for 2.7 as well
这适用于 python 2.6 我猜它也适用于 2.7
The __setitem__method accept 3 arguments (self, index, value)
在__ setitem__方法接受3个参数(自,索引值)
in this case we want to use index as int for retrive the name of the coordinate from __slots__tuple (check the documentation of __slots__is really usefull for performance)
在这种情况下,我们想使用 index as int 来从__ slot__tuple检索坐标的名称(检查__ slot__的文档对性能非常有用)
remember with __slots__only xand yattributes are allowed! so:
记住__插槽__只允许x和y属性!所以:
p = Point()
p.x = 2
print(p.x) # 2.0
p.z = 4 # AttributeError
print(p.z) # AttributeError
This way is faster respect using @propertydecorator (when you start to have 10000+ instances)
这种方式是使用@property装饰器更快的尊重(当您开始拥有 10000 多个实例时)
class Point(object):
@property
def x(self):
return self._data[0] # where self._data = [x, y]
...
so this is my tip for you :)
所以这是我给你的提示:)
class Point(object):
__slots__ = ('x', 'y') # Coordinates
def __init__(self, x=0, y=0):
'''
You can use the constructor in many ways:
Point() - void arguments
Point(0, 1) - passing two arguments
Point(x=0, y=1) - passing keywords arguments
Point(**{'x': 0, 'y': 1}) - unpacking a dictionary
Point(*[0, 1]) - unpacking a list or a tuple (or a generic iterable)
Point(*Point(0, 1)) - copy constructor (unpack the point itself)
'''
self.x = x
self.y = y
def __setattr__(self, attr, value):
object.__setattr__(self, attr, float(value))
def __getitem__(self, index):
'''
p = Point()
p[0] # is the same as self.x
p[1] # is the same as self.y
'''
return self.__getattribute__(self.__slots__[index])
def __setitem__(self, index, value):
'''
p = Point()
p[0] = 1
p[1] = -1
print(repr(p)) # <Point (1.000000, -1.000000)>
'''
self.__setattr__(self.__slots__[index], value) # converted to float automatically by __setattr__
def __len__(self):
'''
p = Point()
print(len(p)) # 2
'''
return 2
def __iter__(self):
'''
allow you to iterate
p = Point()
for coord in p:
print(coord)
for i in range(len(p)):
print(p[i])
'''
return iter([self.x, self.y])
def __str__(self):
return "(%f, %f)" % (self.x, self.y)
def __repr__(self):
return "<Point %s>" % self
回答by theodox
Your may find it a lot easier to use namedtuple for this:
您可能会发现使用 namedtuple 更容易:
from collections import namedtuple
Point= namedtuple('Point', ['x','y'])
fred = Point (1.0, -1.0)
#Result: Point(x=1.0, y=-1.0)
The main drawback is that you can't poke values into a namedtuple - it's immutable. In most applications that's a feature, not a bug
主要的缺点是你不能把值插入到一个命名元组中——它是不可变的。在大多数应用程序中,这是一项功能,而不是错误
回答by Gregory
This is pretty old post, but the solution for your problem is very simple:
这是很老的帖子,但解决您的问题很简单:
class point(object):
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return "point(%s,%s)"%(self.x,self.y)
def __getitem__(self,item):
return self.__dict__[item]
def __setitem__(self,item,value):
self.__dict__[item] = value
Each class has his own dictionary with all properties and methods created inside the class. So with this you can call:
每个类都有自己的字典,其中包含在类中创建的所有属性和方法。所以有了这个,你可以打电话:
In [26]: p=point(1,1)
In [27]: print p
point(1,1)
In [28]: p['x']=2
In [29]: print p
point(2,1)
In [30]: p['y']=5
In [31]: print p
point(2,5)
It is more readable then your "index" like reference.
它比您的“索引”之类的参考更具可读性。
回答by SeasonalShot
Here's an example:
下面是一个例子:
from collections import namedtuple
Deck = namedtuple('cards',['suits','values'])
class FrenchDeck(object):
deck = [str(i) for i in range(2,11)]+list('JQKA')
suits = "heart clubs spades diamond".split()
def __init__(self):
self.totaldecks = [Deck(each,every) for each in self.suits for every in self.deck]
def __len__(self):
return len(self.totaldecks)
def __getitem__(self,index):
return self.totaldecks[index]
def __setitem__(self,key,value):
self.totaldecks[key] = value
CardDeck = FrenchDeck()
CardDeck[0] = "asdd" # needs`__setitem__()`
print CardDeck[0]
If you don't use the __setitem__(), you will get an error
如果你不使用__setitem__(),你会得到一个错误
TypeError: 'FrenchDeck' object does not support item assignment

