Heim > Backend-Entwicklung > Python-Tutorial > Python-Fallstricke und Vorsichtsmaßnahmen, die während der Entwicklung häufig auftreten

Python-Fallstricke und Vorsichtsmaßnahmen, die während der Entwicklung häufig auftreten

大家讲道理
Freigeben: 2016-11-07 16:07:50
Original
1187 Leute haben es durchsucht

Ich bin in letzter Zeit bei der Verwendung von Python auf einige Fallstricke gestoßen, z. B. die Verwendung des Variablenobjekts datetime.datetime.now() als Standardparameter der Funktion, zirkuläre Modulabhängigkeiten usw.

Zeichnen Sie es hier für zukünftige Anfragen und Ergänzungen auf.

Vermeiden Sie veränderliche Objekte als Standardparameter

Bei der Verwendung von Funktionen sind häufig Standardparameter beteiligt. Wenn in Python veränderbare Objekte als Standardparameter verwendet werden, können unerwartete Ergebnisse auftreten.

Sehen Sie sich unten ein Beispiel an:

def append_item(a = 1, b = []):
    b.append(a)
    print b
     
append_item(a=1)
append_item(a=3)
append_item(a=5)
Nach dem Login kopieren


Das Ergebnis ist:

[1]

[ 1, 3]

[1, 3, 5]


Wie Sie den Ergebnissen entnehmen können, wird die Funktion append_item zweimal später aufgerufen Funktionsparameter b Es wird nicht auf [] initialisiert, sondern behält den Wert des vorherigen Funktionsaufrufs bei.

Der Grund für dieses Ergebnis liegt darin, dass in Python der Standardwert eines Funktionsparameters nur einmal initialisiert wird, wenn die Funktion definiert wird.

Sehen wir uns ein Beispiel an, um diese Funktion von Python zu beweisen:


class Test(object):  
    def __init__(self):  
        print("Init Test")  
           
def arg_init(a, b = Test()):  
    print(a)  
arg_init(1)  
arg_init(3)  
arg_init(5)
Nach dem Login kopieren


Das Ergebnis ist:

Init-Test

1

3

5


Wie Sie den Ergebnissen entnehmen können In diesem Beispiel wird die Testklasse nur einmal instanziiert, was bedeutet, dass die Standardparameter nichts mit der Anzahl der Funktionsaufrufe zu tun haben und nur einmal initialisiert werden, wenn die Funktion definiert wird.

Korrekte Verwendung variabler Standardparameter

Für variable Standardparameter können wir das folgende Muster verwenden, um die oben genannten unerwarteten Ergebnisse zu vermeiden:

def append_item(a = 1, b = None):
    if b is None:
        b = []
    b.append(a)
    print b
     
append_item(a=1)
append_item(a=3)
append_item(a=5)
Nach dem Login kopieren


Das Ergebnis ist:

[1]

[3]

[5]


Bereich in Python

Pythons Bereichsauflösungsreihenfolge ist „Lokal“, „Einschließend“, „Global“, „Eingebaut“, was bedeutet, dass der Python-Interpreter Variablen gemäß dieser Reihenfolge analysiert.

Sehen Sie sich ein einfaches Beispiel an:

global_var = 0
def outer_func():
    outer_var = 1
     
    def inner_func():
        inner_var = 2
         
        print "global_var is :", global_var
        print "outer_var is :", outer_var
        print "inner_var is :", inner_var
         
    inner_func()
     
outer_func()
Nach dem Login kopieren


Das Ergebnis ist:


global_var ist: 0

outer_var ist: 1

innere_var ist: 2


In Python etwa Bereich Eins Beachten Sie, dass Python beim Zuweisen eines Werts zu einer Variablen in einem Bereich die Variable als lokale Variable des aktuellen Bereichs betrachtet.


Dies ist auch relativ einfach zu verstehen. Für den folgenden Code weist var_func der Variable num einen Wert zu, daher ist num hier eine lokale Variable im Bereich var_func.


num = 0
def var_func():
    num = 1
    print "num is :", num
     
var_func()
Nach dem Login kopieren


Frage 1

Wenn wir es jedoch im Folgenden verwenden Wenn Variablen verwendet werden, treten Probleme auf:


num = 0
def var_func():
    print "num is :", num
    num = 1
     
var_func()
Nach dem Login kopieren


Das Ergebnis ist wie folgt:


UnboundLocalError: local variable 'num' referenced before assignment
Nach dem Login kopieren


Der Grund, warum dieser Fehler auftritt, ist, dass wir der Num-Variablen in var_func einen Wert zugewiesen haben , also Python Der Interpreter geht davon aus, dass num eine lokale Variable im var_func-Bereich ist, aber wenn der Code ausgeführt wird, um „num is:“, num-Anweisung zu drucken, ist num immer noch undefiniert.


Frage 2

Der obige Fehler ist relativ offensichtlich, und es gibt auch eine subtilere Fehlerform wie folgt:


   
li = [1, 2, 3]
def foo():
    li.append(4)
    print li
foo()
def bar():
    li +=[5]
    print li
bar()
Nach dem Login kopieren


Das Ergebnis des Codes ist:



[1, 2, 3, 4]

UnboundLocalError: local variable 'li' referenced before assignment
Nach dem Login kopieren


In der foo-Funktion wird gemäß Pythons Bereichsauflösungsreihenfolge die globale Funktion verwendet li-Variable; aber in der bar-Funktion wird der li-Variablen ein Wert zugewiesen, sodass li im bar-Bereich als Variable behandelt wird.


Für dieses Problem der Balkenfunktion können Sie das globale Schlüsselwort verwenden.

li = [1, 2, 3]
def foo():
    li.append(4)
    print li
     
foo()
def bar():
    global li
    li +=[5]
    print li
     
bar()
Nach dem Login kopieren


Klassenattribute ausgeblendet

In Python gibt es Klassenattribute und Instanzattribute. Klassenattribute gehören zur Klasse selbst und werden von allen Klasseninstanzen gemeinsam genutzt.

Auf Klassenattribute kann über den Klassennamen zugegriffen und diese geändert werden. Außerdem kann auf Klassenattribute über die Klasseninstanz zugegriffen und diese geändert werden. Wenn eine Instanz jedoch ein Attribut mit demselben Namen wie die Klasse definiert, wird das Klassenattribut ausgeblendet.

Sehen Sie sich das folgende Beispiel an:

class Student(object):
    books = ["Python", "JavaScript", "CSS"]
    def __init__(self, name, age):
        self.name = name
        self.age = age
    pass
     
wilber = Student("Wilber", 27)
print "%s is %d years old" %(wilber.name, wilber.age)
print Student.books
print wilber.books
wilber.books = ["HTML", "AngularJS"]
print Student.books
print wilber.books
del wilber.books
print Student.books
print wilber.books
Nach dem Login kopieren


Das Ergebnis des Codes ist zunächst wie folgt: Die Wilber-Instanz kann direkt auf die Bücher zugreifen Attribut der Klasse, aber wenn die Instanz wilber definiert ist. Nach dem Löschen des Instanzattributs namens „books“ „versteckt“ das Attribut „books“ der wilber-Instanz das Attribut „books“ der Klasse nach dem Löschen des Attributs „books“ der wilber-Instanz, wilber.books entspricht wieder dem Attribut „books“ der Klasse.

Wilber is 27 years old
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
['HTML', 'AngularJS']
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
Nach dem Login kopieren


Bei der Verwendung der Vererbung in Python-Werten sollten Sie auch auf das Ausblenden von Klassenattributen achten. Für eine Klasse können Sie alle Klassenattribute über das Attribut __dict__ der Klasse anzeigen.

Wenn Sie über den Klassennamen auf ein Klassenattribut zugreifen, wird zunächst nach dem __dict__-Attribut der Klasse gesucht. Wenn das Klassenattribut nicht gefunden wird, wird weiterhin nach der übergeordneten Klasse gesucht. Wenn die Unterklasse jedoch ein Klassenattribut mit demselben Namen wie die übergeordnete Klasse definiert, verdecken die Klassenattribute der Unterklasse die Klassenattribute der übergeordneten Klasse.

Sehen Sie sich ein Beispiel an:

class A(object):
    count = 1
     
class B(A):
    pass    
     
class C(A):
    pass        
     
print A.count, B.count, C.count      
B.count = 2
print A.count, B.count, C.count      
A.count = 3
print A.count, B.count, C.count     
print B.__dict__
print C.__dict__
Nach dem Login kopieren


Das Ergebnis ist wie folgt: Wenn Klasse B das Zählattribut definiert, ist das Zählattribut der übergeordneten Klasse wird ausgeblendet.

1 1 1
1 2 1
3 2 3
{'count': 2, '__module__': '__main__', '__doc__': None}
{'__module__': '__main__', '__doc__': None}
Nach dem Login kopieren


Tupel ist „veränderlich“

在Python中,tuple是不可变对象,但是这里的不可变指的是tuple这个容器总的元素不可变(确切的说是元素的id),但是元素的值是可以改变的。

tpl = (1, 2, 3, [4, 5, 6])
print id(tpl)
print id(tpl[3])
tpl[3].extend([7, 8])
print tpl
print id(tpl)
print id(tpl[3])
Nach dem Login kopieren

代码结果如下,对于tpl对象,它的每个元素都是不可变的,但是tpl[3]是一个list对象。也就是说,对于这个tpl对象,id(tpl[3])是不可变的,但是tpl[3]确是可变的。

36764576
38639896
(1, 2, 3, [4, 5, 6, 7, 8])
36764576
38639896
Nach dem Login kopieren

Python的深浅拷贝

在对Python对象进行赋值的操作中,一定要注意对象的深浅拷贝,一不小心就可能踩坑了。

当使用下面的操作的时候,会产生浅拷贝的效果:

使用切片[:]操作

使用工厂函数(如list/dir/set)

使用copy模块中的copy()函数

使用copy模块里面的浅拷贝函数copy():

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
Nach dem Login kopieren


使用copy模块里面的深拷贝函数deepcopy():

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
Nach dem Login kopieren


模块循环依赖

在Python中使用import导入模块的时候,有的时候会产生模块循环依赖,例如下面的例子,module_x模块和module_y模块相互依赖,运行module_y.py的时候就会产生错误。

# module_x.py
import module_y
     
def inc_count():
    module_y.count += 1
    print module_y.count
     
     
# module_y.py
import module_x
count = 10
def run():
    module_x.inc_count()
     
run()
Nach dem Login kopieren

其实,在编码的过程中就应当避免循环依赖的情况,或者代码重构的过程中消除循环依赖。

当然,上面的问题也是可以解决的,常用的解决办法就是把引用关系搞清楚,让某个模块在真正需要的时候再导入(一般放到函数里面)。

对于上面的例子,就可以把module_x.py修改为如下形式,在函数内部导入module_y:

# module_x.py
def inc_count():
    import module_y
    module_y.count += 1
Nach dem Login kopieren
Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage