Python and link. Restriction?

I would like to do something like the following:

class Foo(object): def __init__(self): self.member = 10 pass def factory(foo): foo = Foo() aTestFoo = None factory(aTestFoo) print aTestFoo.member 

However, it crashes with AttributeError: 'NoneType' object has no attribute 'member' : the aTestFoo object aTestFoo not changed inside the factory function call.

What is the pythonic way of doing this? Is this a template to avoid? If this is a current error, what is it called?

In C ++, in a function prototype, I would add a reference to a pointer that will be created in the factory ... but maybe this is not what I should think about in Python.

C # has the ref keyword, which allows you to change the link itself, which is really close to the C ++ path. I don't know in Java ... and I'm really surprised at Python.

+4
source share
4 answers

Python does not have access to the link. By the way, one of the few things he shares with Java. Some people describe the transfer of arguments in Python as a call by value (and define values โ€‹โ€‹as links, where a link does not mean what it means in C ++), some people describe it as a pass by reference with arguments, which I find very doubtful ( they redefine it to be used for what Python calls a โ€œlinkโ€, and ultimately with something that has nothing to do with what has been known as link passing for decades), others use terms that are wrong widely used and abused (pop the most common examples are "{pass, call} {object, sharing}"). See โ€œCall by Objectโ€ on effbot.org for a fairly extensive discussion about the problems of various terms, the history, and the shortcomings of some of the arguments for the terms that follow the link and pass by value.

The story, without naming it, is as follows:

  • Each variable, an attribute of an object, an element of a collection, etc. refers to the object.
  • Assignment, passing arguments, etc. create another variable, an attribute of an object, an element of a collection, etc., which refers to the same object, but does not know what other variables, attributes of an object, elements of a collection, etc. relate to this object.
  • Any variable, attribute of an object, element of a collection, etc. can be used to modify an object, as well as any other variable, an attribute of an object, an element of a collection, etc. can be used to monitor this modification.
  • No variable, attribute of an object, element of a collection, etc. does not apply to another variable, an attribute of an object, elements of a collection, etc., and therefore you cannot emulate pass by reference (in the sense of C ++), except for processing the changed object / as your "namespace". This is overly ugly, so don't use it when there is a much simpler alternative (e.g. return value or exceptions or multiple return values โ€‹โ€‹through iterative unpacking).

You can see this as using pointers, but not pointers to pointers (but sometimes pointers to structures containing pointers) to C. And then passing those pointers by value. But do not read too much in this comparison. The Python data model is significantly different from C.

+12
source

You make a mistake here because in Python

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

in Python, variables in the formal argument list are bound to the actual argument objects. objects are shared between the caller and the callee; no "new places" or additional "stores".

(which, of course, is why CLU people call this call-based exchange mechanism.)

and btw, Python functions also do not run in the advanced environment. functional organs have very limited access to the environment.

+9
source

The Assignment Clauses section in Python docs can be interesting.

The = operator in Python acts differently depending on the situation, but in the case when you imagine, it just binds the new object to a new local variable:

 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 

Although it may be more confusing than useful, the dis module can show you a byte code representation of a function that can show how Python works internally. Here is the disassembly of the `factory:

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

What it is, Python loads the global Foo class by name (0) and calls it (3, the instance and call are very similar), and then stores the result in a local variable (6, see STORE_FAST ). Then it loads the default return value of None (9) and returns it (12)

What is the pythonic way of doing this? Is this a template to avoid? If this is a current error, what is it called?

Functions

Factory is rarely required in Python. In the random case, when they are needed, you simply return a new instance from your factory (instead of trying to assign it to the pass-in variable):

 class Foo(object): def __init__(self): self.member = 10 pass def factory(): return Foo() aTestFoo = factory() print aTestFoo.member 
+3
source

Your factory method does not return anything - and by default it will have a return value of None . You assign aTestFoo to None , but you never assign it again - from which your actual error comes from.

Resolving these issues:

 class Foo(object): def __init__(self): self.member = 10 pass def factory(obj): return obj() aTestFoo = factory(Foo) print aTestFoo.member 

This should do what I think you need, although such patterns are not typical of Python (i.e. factory methods).

+1
source

Source: https://habr.com/ru/post/1438616/


All Articles