Resumen de puntos de conocimiento raros de Python

Resumen de puntos de conocimiento raros de Python

Este artículo toma prestado mucho de  https://github.com/leisurelicht/wtfpython-cn

□ excepto ... finalmente: Toda la lógica en finalmente se ejecutará independientemente de si todo el programa se ejecuta normalmente o no. Al mismo tiempo, la devolución en finalmente sobrescribirá el resultado de la ejecución de la lógica anterior, e incluso se ignorarán las excepciones. Por lo tanto, se recomienda agregar solo lógica relacionada con los recursos en

def calculate(division):
    try:
        return 100 / division
    except ZeroDivisionError as e:
        raise ValueError("Invalid inputs")
    finally:
        return 0
    
print(calculate(0))

'''
最后不会报错,而是正常退出返回 0
'''

□ for ... in: La operación for ... in primero llamará a __iter__ para obtener un iterador, y luego llamará a __next__ para acceder a los elementos a su vez. Por tanto, si el contenido del elemento se modifica durante el proceso de iteración, porque __next__ accede al elemento según el bit de dirección, se producirá una situación anormal.

Hay otro punto de conocimiento aquí: iterable iterable contiene iterador, y el iterador contiene generador. Al mismo tiempo, siempre que se pueda recorrer en bucle, es iterable y el iterador puede acceder a los elementos a su vez hasta el siguiente. Esta es la única forma útil de recorrer los iteradores. Expliquemos brevemente con una imagen.

list_1 = [1, 2, 3, 4]
list_2 = [1, 2, 3, 4]
list_3 = [1, 2, 3, 4]
list_4 = [1, 2, 3, 4]

for idx, item in enumerate(list_1):
    del item

for idx, item in enumerate(list_2):
    list_2.remove(item)

for idx, item in enumerate(list_3[:]):
    list_3.remove(item)

for idx, item in enumerate(list_4):
    list_4.pop(idx)

Output:

>>> list_1
[1, 2, 3, 4]
>>> list_2
[2, 4]
>>> list_3
[]
>>> list_4
[2, 4]

'''
del, remove 和 pop 的不同: 

del var_name 只是从本地或全局命名空间中删除了 var_name (这就是为什么 list_1 没有受到影响). 

remove 会删除第一个匹配到的指定值, 而不是特定的索引, 如果找不到值则抛出 ValueError 异常. 

pop 则会删除指定索引处的元素并返回它, 如果指定了无效的索引则抛出 IndexError 异常.
'''
for i in range(4):
    print(i)
    i = 10 

# 在每次迭代开始之前, 迭代器(这里指 range(4)) 生成的下一个元素就被解包并赋值给目标列表的变量(这里指 i)了.
'''
output:
0
1
2
3
'''

□ python =: La operación de asignación en python es simplemente una asignación de referencia simple para un objeto variable, y las dos referencias en realidad apuntan al mismo objeto de memoria.

list1 = [1, 2, 3]
list2 = list1
list2[0] = 6

'''
list1 = [6, 2, 3]
list2 = [6, 2, 3]
'''

□ La lista está vacía: se recomienda usar lista y no lista directamente para juzgar si la lista no está vacía o vacía en PEP 8.

□ Usar objetos variables como parámetros predeterminados de la función: El valor predeterminado del parámetro ya está configurado cuando se ejecuta la definición del método, lo que significa que el valor predeterminado solo se configurará una vez. Después de definir la función, se configurará cada vez que se llame Hay un proceso de "cálculo previo". En este punto, si el objeto variable se modifica dentro de la función, la entrada predeterminada será el objeto modificado.

#!/usr/bin/env python
# coding: utf-8

class Test(Object):
    def process_data(self, data=[]):
        # 排序
        data.sort()
        # 追加结束符
        data.append("End")
        return data

test1 = Test()
print(test1.process_data())

test2 = Test()
print(test2.process_data())

test3 = Test()
print(test3.process_data(data=["Name:123", "Age:34"]))

test4 = Test()
print(test4.process_data())

'''
输出:
['End']
['End', 'End']
["Age:34", "Name:123", 'End']
['End', 'End', 'End']
'''

Si realmente necesita establecer un objeto variable por defecto, puede utilizar el siguiente método

def some_func(default_arg=None):
    if default_arg is None:
        default_arg = []
    default_arg.append("some_string")
    return default_arg

 □ no local: no local solo puede obtener variables locales en un nivel fuera del alcance actual, y su nivel de expansión solo puede ser 1

n = 0

def f():
    def inner():
        nonlocal n
        n = 2
    
    n = 1
    print(n)
    inner()
    print(n)

if __name__ == "__main__":
    f()
    print()

'''
输出:
1
2
0
'''

□ Rebanada de lista: cuando se divide la lista, la parada debe estar en el lado lógico derecho del inicio; de lo contrario, la salida está vacía

TempStr = 'Hello World'

print(TempStr[-5:-1])
print(TempStr[-5:0])
print(TempStr[-4:-1])
print(TempStr[-5:])

'''
输出:
Worl

orl
World
'''

□ __todos__: __todos__ solo puede limitar los objetos exportados por desde ... importar *. En este momento, solo los objetos especificados en __todos__ se pueden exportar. Sin embargo, todos los objetos aún se pueden exportar explícitamente a través de ... importar ....

□ Transferencia de valor de cierre: El valor que pasa por el cierre pasa a través de la dirección del objeto, por lo que si el valor entrante se modifica externamente, el resultado dentro del cierre también se verá afectado. Sin embargo, si el valor entrante se modifica internamente directamente, el valor entrante del cierre en el ámbito local no será válido y puede solicitar que no se copie. En este momento, si usa nonlocal para especificar el valor del cierre, puede modificar las variables externas dentro del cierre.

#!/usr/bin/env python
# coding: utf-8

def a(s):
    def b():
        print(i)
        # i = 2  # 添加该行,由于指定了局部变量,对应闭包传递过来的对象引用被覆盖,将调试在赋值前引用
        # print(i)
    i = s
    print(i)
    return b


if __name__ == '__main__':
    tb1 = a(1)
    tb1()
    tb2 = a(2)
    tb1()
    tb2()

'''
输出:
1
1
2
1
2
'''

□ Transferencia de valor de cierre: cuando se define una función dentro de un bucle, si la función utiliza una variable de bucle en su cuerpo, la función de cierre estará vinculada a la variable del bucle, no a su valor. Por lo tanto, todas las funciones son Se calcula utilizando el último valor asignado a la variable. 

def f():
    t = [lambda x: i*x for i in range(4)]
    return t
    
print([M(2) for M in f()])

'''
output:
[6, 6, 6, 6]
'''
'''
这个例子本质不是闭包值传递,而是正常的函数值传递
而由于每次都会创建一个局部变量,不同函数对应的局部变量的内存必然不同,因此不存在影响
'''
funcs = []
for x in range(7):
    def some_func(x=x):
        return x
    funcs.append(some_func)

Output:

>>> funcs_results = [func() for func in funcs]
>>> funcs_results
[0, 1, 2, 3, 4, 5, 6]

□ El momento de ejecución de la cláusula in: en la expresión del generador, la cláusula in se ejecuta en el momento de la declaración, mientras que la cláusula condicional se ejecuta en tiempo de ejecución

array = [1, 8, 15]
g = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]

print(list(g))

"""
output:
[8]
"""

array_1 = [1,2,3,4]
g1 = (x for x in array_1)
array_1 = [1,2,3,4,5]

print(list(g1))

array_2 = [1,2,3,4]
g2 = (x for x in array_2)
array_2[:] = [1,2,3,4,5]

print(list(g2))

"""
output:
[1,2,3,4]
[1,2,3,4,5]
"""

□ Multiplicación de objetos de lista: para objetos variables en la lista, use la multiplicación para copiar, y todos los objetos variables copiados apuntarán al mismo espacio de memoria

# 我们先初始化一个变量row
row = [""]*3 #row i['', '', '']
# 并创建一个变量board
board = [row]*3

>>> board
[['', '', ''], ['', '', ''], ['', '', '']]
>>> board[0]
['', '', '']
>>> board[0][0]
''
>>> board[0][0] = "X"
>>> board
[['X', '', ''], ['X', '', ''], ['X', '', '']]

□ no es: no es un operador binario único, que es diferente de usar es y no por separado. Si las variables en ambos lados del operador apuntan al mismo objeto, el resultado de no es Falso; de lo contrario, el resultado es Verdadero.

□ Cadena de barra invertida identificada por r: Lo que hace el intérprete es simplemente cambiar el comportamiento de la barra invertida, por lo que pasará directamente la barra invertida y el siguiente carácter. En este momento, si la cadena termina con una barra invertida, se informará un error SyntaxError: EOL al escanear la cadena literal

□ bool e int: los valores booleanos son subtipos de int, por lo que el valor entero de True es 1 y el valor entero de False es 0

□ Atributos de clase y atributos de instancia: internamente, las variables de clase y las variables de instancia se manejan a través del diccionario del objeto de clase (es decir, el atributo __dict__). Si no puede encontrarlo en el diccionario de la clase actual, vaya a su clase padre. El operador + = modifica los objetos mutables en su lugar, en lugar de crear otros nuevos. Por lo tanto, en este caso, la modificación de las propiedades de una instancia afectará a otras propiedades de instancia y clase.

class A:
    x = 1

class B(A):
    pass

class C(A):
    pass

Output:

>>> A.x, B.x, C.x
(1, 1, 1)
>>> B.x = 2
>>> A.x, B.x, C.x
(1, 2, 1)
>>> A.x = 3
>>> A.x, B.x, C.x
(3, 2, 3)
>>> a = A()
>>> a.x, A.x
(3, 3)
>>> a.x += 1
>>> a.x, A.x
(4, 3)


class SomeClass:
    some_var = 15
    some_list = [5]
    another_list = [5]
    def __init__(self, x):
        self.some_var = x + 1
        self.some_list = self.some_list + [x]
        self.another_list += [x]

Output:

>>> some_obj = SomeClass(420)
>>> some_obj.some_list
[5, 420]
>>> some_obj.another_list
[5, 420]
>>> another_obj = SomeClass(111)
>>> another_obj.some_list
[5, 111]
>>> another_obj.another_list
[5, 420, 111]
>>> another_obj.another_list is SomeClass.another_list
True
>>> another_obj.another_list is some_obj.another_list
True
class Base:
    inited = False
    
    @classmethod
    def set_inited(cls): # 实际可能传入Derived类
        cls.inited = True # 并没有修改Base.inited,而是给Derived添加了成员

class Derived(Base):
    pass

x = Derived()
x.set_inited()
if Base.inited:
    print("Base is inited") # 不会被执行

□ Operador + =: el operador + = modifica la lista en su lugar. La operación de asignación de elementos no funciona, pero cuando se lanza una excepción, el elemento se ha modificado en su lugar

'''
对于不可变对象, 这里指tuple, += 并不是原子操作, 而是 extend 和 = 两个动作
这里 = 操作虽然会抛出异常, 但 extend 操作已经修改成功了
'''
some_tuple = ("A", "tuple", "with", "values")
another_tuple = ([1, 2], [3, 4], [5, 6])

>>> some_tuple[2] = "change this"
TypeError: 'tuple' object does not support item assignment
>>> another_tuple[2].append(1000) # 这里不出现错误
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000])
>>> another_tuple[2] += [99, 999]
TypeError: 'tuple' object does not support item assignment
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000, 99, 999])

□ numpy.empty (): numpy.empty () regresa directamente a la siguiente memoria libre sin reinicializar.

import numpy as np

def energy_send(x):
    # 初始化一个 numpy 数组
    np.array([float(x)])

def energy_receive():
    # 返回一个空的 numpy 数组
    return np.empty((), dtype=np.float).tolist()
Output:

>>> energy_send(123.456)
>>> energy_receive()
123.456

□ Modificación del diccionario en el proceso iterativo: trate de no modificar el objeto iterativo durante el proceso iterativo, ya que el resultado suele ser impredecible.

x = {0: None}

for i in x:
    del x[i]
    x[i+1] = None
    print(i)

Output (Python 3.7):
# 这个结果好像跟字典的自动扩容有关,扩容会导致散列表地址发生变化而中断循环
0
1
2
3
4

□ Expresión del generador y ámbito de variable recursiva de lista: el ámbito anidado en la definición de clase ignorará el enlace de nombre dentro de la clase. La expresión generadora tiene su propio ámbito. A partir de Python 3.X, las listas por comprensión también tienen su propio alcance.

# 这次我们先初始化x
x = -1
for x in range(7):
    if x == 6:
        print(x, ': for x inside loop')
print(x, ': x in global')

Output:

6 : for x inside loop
6 : x in global


x = 1
print([x for x in range(5)])
print(x, ': x in global')

Output (on Python 2.x):

[0, 1, 2, 3, 4]
(4, ': x in global')

# python 3 的列表推导式不再泄露
Output (on Python 3.x): 

[0, 1, 2, 3, 4]
1 : x in global
x = 5
class SomeClass:
    x = 17
    y = (x for i in range(10))

Output:

>>> list(SomeClass.y)[0]
5


x = 5
class SomeClass:
    x = 17
    y = [x for i in range(10)]

Output (Python 2.x):

>>> SomeClass.y[0]
17

Output (Python 3.x):

>>> SomeClass.y[0]
5

□ else: La cláusula else después del bucle solo se ejecutará cuando el bucle no active la instrucción break y finalice normalmente. La cláusula else después de try también se llama "cláusula de finalización", porque llegar a la cláusula else en la declaración try significa que el bloque try se ha completado con éxito.

  def does_exists_num(l, to_find):
      for num in l:
          if num == to_find:
              print("Exists!")
              break
      else:
          print("Does not exist")

Output:

>>> some_list = [1, 2, 3, 4, 5]
>>> does_exists_num(some_list, 4)
Exists!
>>> does_exists_num(some_list, -1)
Does not exist


try:
    pass
except:
    print("Exception occurred!!!")
else:
    print("Try block executed successfully...")

Output:

Try block executed successfully...

□ Variables privadas de doble subrayado: en Python, el intérprete  modifica (mutila) los nombres __ de los miembros de la clase que comienzan con  (doble subrayado) y terminan con como máximo un subrayado_NameOfTheClass

class Yo(object):
    def __init__(self):
        self.__honey = True
        self.bitch = True

Output:

>>> Yo().bitch
True
>>> Yo().__honey
AttributeError: 'Yo' object has no attribute '__honey'
>>> Yo()._Yo__honey
True

 

Supongo que te gusta

Origin blog.csdn.net/a40850273/article/details/106232621
Recomendado
Clasificación