Dry goods! Understand these 27 questions and let you become a Python master in seconds!

↓Recommend attention↓

01. Why use indentation to group statements?


Guido van Rossum thinks that grouping using indentation is very elegant and greatly improves the clarity of common Python programs. Most people learn and love this feature after a while.

Since there are no opening/closing brackets, there will be no disagreement between parser-perceived groupings and human readers. Occasionally a C programmer comes across a code snippet like this:

if (x <= y)  
        x++;  
        y--;  
z++;

The x++ statement is only executed if the condition is true, but the indentation makes you think that's not the case. Even experienced C programmers sometimes stare at it for a long time, wondering why y is decreasing even though x > y .

Because there are no opening/closing brackets, Python is less prone to coding style conflicts. In C, parentheses can be placed in many different positions. If you're used to reading and writing code that uses one style, you'll feel at least a little uncomfortable reading (or being asked to write) another.

Many coding styles place opening/closing brackets on a line by themselves. This makes the program quite long, wastes valuable screen real estate, and makes it more difficult to get a full picture of the program. Ideally, functions should fit on one screen (eg, 20--30 lines). You can do more in 20 lines of Python than in 20 lines of C. This isn't just due to the lack of opening/closing brackets -- missing declarations and advanced data types are also part of the story -- but indentation based on syntax certainly helps.

02. Why do simple arithmetic operations get strange results?


Please see the next question.

03. Why is the floating point calculation inaccurate?


Users are often surprised by results like this:

>>> 1.2 - 1.00.19999999999999996

And thought it was a bug in Python. Not so. This has less to do with Python and more to do with how the underlying platform handles floating point numbers.

The float type in CPython uses the double type of C language for storage. The value of a float object is a binary floating-point number stored with a fixed precision (typically 53 bits), since Python uses C operations, which rely on the hardware implementation in the processor to perform floating-point operations. This means that Python behaves like many popular languages, including C and Java, as far as floating-point arithmetic is concerned.

Many numbers that can be easily represented in decimal cannot be represented in binary floating point. For example, after entering the following statement:

>>> x = 1.2

The value stored for x is a (very close) approximation to the decimal value of 1.2, but not exactly equal to it. On a typical machine, the actual stored value is:

1.0011001100110011001100110011001100110011001100110011   
(binary)

It corresponds to the decimal value:

1.1999999999999999555910790149937383830547332763671875   
(decimal)

A typical precision of 53 bits gives Python floats 15-16 decimal places of precision.

For a more complete explanation, see the chapter on floating-point arithmetic in the Python Tutorial.

04. Why are Python strings immutable?


There are several advantages.

One is performance: knowing that a string is immutable means we can allocate space for it at creation time, and the storage requirements are fixed. This is one of the reasons for the difference between tuples and lists.

Another advantage is that strings in Python are considered as "basic" as numbers. No action will change the value 8 to something else, and no action will change the string "8" to something else in Python.

05. Why must "self" be used explicitly in method definitions and calls?


The idea was borrowed from the Modula-3 language. It has proven to be very useful for a number of reasons.

First, it's more obvious that you're using a method or instance attribute rather than a local variable. Reading self.x or self.meth() makes it clear that an instance variable or method is used even if you don't know the class definition. In C++, you can tell by the lack of local variable declarations (assuming globals are rare or easily recognizable) -- but in Python there are no local variable declarations, so you have to look up the class definition to be sure. Some C++ and Java coding standards require instance attributes to have the m_ prefix, so this explicitness is still useful in those languages.

Second, it means that no special syntax is required if you want to explicitly reference or call the method from a specific class. In C++, if you want to override a method in a base class in a derived class, you have to use the :: operator -- in Python you can write baseclass.methodname(self,). This is useful for init() methods, especially when a derived class method wants to extend a base class method of the same name, but must somehow call the base class method.

Finally, it solves the syntax problem of variable assignments: in order to assign values ​​to variables that are local variables in Python (by definition!) in the body of a function (and not explicitly declared global), one must somehow tell the interpreter that a Assignment is for assigning an instance variable rather than a local variable, which is best done syntactically (for efficiency reasons). C++ does this with declarations, but Python doesn't have declarations, and it would be a shame to introduce them just for this purpose. Using an explicit self.var solves this problem nicely. Similarly, for using instance variables, having to write self.var means that references to unqualified names inside methods don't have to search the instance's directory. In other words, local variables and instance variables live in two different namespaces, and you need to tell Python which namespace to use.

06. Why can't I assign a value in an expression?


Many people who are used to C or Perl complain that they want to use this feature of C:

while (line = readline(f)) {  
    // do something with line  
}

But it is forced to write like this in Python:

while True:  
    line = f.readline()  
    if not line:  
        break  
    ...  # do something with line

The reason assignments are not allowed in Python expressions is that these common, hard-to-find bugs in other languages ​​are caused by this construct:

if (x = 0) {  
    // error handling  
}  
else {  
    // code that only works for nonzero x  
}

The error is a simple typo: x = 0, assigning 0 to the variable x, while the comparison x == 0 is certainly expected.

There have been many alternative proposals. Most are hacks designed to save some typing, but use arbitrary or implicit syntax or keywords that don't meet the simple criteria for a language change proposal: it should be intuitively available to human readers who haven't been introduced to the concept correct meaning.

An interesting observation is that most experienced Python programmers recognize the while True idiom and don't care much about being able to assign values ​​in expression constructs; only newcomers express a strong desire to add it to the language .

There is an alternative spelling that looks attractive, but is generally less reliable than the "while True" solution:

line = f.readline()  
while line:  
    ...  # do something with line...  
    line = f.readline()

The problem is how to know the next line if you change your mind (e.g. you want to change it to sys.stdin.readline()). You have to remember to change two places in the program -- the second occurrence is hidden at the bottom of the loop.

The best way is to use iterators, which can be used to loop through objects with a for statement. For example file objects support the iterator protocol, so can simply be written as:

for line in f:  
    ...  # do something with line...

07 Why does Python use methods for some functions (such as list.index()), while other functions (such as len(List)) use functions?


As Guido said:

(a) For some operations, prefix notation is easier to read than postfix -- prefix (and infix!) operations have a long tradition in mathematics, as is the notation that visually helps mathematicians think about problems. Compare how easily we can rewrite a formula like x*(a+b) as x_a+x_b, and how clumsy it is to do the same thing using raw OO notation. "

(b) When you read code that says len(X), you know it's asking for the length of something. This tells us two things: the result is an integer, and the argument is some kind of container. Instead, when reading x.len(), one must already know that x is some kind of container that implements an interface, or inherits from a class that has a standard len(). We occasionally get confused when a class that doesn't implement a map has a get() or key() method, or a class that isn't a file has a write() method.

—https://mail.python.org/pipermail/python-3000/2006-November/004643.html”

08. Why is join() a string method and not a list or tuple method?


Beginning with Python 1.6, strings became more like other standard types, when methods were added that provided the same functionality as always provided by the String module's functions. Most of these new methods are widely accepted, but one that seems to make some programmers uncomfortable is:

", ".join(['1', '2', '4', '8', '16'])

The result is as follows:

"1, 2, 4, 8, 16"

There are two common arguments against this usage.

The first one reads: "Methods using String Constants look really ugly", and the answer is maybe, but a String Literal is just a fixed value. If these methods are allowed on names bound to strings, there is no logical reason for them not to be available literally.

The second objection usually goes something like this: "I'm actually telling the sequence to concatenate its members together using string constants". Unfortunately not. For some reason, it seems much easier to have split() as a string method, because in this case, it's easy to see:

"1, 2, 4, 8, 16".split(", ")

is a directive on a string literal to return a substring separated by the given delimiter (or, by default, any whitespace).

join() is a string method because when you use it, you tell delimiter string to iterate over a sequence of strings, inserting itself between adjacent elements. The argument to this method can be any object that follows the sequence rules, including any new classes you define yourself. There are similar methods for bytes and bytearray objects.

09. How fast are exceptions?


A try/except block is extremely efficient if no exception is thrown. Actually catching exceptions is expensive. In versions of Python prior to 2.0, this idiom was commonly used:

try:  
    value = mydict[key]  
except KeyError:  
    mydict[key] = getvalue(key)  
    value = mydict[key]

This only makes sense if you expect the dict to have keys at all times. If that's not the case, that's how you should code it:

if key in mydict:  
    value = mydict[key]  
else:  
    value = mydict[key] = getvalue(key)

For this specific case, you could also use value = dict.setdefault(key, getvalue(key)) , but only if calling getvalue() is cheap enough, since it will be evaluated in all cases.

10. Why is there no switch or case statement in Python?


You can easily do this with a series of if... elif... elif... else. There have been some proposals for switch statement syntax, but no consensus on whether and how to do range testing. See PEP 275 for full details and current status.

For cases where you need to choose from a large number of possibilities, you can create a dictionary mapping case values ​​to functions to call. For example:

def function_1(...):  
    ...  
   
functions = {'a': function_1,  
             'b': function_2,  
             'c': self.method_1, ...}  
   
func = functions[value]  
func()

For object call methods, this can be further simplified by using the getattr() built-in to retrieve the method with a specific name:

def visit_a(self, ...):  
    ...  
...  
  
def dispatch(self, value):  
    method_name = 'visit_' + str(value)  
    method = getattr(self, method_name)  
    method()

It is recommended to use a prefix for method names, such as visit_ in this example. Without such a prefix, an attacker would be able to call any method on the object if the value came from an untrusted source.

11. Shouldn't threads be emulated in the interpreter instead of relying on OS-specific threading implementations?


Answer 1: Unfortunately, the interpreter pushes at least one C stack frame for every Python stack frame. Additionally, extensions can call back into Python at any time. Therefore, a complete threading implementation requires threading support in C.

Answer 2: Fortunately, Stackless Python has a completely redesigned interpreter loop that avoids the C stack.

12. Why does a lambda expression not contain a statement?


Python's lambda expressions cannot contain statements because Python's syntax framework cannot handle statements nested inside expressions. In Python, however, this is not a serious problem. Unlike the lambda form in other languages ​​that add functionality, Python's lambdas are just a shorthand notation if you're too lazy to define a function.

Functions are already first-class objects in Python and can be declared at local scope. So the only advantage of using a lambda instead of a locally defined function is that you don't need to create a name for the function -- it's just a local variable assigned a function object (of the exact same type as the object produced by a lambda expression)!

13. Can Python be compiled to machine code, C or other languages?


Cython compiles a modified version of Python with optional comments into C extensions. Nuitka is an emerging compiler that compiles Python to C++ code, aiming to support the full Python language. To compile to Java, consider VOC.

14. How does Python manage memory?


The details of Python's memory management are implementation-dependent. Python's standard implementation, CPython, uses reference counting to detect unreachable objects, and uses another mechanism to collect reference cycles, periodically executing a cycle detection algorithm to find unreachable cycles and delete the objects involved. The gc module provides functions to perform garbage collection, obtain debugging statistics, and optimize collector parameters.

However, other implementations (such as Jython or PyPy),) can rely on different mechanisms, such as a full garbage collector. This difference can cause some subtle porting issues if your Python code relies on the behavior of the reference counting implementation.

On some Python implementations, the following code (which works fine in CPython) may run out of file descriptors:

for file in very_long_list_of_files:  
    f = open(file)  
    c = f.read(1)

In fact, using CPython's reference counting and destructor scheme, each newly assigned f closes the previous file. However, with a traditional GC, these file objects can only be collected (and closed) at varying (possibly long) intervals.

If you want to write code that will work with any Python implementation, you should either explicitly close the file or use a with statement; this works regardless of the memory management scheme:

for file in very_long_list_of_files:  
    with open(file) as f:  
        c = f.read(1)

15. Why doesn't CPython use a more traditional garbage collection scheme?


First, this is not a C standard feature, so it's not portable. (Yes, we know about the Boehm GC library. It contains assembly code for most (but not all) common platforms, and while it's mostly transparent, it's not completely transparent; for Python to use it, you need to use patch.)

Traditional GC also becomes an issue when Python is embedded in other applications. In stand-alone Python, the standard malloc() and free() can be replaced by the versions provided by the GC library, applications that embed Python may wish to replace malloc() and free() with their own, and may not require Python's. CPython now correctly implements malloc() and free().

16. Why doesn't CPython free all memory when it exits?


Objects referenced from the global namespace or Python modules are not always deallocated when Python exits. This can happen if there are circular references and some memory allocated by the C library is also impossible to free (eg tools like Purify will complain about these things). However, Python cleans up memory on exit and tries to destroy every object.

If you want to force Python to remove something on release, use the atexit module to run a function that forces removal of these things.

17. Why are there separate tuple and list data types?


While lists and tuples are similar in many ways, they are often used quite differently. Think of tuples as analogous to Pascal records or C structures; they are small collections of related data, possibly of different types, that can be manipulated as a group. For example, Cartesian coordinates are represented appropriately as tuples of two or three numbers.

Lists, on the other hand, are more like arrays in other languages. They tend to hold varying numbers of objects, all of the same type, and operate on them one by one. For example, os.listdir('.') returns a list of strings representing the files in the current directory. Functions that operate on this output usually don't break if you add a file or two to the directory.

Tuples are immutable, which means that once a tuple is created, it cannot replace any of its elements with new values. Lists are mutable, which means you can always change the elements of the list. Only immutable elements can be used as keys for dictionaries, so only tuples and non-lists can be used as keys.

18. How are lists implemented in CPython?


CPython's lists are actually variable-length arrays, not lisp-style linked lists. The implementation uses a contiguous array of references to other objects and keeps pointers to that array and the length of the array in the list header structure.

This makes the operation cost of indexing a list a[i] independent of the size of the list or the value of the index.

The array of references is resized when items are added or inserted. And employs some neat tricks to improve the performance of repeatedly adding items; when the array has to grow, some extra space is allocated so that the next few times it doesn't need to be actually resized.

19. How are dictionaries implemented in CPython?


CPython's dictionaries are implemented as resizable hash tables. This provides better performance for lookups (by far the most common operation) in most cases and is simpler to implement than B-trees.

The way dictionaries work is by using the hash() built-in function to compute a hash code for each key stored in the dictionary. The hash code varies widely depending on the key and per-process seed; for example, "Python" has a hash of -539294296, while "python" (a bitwise different string) has a hash of 1142331976. The hash code is then used to calculate where in the internal array the value will be stored. Assuming you store keys with different hash values, this means that the dictionary takes constant time -- O(1), in Big-O notation -- to retrieve a key.

20. Why must dictionary keys be immutable?


A hashtable implementation of a dictionary uses a hash value computed from the key value to look up the key. If a key is a mutable object, its value may change, and therefore its hash. However, since whoever changes the key object cannot tell whether it is being used as a dictionary key, an entry cannot be modified in the dictionary. Then, when you try to look up the same object in the dictionary, it won't be able to find it because its hashes are different. If you try to look up the old value, you won't find it either, because the value of the object found in that hash table will be different.

If you want a dictionary indexed by a list, just convert the list to a tuple first; use the function tuple(L) to create a tuple with the same entries as the list L . Tuples are immutable and thus can be used as dictionary keys.

Some unacceptable solutions that have been proposed:

  • Hashes are listed by their address (object ID). This doesn't work because if you construct a new list with the same value, it won't be able to find it; e.g.:

    mydict = {[1, 2]: '12'}  
    print(mydict[[1, 2]])

    A KeyError exception is raised because the id of [1, 2] used in the second line is different from the id in the first line. In other words, you should use == to compare dictionary keys, not is.

  • Copy when using a list as a key. This is useless, because a list being a mutable object can contain a reference to itself, and then the copying code will go into an infinite loop.

  • Allow lists as keys, but tell users not to modify them. This creates a class of bugs in programs that are hard to track down when you accidentally forget or modify the list. It also invalidates an important dictionary invariant: every value in d.keys() can be used as a key for a dictionary.

  • After using a list as a dictionary key, it should be marked as read-only. The thing is, it's not just top-level objects whose values ​​can be changed; you can use tuples that contain lists as keys. Associating anything as a key into a dictionary requires marking all objects reachable from there as read-only -- and self-referencing objects can lead to infinite loops.

If desired, the following approach can be used to work around this, but use it at your own risk: You can wrap a mutable struct in a class instance that has both eq() and hash() methods. You then have to ensure that the hash values ​​of all such wrapper objects residing in a dictionary (or other hash-based structure) remain fixed while the object is in the dictionary (or other structure).

class ListWrapper:  
    def __init__(self, the_list):  
        self.the_list = the_list  
   
    def __eq__(self, other):  
        return self.the_list == other.the_list  
   
    def __hash__(self):  
        l = self.the_list  
        result = 98767 - len(l)*555  
        for i, el in enumerate(l):  
            try:  
                result = result + (hash(el) % 9999999) * 1001 + i  
            except Exception:  
                result = (result % 7777777) + i * 333  
        return result

Note that the hash computation is complicated by the possibility that some members of the list may not be available and the possibility of arithmetic overflow.

Furthermore, it must always be true that if o1 == o2 (ie o1.eq(o2) is True ) then hash(o1) == hash(o2) o1.hash() (即== o2.hash() ), regardless of whether the object in the dictionary. Dictionaries and other hash-based structures will fail if you fail to meet these constraints.

For ListWrapper, as long as the wrapper object is in the dictionary, the wrapped list cannot be changed to avoid the exception. Don't do this unless you're ready to think hard about the requirements and the consequences of incorrectly fulfilling them. Please note.

21. Why does list.sort() not return a sorted list?


In situations where performance matters, making a copy of the list just to sort it would be a waste. So list.sort() sorts the list appropriately. To remind you of that fact, it doesn't return a sorted list. That way you don't accidentally overwrite the list when you need a sorted copy, but also need to keep the unsorted version.

If you want to return a new list, use the built-in sorted() function. This function creates a new list from the provided iterable, sorts it and returns it. For example, here's how to iterate over a dictionary and sort by keys:

for key in sorted(mydict):  
    ...  # do whatever with mydict[key]...

22. How to specify and enforce interface specification in Python?


The module interface specification provided by languages ​​such as C++ and Java describes the prototype of the method and function of the module. Many people argue that compile-time enforcement of interface specifications helps build large programs.

Python 2.6 added an abc module that allows abstract base classes (ABCs) to be defined. You can then use isinstance() and issubclass() to check whether an instance or class implements a particular ABC. The collections.abc module defines a set of useful ABCs such as Iterable , Container , and MutableMapping

In the case of Python, many of the benefits of interface specification can be obtained through proper testing procedures for components. There is also a tool, PyChecker, that can be used to find problems due to subclassing.

A good module test suite provides regression tests as well as a module interface specification and a set of examples. Many Python modules can be run as scripts to provide easy "self-testing". Even modules that use complex external interfaces can often be tested in isolation using simple "stub" mocks of the external interfaces. Exhaustive test suites can be constructed using the doctest and unittest modules or third-party testing frameworks to run every line of code in a module.

Proper testing procedures can help build large, complex applications and interface specifications in Python. In fact, it might be better, because interface specifications cannot test certain properties of programs. For example, the append() method will add new elements to the end of some internal list; the interface specification cannot test that your append() implementation does this correctly, but it is trivial to check this property in a test suite.

Writing test suites is very useful, and you probably want to design your code with a view to making it easy to test. An increasingly popular technique is test-oriented development, which requires that parts of the test suite be written before any actual code is written. Of course, Python allows you to sloppy and not write test cases at all.

23. Why is there no goto?


Exception catching can be used to provide "goto constructs" that even work across function calls. Many consider exception catching to be a convenient way to emulate all reasonable uses of the "go" or "goto" constructs of C, Fortran, and other languages. For example:

class label(Exception): pass  # declare a label  
  
try:  
    ...  
    if condition: raise label()  # goto label  
    ...  
except label:  # where to goto  
    pass  
...

But you are not allowed to jump into the middle of the loop, which is generally considered an abuse of goto. Use with caution.

24. Why can't raw strings (r-strings) end with a backslash?


More precisely, they cannot end with an odd number of backslashes: an unpaired backslash at the end escapes the closing quote character, leaving the string unterminated.

Raw strings are designed to facilitate the creation of input by processors (mainly regular expression engines) that want to do their own backslash-escaping handling. Such processors treat unmatched trailing backslashes as errors, so raw strings do not allow it. This, in turn, allows strings to be escaped by escaping backslashes with quote characters. These rules work well when r-strings are used for their intended purpose.

If you're trying to build Windows pathnames, be aware that all Windows system calls use forward slashes:

f = open("/mydir/file.txt")  # works fine!

If you're trying to build a pathname for a DOS command, try the following example

dir = r"\this\is\my\dos\dir" "\\"  
dir = r"\this\is\my\dos\dir\ "[:-1]  
dir = "\\this\\is\\my\\dos\\dir\\"

25. Why doesn't Python have a "with" statement for attribute assignment?


Python has a 'with' statement which encapsulates the execution of a block, calling code on block entry and exit. Some languages ​​have a structure like this:

with obj:  
    a = 1               # equivalent to obj.a = 1  
    total = total + 1   # obj.total = obj.total + 1

In Python, such constructs are ambiguous.

Other languages, such as ObjectPascal, Delphi, and C++ use static typing, so it is unambiguous to know what member to assign to. This is the point of static typing -- the compiler always knows the scope of each variable at compile time.

Python uses dynamic typing. It is not possible to know in advance which property to refer to at runtime. Member properties can be dynamically added or removed from an object. This makes it impossible to know what property is being referenced by simply reading: local property, global property or member property?

For example, take the following incomplete code snippet:

def foo(a):      
  with a:          
    print(x)

This snippet assumes that "a" must have a member property named "x". However, Python does not tell the interpreter this. Suppose "a" is an integer, what happens? If there is a global variable named "x", will it be used in the with block? As you can see, the dynamic nature of Python makes such a choice more difficult.

However, Python makes it easy to achieve the main benefit of "with" and similar language features (reduced code size) through assignment. replace:

function(args).mydict[index][index].a = 21  
function(args).mydict[index][index].b = 42  
function(args).mydict[index][index].c = 63

written like this:

ref = function(args).mydict[index][index]  
ref.a = 21  
ref.b = 42  
ref.c = 63

This also has the side effect of improving execution speed, since Python resolves name bindings at runtime, whereas the second version only needs to perform the resolution once.

26. Why do if/while/def/cblass statements need a colon?


Colons are primarily used to enhance readability (one of the results of the ABC language experiment). Consider this:

if a == b      
 print(a)

and

if a == b:      
 print(a)

Note that the second method is slightly easier. Note further how the colon is placed in the example in this FAQ answer; this is standard usage in English.

Another secondary reason is that the colon makes it easier for editors with syntax highlighting to work; they can look for the colon to decide when they need to increase indentation without having to do a more elaborate parsing of the program text.

27. Why does Python allow commas at the end of lists and tuples?


Python allows you to add a trailing comma to the end of lists, tuples and dictionaries:

[1, 2, 3,]  
('a', 'b', 'c',)  
d = {  
    "A": [1, 5],  
    "B": [6, 7],  # last trailing comma is optional but good style  
}

There are several reasons to allow this.

If a list, tuple, or dictionary literal is spread over multiple lines, it's easier to add more elements because you don't have to remember to add commas on the previous line. The lines can also be reordered without syntax errors.

Accidentally omitting a comma can lead to hard-to-diagnose bugs. For example:

x = [  
  "fee",  
  "fie"  
  "foo",  
  "fum"  
]

This list appears to have four elements, but actually contains three: "fee", "fiefoo" and "fum". Always adding a comma avoids this source of error.

Allowing trailing commas also makes programming code easier to generate.


Finally, recommend your own column

Learning GPT alone is time-consuming and laborious, and there is no one to discuss, communicate and guide when encountering problems, wasting a lot of time and energy. Now the top priority is to use this super AI quickly and quickly to help you improve the efficiency of work and study and save costs!

We wrote a column, the content of which is roughly like this, which records in detail how to register for the ChatGPT nanny guide from the beginning, how to upgrade the Plus strategy, and how to play GPT in various ways, including generating pictures, creating your own English personal education, deploying WeChat robot, using Python to call API, how to use GPT to make PPT, making audio novels, etc., the content will be updated every week!

The original price is 299 yuan, and the current early bird price is 109 yuan (the content is permanently valid), and the price will increase by 20 yuan after 200 yuan, until the original price . At present, many planets are priced at hundreds of dollars. WeChat contact editor: coder_v5

Now GPT is a hot spot, which belongs to the early bonus period. If you don’t get on the train, you won’t need to get on the train after two years when everyone gets on the train.

49085a4654e1f1f643cae995f331b732.png

The content will continue to be released to unlock more advanced and fun skills. If you are interested, scan the QR code quickly to join!

Past recommendations:

5 Tips for Making Money with a Side Hustle with ChatGPT!

Can't stop playing! ! Use Python+ChatGPT to create a super WeChat robot!

ChatGPT4 has come, make a pinball game in 30 seconds!

Earned 3,000 yuan by ChatGPT!

Recommended reading:

Getting Started:  The most comprehensive zero-basics learning Python questions   |  Learning Python for 8 months with zero foundation   |  Practice project  | Learning Python is this shortcut

Dry goods: Crawl Douban short reviews, the movie "Later Us"  |  Analysis of the best NBA players in 38 years  |    From high expectations to word-of-mouth hits the street! Tang Detective 3 is disappointing   |  Laughing at the new Yitian Tulongji  |  Lantern Riddle Answer King  | Use Python to make a large number of sketches of young ladies  | Mission: Impossible is so popular, I use machine learning to make a mini recommendation system movie

Fun: pinball game   |  Nine-square grid   |  beautiful flowers  |  200 lines of Python "Daily Cool Run" game!

AI:  A robot that can write poetry  |  Colorize pictures  |  Predict income  |  Mission: Impossible is so popular, I use machine learning to make a mini recommendation system movie

Gadget:  Pdf to Word, easy to get tables and watermarks!  |  Save html web pages as pdf with one click! |   Goodbye PDF Extraction Fees!  |  Build the strongest PDF converter with 90 lines of code, one-click conversion of word, PPT, excel, markdown, html  |  Make a DingTalk low-cost air ticket reminder!  |60 lines of code made a voice wallpaper switcher to see Miss Sister every day! |

Guess you like

Origin blog.csdn.net/cainiao_python/article/details/130073309