Создавать уникальный объект каждый раз при использовании композиции объекта? - PullRequest
2 голосов
/ 21 октября 2011

В качестве примера, просто пара фиктивных объектов, которые будут использоваться вместе.FWIW это использует Python 2.7.2.

class Student(object):
    def __init__(self, tool):
        self.tool = tool

    def draw(self):
        if self.tool.broken != True:
            print "I used my tool. Sweet."
        else:
            print "My tool is broken. Wah."

class Tool(object):
    def __init__(self, name):
        self.name = name
        self.broken = False

    def break(self):
        print "The %s busted." % self.name
        self.broken = True

Hammer = Tool(hammer)
Billy = Student(Hammer)
Tommy = Student(Hammer)

Этого кода, наверное, достаточно, вы видите, куда я иду с этим.Если я вызываю Hammer.break (), я вызываю его для того же экземпляра объекта;если молот Билли сломан, то же самое относится и к Томми (в конце концов, это действительно тот же Молот).

Теперь, очевидно, если бы программа ограничивалась только Билли и Томми в качестве экземпляров Студентов, исправление было бы очевидным - создавать больше экземпляровмолотки.Но ясно, что я спрашиваю, потому что это не так просто, хе.Я хотел бы знать, возможно ли создавать объекты, которые появляются как уникальные экземпляры для себя каждый раз, когда они вызваны к существованию.

РЕДАКТИРОВАТЬ: Вид ответов, которые я получаю, приводит меня к мысли, чтоУ меня зияющая дыра в моем понимании реализации.Если у меня есть что-то вроде этого:

class Foo(object):
    pass

class Moo(Foo):
    pass

class Guy(object):
    def __init__(self, thing):
        self.thing = thing

Bill = Guy(Moo())
Steve = Guy(Moo())

Каждый раз, когда я использую Moo (), это отдельный экземпляр, или они оба ссылаются на один и тот же объект?Если они отделены , тогда весь мой вопрос может быть снят, потому что это поможет освободиться для моего разума.

Ответы [ 6 ]

3 голосов
/ 21 октября 2011

Вы должны создать новые экземпляры инструмента для каждого ученика.

class Student(object):
    def __init__(self, tool):
        self.tool = tool

    def draw(self):
        if self.tool.broken != True:
            print "I used my tool. Sweet."
        else:
            print "My tool is broken. Wah."

class Tool(object):
    def __init__(self, name):
        self.name = name
        self.broken = False

    def break(self):
        print "The %s busted." % self.name
        self.broken = True

# Instead of instance, make it a callable that returns a new one
def Hammer():
    return Tool('hammer')

# Pass a new object, instead of the type
Billy = Student(Hammer())
Tommy = Student(Hammer())
2 голосов
/ 21 октября 2011

Я постараюсь быть краток.Хорошо .. Я всегда стараюсь быть кратким, но мой уровень успеха в значительной степени случайный .randint (0, никогда).Так что да.

Лол.Вы даже не смогли быть краткими в объявлении о том, что попытаетесь быть краткими.

Во-первых, нам нужно четко понимать, что означает «призвание к существованию».Предположительно, вы хотите новый молот каждый раз, когда случается self.tool = object.Вам не нужен новый экземпляр каждый раз, например, когда вы получаете доступ к атрибуту инструмента, или вы всегда будете получать новый, предположительно не сломанный, молоток при каждой проверке self.tool.broken.

Параподходы.

Во-первых, дать Tool метод копирования, который создает новый объект, который должен быть равен исходному объекту, но быть другим экземпляром.Например:

class Tool:

    def __init__(self, kind):
        self.kind = kind
        self.broken = False

    def copy(self):
        result = Tool(self.kind)
        result.broken = self.broken
        return result

Затем в init для ученика вы говорите:

    self.tool = tool.copy()

Второй вариант, используйте заводскую функцию.

def makehammer():
    return Tool(hammer)

class Student:
    def __init__(self, factory):
        self.tool = factory()

Billy = Student(makehammer)

Я не могу думать ни о чемВ Python вы можете написать строку self.tool = object и сделать так, чтобы объект автоматически сделал копию, и я не думаю, что вы захотите.Одна вещь, которая мне нравится в Python - это WYSIWYG.Если вы хотите волшебство, используйте C ++.Я думаю, что это затрудняет понимание кода, когда вы не только не можете сказать, что делает строка кода, вы даже не можете сказать, что он делает что-нибудь специальное.

Обратите внимание, что вы можетеПолучите еще больше от фабричного объекта .Например:

class RealisticFactory:
    def __init__(self, kind, failurerate):
        self.kind = kind
        self.failurerate = failurerate

    def make(self):
        result = Tool(self.kind)
        if random.random() < self.failurerate:
            result.broken = True
        if (self.failurerate < 0.01):
            self.failurerate += 0.0001
        return result

factory = RealisticFactory(hammer, 0.0007)
Billy = Student(factory.make)
Tommy = Student(factory.make) # Tommy's tool is slightly more likely to be broken
1 голос
/ 21 октября 2011

Просто вызывайте инструмент («молоток») каждый раз, когда вы хотите создать новый инструмент.

h1 = Tool('hammer')
h2 = Tool('hammer')
Billy = Student(h1)
Tommy = Student(h2)
1 голос
/ 21 октября 2011

Вы можете изменить свои строки следующим образом:

Billy = Student(Tool('hammer'))
Tommy = Student(Tool('hammer'))

Это создаст отдельный экземпляр вашего класса Tool для каждого экземпляра класса Student.проблема с вашим опубликованным примером кода состоит в том, что вы «не вызывали инструмент» (чтобы использовать свои слова) более одного раза.

0 голосов
/ 23 октября 2011

После того, как я увижу смысл ответов здесь и вспомню Zen of Python, я собираюсь ответить на свой вопрос о чёрте, сказав: «Я, наверное, должен был просто подумать об этом».

Я переформулирую свой вопрос в качестве ответа. Предположим, у меня есть эта крошечная программа:

class Item(object):
    def __init__(self):
        self.broken = False

    def smash(self):
        print "This object broke."
        self.broken = True

class Person(object):
    def __init__(self, holding):
        self.holding = holding

    def using(self):
        if self.holding.broken != True:
            print "Pass."
        else:
            print "Fail."

Foo = Person(Item())
Bar = Person(Item())

Foo.holding.smash()
Foo.using()
Bar.using()

Программа вернет «Fail» для Foo.using () и «Pass» для Bar.using (). После фактического размышления о том, что я делаю , "Foo.holding = Item ()" и "Bar.holding = Item ()" - явно разные случаи. Я даже запустил эту дамповую программу, чтобы доказать, что она работает, как я и предполагал, и никаких сюрпризов для вас, профессионалов, не так. Поэтому я снял свой вопрос на том основании, что я на самом деле не использовал свой мозг, когда спросил его . Самое смешное, что с программой, над которой я работал, я уже делал это таким образом, но предполагал, что это был неправильный способ сделать это. Так что спасибо за то, что пошутил.

0 голосов
/ 21 октября 2011

Ой, подождите, я забыл, у Питона есть магия.

class Student:
    def __setattr__(self, attr, value):
        if attr == 'tool':
            self.__dict__[attr] = value.copy()
        else:
            self.__dict__[attr] = value

Но я все еще говорю, что вы должны использовать магию экономно.

...