我正在尝试创建一个多边形类,当给定用户输入的边和长度时,该类返回区域和周长。但是,我没有尝试将两个变量传递给__init__
方法。边和长度必须是私密的,必须通过用户输入接收。
import math
class Polygon:
use = (input("Enter in the sides and length of sides seperated by a comma"))
ans = use.split(",")
__numofSides = ans[0]
__sideLength = ans[1]
def __init__(self, __numofSides, __sideLength):
self.__numofSides = __numofSides
self.__sideLength = __sideLength
def get__numofSides(self):
self.__numofSides = ans[0]
return __numofSides
def get__sideLength(self):
self.__sideLength = ans[1]
return __sideLength
def perimeter(self, __numofSides,__sideLength):
peri = self. __numofSides * self.__sideLength
return peri
def area(self, __numofSides, __sideLength):
area = (((__sideLength **2) * __numofSides) / (tan(4) *(math.pi/__numofSides)))
return area
def __str___(self,):
print("Number of Sides: {}\n Length of Sides: {}\n" \
"Perimeter is: {}\n Area is: {}".format(__numofSides,__sideLength,peri,area))
def main():
p1 = Polygon()
p1.perimeter()
p1.area()
p1.__str__()
main()
答案 0 :(得分:2)
您似乎对OOP如何在Python中工作有一个基本的误解。实例化一个类时,会调用__init__()
方法,通常会将给定的参数赋给实例变量,如下所示:
class Pet(object):
def __init__(self, name):
self._name = name # argument stored in self._name
然后,无论您想使用哪种方法,都可以通过实例访问它们:
def get_name(self):
return self._name
请注意,所有此方法都会将self._name
返回给调用方。使用decorators:
@property
def name(self):
return self._name
与get_name()
相比,这种优势是双重的。首先,您可以调用没有括号的方法,就像它是一个实例变量一样:
my_pet = Pet('Rosita')
print(my_pet.name)
>> Rosita
其次,如果用户后来尝试用其他东西覆盖它,那么Python会引发一个AttributeError:
my_pet = Pet('Rosita')
my_pet.name = 'Maggie'
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in <module>
>> AttributeError: can't set attribute
关于你的__repr__
方法,我认为你的意思是:
def __repr__(self):
return "<Polygon sides={}; length={}; perimeter={}; area={}>".format(
self.sides, self.side_length, self.perimeter, self.area)
执行__repr__
或print(my_polygon)
时会调用 str(my_polygon)
,因此它应返回一个字符串。
最后,您可能已经注意到我已使用一个前导下划线而不是两个来命名实例变量。如果您希望类的用户知道特定的实例变量是“私有的”并且他们不应该使用它,那么最好在其名称前面加上一个下划线。这样做的原因是它允许您使用相同名称的acessor方法和实例变量,同时避免使用name mangling。具有两个前导下划线的名称被破坏,因此通常不建议使用。
考虑到所有这些因素,这里是对代码的重写:
import math
class RegularPolygon(object):
def __init__(self, sides, side_length):
self._sides = sides
self._side_length = side_length
@property
def sides(self):
return self._sides
@property
def side_length(self):
return self._side_length
@property
def perimeter(self):
return self.sides * self.side_length
@property
def area(self):
return ((self.side_length**2 * self._sides)
/ (4 * math.tan(math.pi / self.sides)))
def __repr__(self):
return "<Polygon sides={}; length={}; perimeter={}; area={}>".format(
self.sides, self.side_length, self.perimeter, self.area)
if __name__ == '__main__':
poly = RegularPolygon(5, 7)
print(poly)
答案 1 :(得分:2)
您的问题是,您没有向__init__
传递任何内容,当您执行此操作时,您正在创建类级变量:
class Foo:
x = 42
y = input("Don't do this, this is bad")
这些仅每个程序*也会被调用一次,因此如果你需要的话,你将永远无法提供不同的值。 如果要将参数传递给函数,则在创建类的实例时执行此操作:
class Polygon:
def __init__(self, num_of_sides, side_length):
self._num_of_sides = num_of_sides
self._side_length = side_length
正如其他人所提到的,Python中的私有变量实际上 无法访问,尽管有一些方法可以强制它们是不可变的,因为jonrsharpe指出了他的答案。您还可以调查__slots__
其他选项。
* 每次导入,每个程序通常一次,但有一些方法可以解决这个问题,但情况更糟。除非您参加混淆的Python比赛,否则不要这样做。
答案 2 :(得分:1)
以下是您的代码的快速代码审查(无数学考虑):
您可以继承object
(与Python 2兼容):
class Polygon(object):
简化参数名称,不要使用双下划线:
def __init__(self, sides, length):
self.sides = sides
self.length = length
使用实例变量self.sides
和self.length
,删除参数:
def perimeter(self):
return self.sides * self.length
将tan()
替换为math.tan()
def area(self):
return ((self.length ** 2) * self.sides) / (math.tan(4) * (math.pi / self.sides))
在main()
函数中:
(使用Python 2,使用raw_input
代替input
。)
use = input("Enter in the sides and length of sides separated by a comma: ")
ans = use.split(",")
将字符串值转换为int
sides = int(ans[0])
length = int(ans[1])
p1 = Polygon(sides, length)
使用print()
功能打印结果
print(p1.perimeter())
print(p1.area())
答案 3 :(得分:1)
以下是我写这个的方法:
from collections import namedtuple
from math import pi, tan
class Polygon(namedtuple('Polygon', 'sides,length')):
PROMPT = 'Enter in the number and length of sides, separated by a comma'
@property
def perimeter(self):
return self.sides * self.length
@property
def area(self):
return (self.sides * (self.length ** 2)) / (4 * tan(pi / self.sides))
@classmethod
def from_input(cls):
return cls(*map(int, input(cls.PROMPT).split(',')))
为什么呢?这是因为:
从namedtuple
继承使得实例不可变,因此您无法在初始创建后重新分配sides
和length
,同时为您提供合理的相等比较和{{1格式免费:
__repr__
使用@property
表示您可以再次以只读方式轻松访问计算出的属性:
>>> square = Polygon(4, 1)
>>> square
Polygon(sides=4, length=1)
>>> square.sides = 5
Traceback (most recent call last):
File "python", line 1, in <module>
AttributeError: can't set attribute
使用@classmethod
保留用于在类所属的用户输入中创建对象的逻辑:
>>> square.area
1.0000000000000002
>>> square.perimeter
4
>>> square.area = 7
Traceback (most recent call last):
File "python", line 1, in <module>
AttributeError: can't set attribute
在您当前的实现中,您的输入在定义类时运行一次,而不是在用户实际想要创建实例时运行。
注意:我假设您使用的是Python 3.x - 如果不是,您应该使用
>>> hexagon = Polygon.from_input() Enter in the number and length of sides, separated by a comma 6,2 >>> hexagon Polygon(sides=6, length=2) >>> hexagon.area 10.392304845413264 >>> hexagon.perimeter 12
。此外,您的类应该从raw_input
继承 你没有使用例如object
。