10

How does IPython handle local variables? I have this function that works in the Python shell but will not work in the IPython shell.

def change(key,value):
    global aname
    global alist
    alist.append(key)
    aname.extend(value)

I am using this inside a for loop and which is reading input in from a JSON and other .txt files and adding the keys and value to a list which is then used by another function to save to the database. If I do not do it this way it will be ugly and will use the indexes in my loop.

[change(key,value) for key,value in jsondata.itervalues()]

def storeindatabase():
    do_sothing to the list aname and store
    do_sothing to the alist and store
Michael Currie
  • 13,721
  • 9
  • 42
  • 58
user1940979
  • 895
  • 1
  • 13
  • 29
  • I am using this inside of a for loop and which is reading inputting in from a json and other txt files and adding the keys and value to a list which is then used by another function to save to the database. if am not doing it this way it will be ugly and ill the using indexes in my loop – user1940979 Jun 04 '13 at 18:38
  • 1
    Doesn't matter. If you're not using `=` to assign to the name in your function, `global` does nothing whatsoever. – Wooble Jun 04 '13 at 18:47
  • 1
    protip the first word of sentences is generally capitalized a period or other terminal punctuation usually follows it is nearly impossible to read sentences that are run together please help us read write better – kindall Jun 04 '13 at 19:15
  • The `global` statements are not required in the `change` function. `aname` and `alist` are not defined in `change`, so Python will automatically look for the variables outside the function. This will also work in IPython too, so if you found it didn't, then `aname` and `alist` were likely not defined anywhere - recalculate the cell that defined them, then try to call `change` again. – Rian Rizvi Nov 01 '18 at 22:50
  • I think def storeindatabase() is not needed to illustrate. Can you please remove that if so? – behold Apr 21 '19 at 16:35

2 Answers2

6

Append and extend won't work unless the lists already exist the first time they're called. Declaring them upfront makes it work in notebook as well.

aname=[]
alist=[]
def change(key,value):
    global aname
    global alist
    alist.append(key)
    aname.extend(value)

change(3,[3])
print(alist)
[3]
print(aname)
[4]
behold
  • 538
  • 5
  • 19
5

Beforeword: in the last couple of months this answer has been downvoted considerably. I apology if my words might seem a bit rough, but I insist globals are really harmful, as explained in the documentation linked below. If you consider downvoting further down this answer, please read the documentation and elaborate why you disagree with what's below. To quote an answer linked below: "The reason they are bad is that they allow functions to have hidden (non-obvious, surprising, hard-to-detect) side effects, leading to an increase in complexity, potentially leading to Spaghetti code."

  1. Using globals is very likely to mean wrong engineering. If you need a global, that means you need to redesign your code. That's even more true in python.
  2. when you do really want to use a global (maybe the only acceptable case: singleton, though in python, you'd only scope the singleton more globally than where you use it...), you need to declare your variable as global, and then attribute it a value.

For example:

global bar
bar = []
def foobar():
    bar.append('X')

RTFM:


about the IPython part, my example does work:

In [1]: global bar

In [2]: bar = []

In [3]: def foo():
   ...:     bar.append(3)
   ...:     

In [4]: foo()

In [5]: foo()

In [6]: foo()

In [7]: bar
Out[7]: [3, 3, 3]

and here is another example, that shows global is indeed working, and not the outer scoping:

In [2]: def foo():
   ...:     global bar
   ...:     bar = []
   ...:     

In [3]: def oof():
   ...:     bar.append('x')
   ...:     

In [4]: foo()

In [5]: oof()

In [6]: oof()

In [7]: oof()

In [8]: oof()

In [9]: bar
Out[9]: ['x', 'x', 'x', 'x']

anyway, globals are evil!

zamir
  • 2,144
  • 1
  • 11
  • 23
zmo
  • 24,463
  • 4
  • 54
  • 90
  • 1
    can u try ur own example in ipthon it will not work that is what i want to know and why thanks – user1940979 Jun 04 '13 at 19:07
  • 38
    iPython notebooks are often used for tinkering with new problems. There's nothing wrong with using global variables in this case. This isn't about writing polished code, but rather about why the specific case given by @user1940979 doesn't work. – apdnu Aug 10 '15 at 18:07
  • well, I am using daily python REPL for "tinkering" with new problems (or even old ones), and I never _need_ global (from a python perspective) variables. Of course, like everybody I then do abuse the `__main__` scope where I declare all my variables that I'm working with, those variables being mockup parameters for a function, or just a dataset variable I'm working on. But my experience is that whatever you "tinker" in your REPL, it's likely to end up within a script. So there's rarely any _good_ reason to use python globals, it's always better to properly use the scope. – zmo Aug 13 '15 at 00:04
  • 1
    I'm actually quite stumped to get a comment (and -1) defending using `global` variables within the REPL (or ipython notebook). In your comment, @Thucydides411, you say "*This isn't about writing polished code*", but *polishing* a code is only making some cosmetic work to have it look better (rename variables, add docstring, reformat long lines…). – zmo Aug 13 '15 at 00:14
  • When it comes to using globals, or eval() or any abusing language feature, this is not polishing, those things can and shall be avoided _before_ writing a line of code in the REPL. It can only make your code simpler to use, and that's even more true REPL. – zmo Aug 13 '15 at 00:14
  • 1
    Rather than judge or presume the need of the person asking the question, its probably better to just answer with what you recommend and leave it at that. This could be simply based around exploration and even if its not, not every piece of code needs to be production quality. – 0-0 Apr 09 '17 at 16:13
  • @0-0 well, please read again my former two comments: this is not a question of "production quality", but code design. Using `global` is a fscked up, constraintful, inelegant way of passing a parameter, for which you enforce a name in the outer scope. It's almost never useful, and almost always harmful. If you need a global in a function, then you can use a parameter and pass the variable explicitely. And that's *pythonic*. So I stand by my answer as is, because ***any*** answer talking about globals should include a fair warning. – zmo Apr 10 '17 at 11:01
  • 15
    I see nothing wrong with using `global`. I think you're being elitist. I do it all the time in my PHP code and a friend called Adrian told me it was fine. – l0ck3 Apr 10 '17 at 13:26
  • oh you trollesque pundit, @lock3 – zmo Apr 10 '17 at 14:29
  • 4
    I strongly disagree with your claim that its "almost never useful" This is specifically using globals in within an IPython shell. Its entirely reasonable, and extremely useful to use globals when doing exploration and rapid prototyping. I found your post wholly unhelpful (it doesnt even work) and pretty presumptuous. – 0-0 Apr 14 '17 at 20:54
  • This question and answer are about variables using `global` keyword, that are a way to forward declare and access variables in the global environment. When doing exploration in ipython and you need that feature, then you'd better expose those variables as parameters and keep some control over how they react. Using *closure* on the global scope is something else, and something we all do in REPL work. BTW, I double checked my answer and it does work exactly as it's written and it answered the OP's question. And I'm giving a fair warning and advice in not using a feature considered harmful. – zmo Apr 17 '17 at 10:28
  • I don't see why you insist on saying that globals are fine where they aren't, and I'm far from being the only one to support this. [here](http://wiki.c2.com/?GlobalVariablesAreBad), [here](http://stackoverflow.com/questions/19158339/why-are-global-variables-evil), or [there](https://softwareengineering.stackexchange.com/a/148109/70303) and [there](http://koopman.us/bess/chap19_globals.pdf)… There's so much litterature explaining why globals are wrong. – zmo Apr 17 '17 at 10:36
  • @0-0 said "for prototyping". Not for writing the actual code. What harm can be done about using globals at that moment? Plus, I know that passing a parameter is better code design, but if you need to reuse the same variable in multiple functions, maybe it's simpler to make it global than having to pass it as a parameter multiple times. As long as you know why you are doing it and what should not be done with it, why would that be so serious? Let's say you want to use a boolean for enabling to change the input type in multiple functions, that might be useful. Why should it unleash hell? – Ando Jurai May 30 '17 at 15:03
  • 4
    @zmo, nobody is doing real programming in IPython. IPython is for research and prototyping. – Gabriel Fair Mar 08 '18 at 12:48
  • @GabrielFair you would be surprised… by either those who run scripts using ipython as `#!` interpreter (for some people ipython *is* python), or those who prototype stuff using `global`s and then keep them in the *real* code afterwards (if it's working that way, what could go wrong?). I've had to refactor that kind of code being used in production and '*working well so far*' way too many times… up until '*it was working well, but now it's having an issue, but nothing has changed*'!. – zmo Mar 10 '18 at 11:48
  • There's many problems that can only be solved with a global. One example is in multi-threaded environments or garbage collectors. – Pithikos Feb 05 '19 at 23:26
  • No, those problems need a singleton, but it is _not_ necessary for the singleton to be declared as global, it's just then a convenience. You have many other ways to handle that, including having it passed as parameter to all the functions that need it, using a closure to that end, or declaring it at the root of an included module. – zmo Feb 06 '19 at 11:25
  • This answer introduces opinion but does not address the original question. – BarryPye Dec 06 '19 at 00:13
  • @BarryPye it does answer the original question (as I do explain how to use globals in the OP's context), and I'm not giving an _opinion_ I'm making a sourced statement about why using globals is almost always _wrong_. – zmo Dec 24 '19 at 13:40
  • @zmo - The original question is *How does IPython handle global variables?* You have provided a substantive answer to **why** you should not use global variables. For those who came to this question hoping to find an answer to the original question, your answer does not address the original question. – BarryPye Dec 31 '19 at 05:22
  • @BarryPye I did not provide a substansive answer against globals, but a fair bold warning/disclaimer that using a global shall be avoided. Then I gave precisions on how to use globals. For those who came to this question hoping to find an answer on *How to use globals in IPython?* this is an important warning to be put first. I have 20 years of coding experience and always avoided globals, I gave resources supporting this warning, so instead of dismissing it, understand that you never need globals, when you can use the scope's closure, or even better function parameters. – zmo Jan 06 '20 at 09:50
  • 1
    @zmo / Why does your IPython example work without declaring bar global inside the function again? With a counter integer I need to declare it global inside the function for it to work and I really don't know why... – BUFU Mar 03 '20 at 12:05
  • ah, that's because you've hit an edge case of using globals in python: variable shadowing. You declare `global x; x = 0` in the outter scope, then in the function you do `def foo(): x = x + 1` the right hand side `x` will be the one you defined as global, but on the left hand side you create a new `x` shadowing the former `x`. If you do `def foo(); global x; x = x + 1` then you declare to the compiler that the left hand side `x` is from the global env, and will update that one. My example works because I'm updating an object in global env, never shadowing the variable. – zmo Mar 23 '20 at 16:06
  • Globals and GOTOs are ALWAYS useful. The point of Jupyter Notebooks and Jupyterlabs is HACKS. Quick, Ugly and quickly reiterated. R&D is all about how quick can I answer this question the FIRST TIME. KISS - the reason that the OP wanted to do this, was to trivially simply the creation of objects. Without having to be pedantic. But go ahead, explain how R&D scientists should obey "engineering" pedantic rules. You be YOU. But we asked about a question for US. Not YOU. Maybe read the OP again. Did it say "How would you do this?" or "How can I do this?" – Peter Cibulskis Jun 05 '23 at 13:18
  • Whoa, so much anger in your comment, on a 10 years old answer, where I actually take the time to warn the readers 1. why this is wrong ; 2. how to do what they want. Pardon me if I had a 'pedantic prose'. I'm not a native english writer. Any code you write is code someone else will read again later. And that someone can be you in six months. Also, having a methodology in how you engineer your code will help you get faster to the answer. All in all, you're free to do what you want, but I know some people were helped and decided to better use closures instead of globals, and that makes my day. – zmo Jun 05 '23 at 13:30
  • I came here from google and this is really not helpful and does not answer the question. – HerpDerpington Jun 18 '23 at 21:05
  • @HerpDerpington Why do you say it does not answer the question? I explain why global is never a good solution, when you have scoping, and variable passing. But I still show a couple of examples on how to use global. I'm quite amazed how in 10 years this question is still a flamewar :) – zmo Jul 28 '23 at 15:39