Python列表乘法和公共引用
示例
考虑通过以下方式创建嵌套列表结构的情况:
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:
# 做点什么甚至更好Python2.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将接受字符串,元组,集合,列表等等。便宜的干。
不要混用空格和制表符
将对象用作第一父对象
这很棘手,但是随着程序的增长它会咬你。中有新旧类Python2.x。好吧,老了。它们缺乏某些功能,并且在继承时可能会出现笨拙的行为。要使用,您的任何班级都必须是“新风格”。为此,请使其继承自object。
不要:
class Father:
pass
class Child(Father):
pass应该这样:
class Father(object):
pass
class Child(Father):
pass在Python3.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()]