python setup.py uninstall

Questions : python setup.py uninstall

I have installed a python package with python setup.py install.

How do I uninstall it?

Total Answers: 18 Answers 18


Popular Answers:

  1. Note: Avoid using python setup.py install use pip install .

    You need to remove all files manually, and also undo any other stuff that installation did manually.

    If you don’t know the list of all files, you can reinstall it with the --record option, and take a look at the list this produces.

    To record a list of installed files, you can use:

    python setup.py install --record files.txt 

    Once you want to uninstall you can use xargs to do the removal:

    xargs rm -rf < files.txt 

    Or if you’re running Windows, use Powershell:

    Get-Content files.txt | ForEach-Object {Remove-Item $_ -Recurse -Force} 

    Then delete also the containing directory, e.g. /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/my_module-0.1.egg/ on macOS. It has no files, but Python will still import an empty module:

    >>> import my_module >>> my_module.__file__ None 

    Once deleted, Python shows:

    >>> import my_module Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'my_module' 
  2. The #1 answer has problems:

    • Won’t work on mac.
    • If a file is installed which includes spaces or other special characters, the xargs command will fail, and delete any files/directories which matched the individual words.
    • the -r in rm -rf is unnecessary and at worst could delete things you don’t want to.

    Instead, for unix-like:

    sudo python setup.py install --record files.txt # inspect files.txt to make sure it looks ok. Then: tr 'n' '' < files.txt | xargs -0 sudo rm -f -- 

    And for windows:

    python setup.py bdist_wininst dist/foo-1.0.win32.exe 

    There are also unsolvable problems with uninstalling setup.py install which won’t bother you in a typical case. For a more complete answer, see this wiki page:

    https://ofswiki.org/wiki/Uninstalling_setup.py_install

  3. Now python gives you the choice to install pip during the installation (I am on Windows, and at least python does so for Windows!). Considering you had chosen to install pip during installation of python (you don’t actually have to choose because it is default), pip is already installed for you. Then, type in pip in command prompt, you should see a help come up. You can find necessary usage instructions there. E.g. pip list shows you the list of installed packages. You can use

    pip uninstall package_name 

    to uninstall any package that you don’t want anymore. Read more here (pip documentation).

  4. Not exactly answering the question, but something that helps me every day:

    Install your packages with

    pip install . 

    This puts the package in $HOME/.local. Uninstall with

    pip uninstall <package_name> 
  5. The lazy way: simply uninstall from the Windows installation menu (if you’re using Windows), or from the rpm command, provided you first re-install it after creating a distribution package.

    For example,

    python setup.py bdist_wininst dist/foo-1.0.win32.exe 

    (“foo” being an example of course).

  6. Go to your python package directory and remove your .egg file, e.g.: In python 2.5(ubuntu): /usr/lib/python2.5/site-packages/

    In python 2.6(ubuntu): /usr/local/lib/python2.6/dist-packages/

  7. Probably you can do this as an alternative :-

    1) Get the python version –

    [linux machine]# python Python 2.4.3 (#1, Jun 18 2012, 14:38:55)  

    -> The above command gives you the current python Version which is 2.4.3

    2) Get the installation directory of python –

    [linux machine]# whereis python python: /usr/bin/python /usr/bin/python2.4 /usr/lib/python2.4 /usr/local/bin/python2.5 /usr/include/python2.4 /usr/share/man/man1/python.1.gz 

    -> From above command you can get the installation directory which is – /usr/lib/python2.4/site-packages

    3) From here you can remove the packages and python egg files

    [linux machine]# cd /usr/lib/python2.4/site-packages [linux machine]# rm -rf paramiko-1.12.0-py2.4.egg paramiko-1.7.7.1-py2.4.egg paramiko-1.9.0-py2.4.egg 

    This worked for me.. And i was able to uninstall package which was troubling me 🙂

  8. I think you can open the setup.py, locate the package name, and then ask pip to uninstall it.

    Assuming the name is available in a ‘METADATA’ variable:

    pip uninstall $(python -c "from setup import METADATA; print METADATA['name']") 
  9. At {virtualenv}/lib/python2.7/site-packages/ (if not using virtualenv then {system_dir}/lib/python2.7/dist-packages/)

    • Remove the egg file (e.g. distribute-0.6.34-py2.7.egg)
    • If there is any from file easy-install.pth, remove the corresponding line (it should be a path to the source directory or of an egg file).
  10. Extending on what Martin said, recording the install output and a little bash scripting does the trick quite nicely. Here’s what I do…

    for i in $(less install.record); sudo rm $i; done; 

    And presto. Uninstalled.

  11. If you still have files that are supposed to be deleted after re-installing a package, make sure the folder build is also deleted. Therefore, assuming that pkg is the package you want to delete:

    rm -r $(python3 -c "import pkg; print(pkg.__path__[0] + '*' )") rm -rf build 

    Obove work out for python3 and delete the package and its *.egg-info file

  12. It might be better to remove related files by using bash to read commands, like the following:

    sudo python setup.py install --record files.txt sudo bash -c "cat files.txt | xargs rm -rf" 
  13. I had run “python setup.py install” at some point in the past accidentally in my global environment, and had much difficulty uninstalling. These solutions didn’t help. “pip uninstall ” didn’t work with “Can’t uninstall ‘splunk-appinspect’. No files were found to uninstall.” “sudo pip uninstall ” didn’t work “Cannot uninstall requirement splunk-appinspect, not installed”. I tried uninstalling pip, deleting the pip cache, searching my hard drive for the package, etc…

    “pip show ” eventually led me to the solution, the “Location:” was pointing to a directory, and renaming that directory caused the packaged to be removed from pip’s list. I renamed the directory back, and it didn’t reappear in pip’s list, and now I can reinstall my package in a virtualenv.

  14. I had run python setup.py install once in my PyCharm, it installs all the packages into my conda base environment. Later when I want to remove all these packages, pip uninstall does not work. I had to delete them from /anaconda3/lib/python3.7/site-packages manually 🙁

    So I don’t see the reason why they use setup.py instead of writing requirements.txt file. The requirement file can be used to install packages in virtual environment and won’t mess with system python packages.

  15. I have a develop egg link set up with python setup.py develop under a conda environment and with pip uninstall <packagename> the egg link is removed. At least in this scenario, pip uninstall is one way to do this.

  16. Yet another TL;DR

    Iterator on list: next() returns the next element of the list

    Iterator generator: next() will compute the next element on the fly (execute code)

    You can see the yield/generator as a way to manually run the control flow from outside (like continue loop one step), by calling next, however complex the flow.

    Note: The generator is NOT a normal function. It remembers the previous state like local variables (stack). See other answers or articles for detailed explanation. The generator can only be iterated on once. You could do without yield, but it would not be as nice, so it can be considered ‘very nice’ language sugar.

  17. Here’s a simple yield based approach, to compute the fibonacci series, explained:

    def fib(limit=50): a, b = 0, 1 for i in range(limit): yield b a, b = b, a+b 

    When you enter this into your REPL and then try and call it, you’ll get a mystifying result:

    >>> fib() <generator object fib at 0x7fa38394e3b8> 

    This is because the presence of yield signaled to Python that you want to create a generator, that is, an object that generates values on demand.

    So, how do you generate these values? This can either be done directly by using the built-in function next, or, indirectly by feeding it to a construct that consumes values.

    Using the built-in next() function, you directly invoke .next/__next__, forcing the generator to produce a value:

    >>> g = fib() >>> next(g) 1 >>> next(g) 1 >>> next(g) 2 >>> next(g) 3 >>> next(g) 5 

    Indirectly, if you provide fib to a for loop, a list initializer, a tuple initializer, or anything else that expects an object that generates/produces values, you’ll “consume” the generator until no more values can be produced by it (and it returns):

    results = [] for i in fib(30): # consumes fib results.append(i) # can also be accomplished with results = list(fib(30)) # consumes fib 

    Similarly, with a tuple initializer:

    >>> tuple(fib(5)) # consumes fib (1, 1, 2, 3, 5) 

    A generator differs from a function in the sense that it is lazy. It accomplishes this by maintaining it’s local state and allowing you to resume whenever you need to.

    When you first invoke fib by calling it:

    f = fib() 

    Python compiles the function, encounters the yield keyword and simply returns a generator object back at you. Not very helpful it seems.

    When you then request it generates the first value, directly or indirectly, it executes all statements that it finds, until it encounters a yield, it then yields back the value you supplied to yield and pauses. For an example that better demonstrates this, let’s use some print calls (replace with print "text" if on Python 2):

    def yielder(value): """ This is an infinite generator. Only use next on it """ while 1: print("I'm going to generate the value for you") print("Then I'll pause for a while") yield value print("Let's go through it again.") 

    Now, enter in the REPL:

    >>> gen = yielder("Hello, yield!") 

    you have a generator object now waiting for a command for it to generate a value. Use next and see what get’s printed:

    >>> next(gen) # runs until it finds a yield I'm going to generate the value for you Then I'll pause for a while 'Hello, yield!' 

    The unquoted results are what’s printed. The quoted result is what is returned from yield. Call next again now:

    >>> next(gen) # continues from yield and runs again Let's go through it again. I'm going to generate the value for you Then I'll pause for a while 'Hello, yield!' 

    The generator remembers it was paused at yield value and resumes from there. The next message is printed and the search for the yield statement to pause at it performed again (due to the while loop).

  18. yield is similar to return. The difference is:

    yield makes a function iterable (in the following example primes(n = 1) function becomes iterable).
    What it essentially means is the next time the function is called, it will continue from where it left (which is after the line of yield expression).

    def isprime(n): if n == 1: return False for x in range(2, n): if n % x == 0: return False else: return True def primes(n = 1): while(True): if isprime(n): yield n n += 1 for n in primes(): if n > 100: break print(n) 

    In the above example if isprime(n) is true it will return the prime number. In the next iteration it will continue from the next line

    n += 1 
  19. In Python generators (a special type of iterators) are used to generate series of values and yield keyword is just like the return keyword of generator functions.

    The other fascinating thing yield keyword does is saving the state of a generator function.

    So, we can set a number to a different value each time the generator yields.

    Here’s an instance:

    def getPrimes(number): while True: if isPrime(number): number = yield number # a miracle occurs here number += 1 def printSuccessivePrimes(iterations, base=10): primeGenerator = getPrimes(base) primeGenerator.send(None) for power in range(iterations): print(primeGenerator.send(base ** power)) 
  20. In [4]: def make_cake(numbers): ...: for i in range(numbers): ...: yield 'Cake {}'.format(i) ...: In [5]: factory = make_cake(5)
  21. All of the answers here are great; but only one of them (the most voted one) relates to how your code works. Others are relating to generators in general, and how they work.

    So I won’t repeat what generators are or what yields do; I think these are covered by great existing answers. However, after spending few hours trying to understand a similar code to yours, I’ll break it down how it works.

    Your code traverse a binary tree structure. Let’s take this tree for example:

     5 /  3 6 /   1 4 8 

    And another simpler implementation of a binary-search tree traversal:

    class Node(object): .. def __iter__(self): if self.has_left_child(): for child in self.left: yield child yield self.val if self.has_right_child(): for child in self.right: yield child 

    The execution code is on the Tree object, which implements __iter__ as this:

    def __iter__(self): class EmptyIter(): def next(self): raise StopIteration if self.root: return self.root.__iter__() return EmptyIter() 

    The while candidates statement can be replaced with for element in tree; Python translate this to

    it = iter(TreeObj) # returns iter(self.root) which calls self.root.__iter__() for element in it: .. process element .. 

    Because Node.__iter__ function is a generator, the code inside it is executed per iteration. So the execution would look like this:

    1. root element is first; check if it has left childs and for iterate them (let’s call it it1 because its the first iterator object)
    2. it has a child so the for is executed. The for child in self.left creates a new iterator from self.left, which is a Node object itself (it2)
    3. Same logic as 2, and a new iterator is created (it3)
    4. Now we reached the left end of the tree. it3 has no left childs so it continues and yield self.value
    5. On the next call to next(it3) it raises StopIteration and exists since it has no right childs (it reaches to the end of the function without yield anything)
    6. it1 and it2 are still active – they are not exhausted and calling next(it2) would yield values, not raise StopIteration
    7. Now we are back to it2 context, and call next(it2) which continues where it stopped: right after the yield child statement. Since it has no more left childs it continues and yields it’s self.val.

    The catch here is that every iteration creates sub-iterators to traverse the tree, and holds the state of the current iterator. Once it reaches the end it traverse back the stack, and values are returned in the correct order (smallest yields value first).

    Your code example did something similar in a different technique: it populated a one-element list for every child, then on the next iteration it pops it and run the function code on the current object (hence the self).

    I hope this contributed a little to this legendary topic. I spent several good hours drawing this process to understand it.

  22. The yield keyword in Python used to exit from the code without disturbing the state of local variables and when again the function is called the execution starts from the last point where we left the code.

    The below example demonstrates the working of yield:

    def counter(): x=2 while x < 5: yield x x += 1 print("Initial value of x: ", counter()) for y in counter(): print(y) 

    The above code generates the Below output:

    Initial value of x: <generator object counter at 0x7f0263020ac0> 2 3 4 
  23. Can also send data back to the generator!

    Indeed, as many answers here explain, using yield creates a generator.

    You can use the yield keyword to send data back to a “live” generator.

    Example:

    Let’s say we have a method which translates from english to some other language. And in the beginning of it, it does something which is heavy and should be done once. We want this method run forever (don’t really know why.. :)), and receive words words to be translated.

    def translator(): # load all the words in English language and the translation to 'other lang' my_words_dict = {'hello': 'hello in other language', 'dog': 'dog in other language'} while True: word = (yield) yield my_words_dict.get(word, 'Unknown word...') 

    Running:

    my_words_translator = translator() next(my_words_translator) print(my_words_translator.send('dog')) next(my_words_translator) print(my_words_translator.send('cat')) 

    will print:

    dog in other language Unknown word... 

    To summarise:

    use send method inside a generator to send data back to the generator. To allow that, a (yield) is used.

  24. yield in python is in a way similar to the return statement, except for some differences. If multiple values have to be returned from a function, return statement will return all the values as a list and it has to be stored in the memory in the caller block. But what if we don’t want to use extra memory? Instead, we want to get the value from the function when we need it. This is where yield comes in. Consider the following function :-

    def fun(): yield 1 yield 2 yield 3 

    And the caller is :-

    def caller(): print ('First value printing') print (fun()) print ('Second value printing') print (fun()) print ('Third value printing') print (fun()) 

    The above code segment (caller function) when called, outputs :-

    First value printing 1 Second value printing 2 Third value printing 3 

    As can be seen from above, yield returns a value to its caller, but when the function is called again, it doesn’t start from the first statement, but from the statement right after the yield. In the above example, “First value printing” was printed and the function was called. 1 was returned and printed. Then “Second value printing” was printed and again fun() was called. Instead of printing 1 (the first statement), it returned 2, i.e., the statement just after yield 1. The same process is repeated further.

  25. Simple answer

    When function contains at least one yield statement, the function automaticly becomes generator function. When you call generator function, python executes code in the generator function until yield statement occur. yield statement freezes the function with all its internal states. When you call generator function again, python continues execution of code in the generator function from frozen position, until yield statement occur again and again. The generator function executes code until generator function runs out without yield statement.

    Benchmark

    Create a list and return it:

    def my_range(n): my_list = [] i = 0 while i < n: my_list.append(i) i += 1 return my_list @profile def function(): my_sum = 0 my_values = my_range(1000000) for my_value in my_values: my_sum += my_value function() 

    Results with:

    Total time: 1.07901 s Timer unit: 1e-06 s Line # Hits Time Per Hit % Time Line Contents ============================================================== 9 @profile 10 def function(): 11 1 1.1 1.1 0.0 my_sum = 0 12 1 494875.0 494875.0 45.9 my_values = my_range(1000000) 13 1000001 262842.1 0.3 24.4 for my_value in my_values: 14 1000000 321289.8 0.3 29.8 my_sum += my_value Line # Mem usage Increment Occurences Line Contents ============================================================ 9 40.168 MiB 40.168 MiB 1 @profile 10 def function(): 11 40.168 MiB 0.000 MiB 1 my_sum = 0 12 78.914 MiB 38.746 MiB 1 my_values = my_range(1000000) 13 78.941 MiB 0.012 MiB 1000001 for my_value in my_values: 14 78.941 MiB 0.016 MiB 1000000 my_sum += my_value 

    Generate values on the fly:

    def my_range(n): i = 0 while i < n: yield i i += 1 @profile def function(): my_sum = 0 for my_value in my_range(1000000): my_sum += my_value function() 

    Results with:

    Total time: 1.24841 s Timer unit: 1e-06 s Line # Hits Time Per Hit % Time Line Contents ============================================================== 7 @profile 8 def function(): 9 1 1.1 1.1 0.0 my_sum = 0 10 11 1000001 895617.3 0.9 71.7 for my_value in my_range(1000000): 12 1000000 352793.7 0.4 28.3 my_sum += my_value Line # Mem usage Increment Occurences Line Contents ============================================================ 7 40.168 MiB 40.168 MiB 1 @profile 8 def function(): 9 40.168 MiB 0.000 MiB 1 my_sum = 0 10 11 40.203 MiB 0.016 MiB 1000001 for my_value in my_range(1000000): 12 40.203 MiB 0.020 MiB 1000000 my_sum += my_value 

    Summary

    The generator function needs a little more time to execute, than function which returns a list but it use much less memory.

  26. A simple use case:

    >>> def foo(): yield 100 yield 20 yield 3 >>> for i in foo(): print(i) 100 20 3 >>>  

    How it works: when called, the function returns an object immediately. The object can be passed to the next() function. Whenever the next() function is called, your function runs up until the next yield and provides the return value for the next() function.

    Under the hood, the for loop recognizes that the object is a generator object and uses next() to get the next value.

    In some languages like ES6 and higher, it’s implemented a little differently so next is a member function of the generator object, and you could pass values from the caller every time it gets the next value. So if result is the generator then you could do something like y = result.next(555), and the program yielding values could say something like z = yield 999. The value of y would be 999 that next gets from the yield, and the value of z would be 555 that yield gets from the next. Python get and send methods have a similar effect.

  27. Usually, it’s used to create an iterator out of function. Think ‘yield’ as an append() to your function and your function as an array. And if certain criteria meet, you can add that value in your function to make it an iterator.

    arr=[] if 2>0: arr.append(2) def func(): if 2>0: yield 2 

    the output will be the same for both.

    The main advantage of using yield is to creating iterators. Iterators don’t compute the value of each item when instantiated. They only compute it when you ask for it. This is known as lazy evaluation.

  28. Generators allow to get individual processed items immediately (without the need to wait for the whole collection to be processed). This is illustrated in the example below.

    import time def get_gen(): for i in range(10): yield i time.sleep(1) def get_list(): ret = [] for i in range(10): ret.append(i) time.sleep(1) return ret start_time = time.time() print('get_gen iteration (individual results come immediately)') for i in get_gen(): print(f'result arrived after: {time.time() - start_time:.0f} seconds') print() start_time = time.time() print('get_list iteration (results come all at once)') for i in get_list(): print(f'result arrived after: {time.time() - start_time:.0f} seconds') 
    get_gen iteration (individual results come immediately) result arrived after: 0 seconds result arrived after: 1 seconds result arrived after: 2 seconds result arrived after: 3 seconds result arrived after: 4 seconds result arrived after: 5 seconds result arrived after: 6 seconds result arrived after: 7 seconds result arrived after: 8 seconds result arrived after: 9 seconds get_list iteration (results come all at once) result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds 
  29. The yield keyword is used in enumeration/iteration where the function is expected to return more then one output. I want to quote this very simple example A:

    # example A def getNumber(): for r in range(1,10): return r 

    The above function will return only 1 even when it’s called multiple times. Now if we replace return with yield as in example B:

    # example B def getNumber(): for r in range(1,10): yield r 

    It will return 1 when first called 2 when called again then 3,4 and it goes to increment till 10.

    Although the example B is conceptually true but to call it in python 3 we have to do the following:

     g = getNumber() #instance print(next(g)) #will print 1 print(next(g)) #will print 2 print(next(g)) #will print 3 # so to assign it to a variables v = getNumber() v1 = next(v) #v1 will have 1 v2 = next(v) #v2 will have 2 v3 = next(v) #v3 will have 3 
  30. names = ['Sam', 'Sarah', 'Thomas', 'James'] # Using function def greet(name) : return f'Hi, my name is {name}.' for each_name in names: print(greet(each_name)) # Output: >>>Hi, my name is Sam. >>>Hi, my name is Sarah. >>>Hi, my name is Thomas. >>>Hi, my name is James. # using generator def greetings(names) : for each_name in names: yield f'Hi, my name is {each_name}.' for greet_name in greetings(names): print (greet_name) # Output: >>>Hi, my name is Sam. >>>Hi, my name is Sarah. >>>Hi, my name is Thomas. >>>Hi, my name is James.
  31. Key points

    • The grammar for Python uses the presence of the yield keyword to make a function that returns a generator.

    • A generator is a kind of iterator, which is that main way that looping occurs in Python.

    • A generator is essentially a resumable function. Unlike return that returns a value and ends a function, the yield keyword returns a value and suspends a function.

    • When next(g) is called on a generator, the function resumes execution where it left off.

    • Only when the function encounters an explicit or implied return does it actually end.

    Technique for writing and understanding generators

    An easy way to understand and think about generators is to write a regular function with print() instead of yield:

    def f(n): for x in range(n): print(x) print(x * 10) 

    Watch what it outputs:

    >>> f(3) 0 0 1 10 2 2 

    When that function is understood, substitute the yield for print to get a generator that produces the same values:

    def f(n): for x in range(n): yield x yield x * 10 

    Which gives:

    >>> list(f(3)) [0, 0, 1, 10, 2, 20] 

    Iterator protocol

    The answer to “what yield does” can be short and simple, but it is part of a larger world, the so-called “iterator protocol”.

    On the sender side of iterator protocol, there are two relevant kinds of objects. The iterables are things you can loop over. And the iterators are objects that track the loop state.

    On the consumer side of the iterator protocol, we call iter() on the iterable object to get a iterator. Then we call next() on the iterator to retrieve values from the iterator. When there is no more data, a StopIteration exception is raised:

    >>> s = [10, 20, 30] # The list is the "iterable" >>> it = iter(s) # This is the "iterator" >>> next(it) # Gets values out of an iterator 10 >>> next(it) 20 >>> next(it) 30 >>> next(it) Traceback (most recent call last): ... StopIteration 

    To make this all easier for us, for-loops call iter and next on our behalf:

    >>> for x in s: ...  print(x) ...  10 20 30 

    A person could write a book about all this, but these are the key points. When I teach Python courses, I’ve found that this is a minimal sufficient explanation to build understand and start using it right away. In particular, the trick of writing a function with print, testing it, and then converting to yield seems to work well with all levels of Python programmers.

  32. To understand its yield function, one must understand what a generator is. Moreover, before understanding generators, you must understand iterables. Iterable: iterable To create a list, you naturally need to be able to read each element one by one. The process of reading its items one by one is called iteration:

    >>> mylist = [1, 2, 3] >>> for i in mylist: ...  print(i) 1 2 3 

    mylist is an iterable. When you use list comprehensions, you create a list and therefore iterable:

    >>> mylist = [x*x for x in range(3)] >>> for i in mylist: ...  print(i) 0 1 4 

    All data structures that can be used for… in… are iterable; lists, strings, files…

    These iterable methods are convenient because you can read them at will, but you store all the values ​​in memory, which is not always desirable when you have many values. Generator: generator A generator is also a kind of iterator, a special kind of iteration, which can only be iterated once. The generator does not store all values ​​in memory, but generates values ​​on the fly:

    generator: generator, generator, generator generates electricity but does not store energy;)

    >>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ...  print(i) 0 1 4 

    As long as () is used instead of [], the list comprehension becomes the generator comprehension. However, since the generator can only be used once, you cannot execute for i in mygenerator a second time: the generator calculates 0, then discards it, then calculates 1, and the last time it calculates 4. The typical black blind man breaks corn.

    The yield keyword is used in the same way as return, except that the function will return the generator.

    >>> def createGenerator(): ...  mylist = range(3) ...  for i in mylist: ...  yield i*i ... >>> mygenerator = createGenerator() >>> print(mygenerator) <generator object createGenerator at 0xb7555c34> >>> for i in mygenerator: ...  print(i) 0 1 4 

    This example itself is useless, but when you need a function to return a large number of values ​​and only need to read it once, using yield becomes convenient.

    To master the yield, one need to be clear is that when a function is called, the code written in the function body will not run. The function only returns the generator object. Beginners are likely to be confused about this.

    Second, understand that the code will continue from where it left off every time for uses the generator.

    The most difficult part now is:

    The first time for calls the generator object created from your function, it will run the code in the function from the beginning until it hits yield, and then it will return the first value of the loop. Then, each subsequent call will run the next iteration of the loop you wrote in the function and return the next value. This will continue until the generator is considered empty, which yields when there is no hit while the function is running. That may be because the loop has ended, or because you are no longer satisfied with “if/else”.

    Personal understanding I hope to help you!

Tasg: python, setup.py