Передача Python и ссылок. Ограничение?

Я хотел бы сделать что-то вроде следующего:

class Foo(object):
    def __init__(self):
        self.member = 10
        pass

def factory(foo):
    foo = Foo()

aTestFoo = None
factory(aTestFoo)

print aTestFoo.member

Однако он падает сAttributeError: 'NoneType' object has no attribute 'member': the object aTestFoo не был изменен внутри вызова функцииfactory.

Каков питонный способ выполнения этого? Это шаблон, чтобы избежать? Если это текущая ошибка, как она называется?

В C ++, в прототипе функции, я бы добавил ссылку на указатель, который будет создан на фабрике ... но, возможно, это не тот тип вещей, о котором я должен думать в Python.

В C # есть ключевое словоref это позволяет изменить саму ссылку, действительно близкую к C ++. Я не знаю, на Java ... и я удивляюсь на Python.

 stranac09 окт. 2012 г., 12:28
Итак, ваша проблема в том, что python не передает объекты по ссылке.
 Stephane Rolland09 окт. 2012 г., 12:31
Да ... как подробно объясняют ответы Делнана и Рахула.
 Rahul Gautam09 окт. 2012 г., 12:44
взглянутьstackoverflow.com/questions/291978/…ответ краткий и частный
 stranac09 окт. 2012 г., 12:18
Что вы на самом деле пытаетесь сделать здесь? Кроме того, зачем вам заводская функция?
 Stephane Rolland09 окт. 2012 г., 12:22
Рассматриваемый код относительно прост, чтобы ответить на мой вопрос. Конечно, возврат в фабричную функцию с прямым присваиванием будет работать. Но поскольку я наткнулся на это, я стараюсь предпринять.This problem точно

Ответы на вопрос(4)

возвращаемое значениеNone, Вы назначаетеaTestFoo вNone, но никогда не переназначайте его - отсюда ваша фактическая ошибка.

Исправление этих проблем:

class Foo(object):
    def __init__(self):
        self.member = 10
        pass

def factory(obj):
    return obj()

aTestFoo = factory(Foo)
print aTestFoo.member

Это должно сделать то, что я думаю, что вы после, хотя такие шаблоны не являются типичными в Python (то есть, фабричные методы).

 09 окт. 2012 г., 12:38
Я бы позвонилfactory()параметрclsскорее, чемobj...
 09 окт. 2012 г., 12:26
Я никогда не говорил, что это ошибка? Но я удалил это - так или иначе, я не уверен, как / что вы ожидали от исходного кода, поскольку вы ничего не возвращали и просто печатали элементNone, Это был бы тот же результат, если бы только что сделалprint None.foo
Решение Вопроса

одна из немногих вещей, которыми он делится с Java. Некоторые люди описывают передачу аргументов в Python как вызов по значению (и определяют значения как ссылки, где ссылка означает не то, что означает в C ++), некоторые люди описывают это как передачу по ссылке с доводами, которые я считаю довольно сомнительными (они переопределяют это использовать то, что Python называет «ссылка», и в конечном итоге получить что-то, что не имеет ничего общего с тем, что известно как передача по ссылке в течение десятилетий), другие используют термины, которые не так широко используются и злоупотребляют (популярные примеры & quot; {pass, call} by {object, share} & quot;). УвидетьЗвонок по объекту на effbot.org для довольно обширного обсуждения определений различных терминов, истории и недостатков в некоторых аргументах для терминов, передаваемых по ссылке и передаваемых по значению.

Короткая история без названия выглядит так:

Every variable, object attribute, collection item, etc. refers to an object. Assignment, argument passing, etc. create another variable, object attribute, collection item, etc. which refers to the same object but has no knowledge which other variables, object attributes, collection items, etc. refer to that object. Any variable, object attribute, collection item, etc. can be used to modify an object, and any other variable, object attribute, collection item, etc. can be used to observe that modification. No variable, object attribute, collection item, etc. refers to another variable, object attribute, collection items, etc. and thus you can't emulate pass by reference (in the C++ sense) except by treating a mutable object/collection as your "namespace". This is excessively ugly, so don't use it when there's a much easier alternative (such as a return value, or exceptions, or multiple return values via iterable unpacking).

Вы можете рассмотреть это как использование указателей, но не указателей на указатели (но иногда указатели на структуры, содержащие указатели) в C. И затем передачу этих указателей по значению. Но не читайте слишком много в этом сравнении. Модель данных Python значительно отличается от модели C.

"We call the argument passing technique _call by sharing_,
because the argument objects are shared between the
caller and the called routine.  This technique does not
correspond to most traditional argument passing techniques
(it is similar to argument passing in LISP).  In particular it
is not call by value because mutations of arguments per-
formed by the called routine will be visible to the caller.
And it is not call by reference because access is not given
to the variables of the caller, but merely to certain objects."

в Python переменные в списке формальных аргументов связаны с фактические объекты аргумента. объектыshared между звонящим и вызываемый абонент; нет "свежих мест" или дополнительные "магазины" участвует.

(что, конечно, именно поэтому люди CLU назвали этот механизм "вызовом путем обмена & Quot ;.)

and btw, Python functions doesn't run in an extended environment, either. function bodies have very limited access to the surrounding environment.

Заявления о назначении раздел документации по Python может быть интересным.

= Оператор в Python действует по-разному в зависимости от ситуации, но в случае, если вы представляете, он просто связывает новый объект с новой локальной переменной:

def factory(foo):
    # This makes a new instance of Foo,
    # and binds it to a local variable `foo`,
    foo = Foo()

# This binds `None` to a top-level variable `aTestFoo`
aTestFoo = None

# Call `factory` with first argument of `None`
factory(aTestFoo)

print aTestFoo.member

Хотя это может быть скорее запутанным, чем полезным,dis Модуль может показать вам представление функции в байт-коде, которое может показать внутреннюю работу Python. Вот разборка "фабрики":

>>> dis.dis(factory)
  4           0 LOAD_GLOBAL              0 (Foo)
              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (foo)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE        

Что это говорит, Python загружает глобальныйFoo класс по имени (0) и вызывает его (3, создание экземпляра и вызов очень похожи), затем сохраняет результат в локальной переменной (6, см.STORE_FAST). Затем он загружает возвращаемое значение по умолчаниюNone (9) и возвращает его (12)

What is the pythonic way of performing that ? Is it a pattern to avoid ? If it is a current mistake, how is it called ?

Фабричные функции редко нужны в Python. В тех случаях, когда они необходимы, вы просто возвращаете новый экземпляр с вашей фабрики (вместо того, чтобы пытаться присвоить его переданной переменной):

class Foo(object):
    def __init__(self):
        self.member = 10
        pass

def factory():
    return Foo()

aTestFoo = factory()

print aTestFoo.member

Ваш ответ на вопрос