2016-11-18 8 views
0

Я пытаюсь создать класс многоугольника, который возвращает область и периметр, если заданы стороны и длина с пользовательского ввода. Тем не менее, он не принимает две переменные, которые я пытаюсь передать в метод __init__. Стороны и длина должны быть конфиденциальными и должны приниматься через вход пользователя.Пользовательский ввод не передается __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

Если вы собираетесь опубликовать код Python, убедитесь, что вы точно воспроизводите свои отступы. Плохой с отступом код Python - это нонсенс. – khelwood

+0

Не используйте два символа подчеркивания, они переводят интерпретатор Python на имя. –

+2

* «Стороны и длина должны быть частными» * - тогда Python, вероятно, не является для вас языком, даже если «__name_mangling» они доступны. Если вы хотите, чтобы он был неизменным, подумайте о подклассе 'namedtuple'. хотите защищенные атрибуты, используйте '@ property'. – jonrsharpe

ответ

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()) 
2

Вы, кажется, имеют фундаментальное непонимание того, как работает ООП в Python. При создании экземпляра класса, метод __init__() называется, и, как правило, присваиваются аргументы, переданные переменные экземпляра, например, так:

class Pet(object): 

    def __init__(self, sides): 
     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), чтобы он возвращал строку.

Наконец, вы, возможно, заметили, что я назвал переменные экземпляра одним ведущим символом подчеркивания, а не двумя. Если вы хотите, чтобы пользователи вашего класса знали, что конкретная переменная экземпляра является «конфиденциальной», и им не следует связываться с ней, лучше прикрепить ее имя только одним подчеркиванием. Причиной этого является то, что он позволяет вам использовать методы-члены и переменные экземпляра с тем же именем, в то же время избегая 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

Вот как я это пишу:

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 после первоначального создания, давая Вам разумное сравнение равенства и __repr__ форматирования бесплатно:

    >>> 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 
    
  • Использование @property означает, что вы можете легко получить доступ к вычисленным атрибутам, снова в режиме только для чтения:

    >>> 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 
    
  • Использование @classmethod сохраняет логику для создания объекта из пользовательского ввода в классе, где она принадлежит:

    >>> 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 
    

    В текущей реализации, ваш вход выполняется один раз, когда класс определяется не тогда, когда пользователь на самом деле хочет создать экземпляр.

Note: I've assumed you're using Python 3.x - if not you should use raw_input . Also your classes should inherit from object , when you're not using e.g. namedtuple .

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__ для других вариантов.

*Per import, which is usually once per program, but there are ways you can get around that, but that's even worse. Unless you're going for an obfuscated Python contest, don't do that.