考虑通过以下方式创建嵌套列表结构的情况:
li = [[]] * 3 print(li) # 输出:[[],[],[]]
乍一看,我们认为我们有一个包含3个不同嵌套列表的列表。让我们尝试附加1到第一个:
li[0].append(1) print(li) # 输出:[[1],[1],[1]]
1已附加到中的所有列表li。
原因是[[]] * 3不会创建list3个不同list的。而是,它创建了一个list持有3个对同一list对象的引用。因此,当我们追加li[0]更改时,在的所有子元素中都可见li。这等效于:
li = [] element = [[]] li = element + element + element print(li) # 输出:[[],[],[]] element.append(1) print(li) # 输出:[[1],[1],[1]]
这可以进一步证实,如果我们打印的内容包含在存储地址list使用id:
li = [[]] * 3 print([id(inner_list) for inner_list in li]) # 输出:[6830760、6830760、6830760]
解决方案是使用循环创建内部列表:
li = [[] for _ in range(3)]
list现在,我们创建3个不同的列表,而不是先创建一个,然后再对其进行3个引用。同样,可以使用以下id函数来验证:
print([id(inner_list) for inner_list in li]) # 输出:[6331048、6331528、6331488]
您也可以这样做。这将导致在每个append调用中创建一个新的空列表。
>>> li = [] >>> li.append([]) >>> li.append([]) >>> li.append([]) >>> for k in li: print(id(k)) ... 4315469256 4315564552 4315564808
不要使用索引来循环序列。
不要:
for i in range(len(tab)): print(tab[i])
应该这样:
for elem in tab: print(elem)
for 将为您自动化大多数迭代操作。
如果确实需要索引和元素,请使用枚举。
for i, elem in enumerate(tab): print((i, elem))
使用“ ==”来检查True或False时要小心
if (var == True): # 如果var为True或1、1.0、1L,则将执行此操作 if (var != True): # 如果var既不是True也不是1,则将执行此操作 if (var == False): # 如果var为False或0(或0.0、0L,0j),则将执行此操作 if (var == None): # 仅在var为None时执行 if var: # 如果var是非空字符串/列表/字典/元组,非0等,则执行 if not var: # execute if var is "", {}, [], (), 0, None, etc. if var is True: # 仅在var为布尔值True而不是1时执行 if var is False: # 仅在var为布尔值False而不是0时执行 if var is None: # 与var ==无相同
不要检查是否可以,只需执行并处理错误
Pythonista通常会说:“请求宽恕比允许许可容易。”
不要:
if os.path.isfile(file_path): file = open(file_path) else: # 做点什么
应该这样:
try: file = open(file_path) except OSError as e: # 做点什么
甚至更好Python 2.6+:
with open(file_path) as file:
它更好,因为它更通用。您try/except几乎可以申请任何东西。您无需关心如何采取预防措施,只需关心您所冒的错误。
不检查类型
Python是动态类型的,因此检查类型会使您失去灵活性。而是通过检查行为来使用鸭子类型。如果您希望函数中有字符串,请使用str()将任何对象转换为字符串。如果需要列表,可使用list()将所有可迭代对象转换为列表。
不要:
def foo(name): if isinstance(name, str): print(name.lower()) def bar(listing): if isinstance(listing, list): listing.extend((1, 2, 3)) return ", ".join(listing)
应该这样:
def foo(name) : print(str(name).lower()) def bar(listing) : l = list(listing) l.extend((1, 2, 3)) return ", ".join(l)
使用最后一种方法,foo将接受任何对象。bar将接受字符串,元组,集合,列表等等。便宜的干。
不要混用空格和制表符
将对象用作第一父对象
这很棘手,但是随着程序的增长它会咬你。中有新旧类Python 2.x。好吧,老了。它们缺乏某些功能,并且在继承时可能会出现笨拙的行为。要使用,您的任何班级都必须是“新风格”。为此,请使其继承自object。
不要:
class Father: pass class Child(Father): pass
应该这样:
class Father(object): pass class Child(Father): pass
在Python 3.x所有类中都是新样式,因此您不需要这样做。
不要在init方法之外初始化类属性
来自其他语言的人会发现它很诱人,因为那是您在Java或PHP中所做的。您编写类名称,然后列出您的属性并为它们提供默认值。它似乎可以在Python中工作,但是,这并不符合您的想法。这样做将设置类属性(静态属性),然后当您尝试获取对象属性时,它将为您提供其值,除非它为空。在这种情况下,它将返回类属性。这意味着两个大危害:
如果更改了class属性,则更改初始值。
如果将可变对象设置为默认值,则将获得跨实例共享的同一对象。
请勿(除非您想要静态):
class Car(object): color = "red" wheels = [Wheel(), Wheel(), Wheel(), Wheel()]
做:
class Car(object): def __init__(self): self.color= "red" self.wheels= [Wheel(), Wheel(), Wheel(), Wheel()]