【Python语言中很多大牛也无法避免的常见陷阱】
Python是一种语言清晰、没有任何歧义和意想不到的行为。 不幸的是,这些目标并非在所有情况下都能实现,这就是为什么Python有一些会比你预期不同的东西。本节展示编写Python代码时可能遇到的一些问题。
乘法和常见的引用表
考虑创建一个嵌套的情况下由乘法表结构:
1 |
li = [[]] * 3print(li)# Out: [[], [], []] |
乍一看我们会认为我们有一个包含三种不同的嵌套列表的列表。 让我们试着添加 1 第一个:
1 |
li[0].append(1)print(li)# Out: [[1], [1], [1]] |
1 被附加到所有的列表 li 。
原因在于,[[ ]] * 3 不创建一个 list 3种不同的 list 年代,而是创建一个 list 3引用相同的 list 对象。 因此,当我们追加 li[0]变化是可见的所有子元素 li。 这是相当于:
1 |
li = []element = [[]]li = element + element + elementprint(li)# Out: [[], [], []]element.append(1)print(li)# Out: [[1], [1], [1]] |
这可以进一步证实了如果我们打印包含的内存地址 list 通过使用id:
1 |
li = [[]] * 3print([id(inner_list) for inner_list in li])# Out: [6830760, 6830760, 6830760] |
解决方案是创建与一个循环内列表:
1 |
li = [[] for _ in range(3)] |
而不是创建一个 list 然后做3引用它,我们现在创建3个不同不同的列表。 再次,这可以通过使用验证 id 功能:
1 |
print([id(inner_list) for inner_list in li])# Out: [6331048, 6331528, 6331488] |
你也可以这样做,它会导致创建一个新的空列表 append 调用。
1 |
>>> li = []>>> li.append([])>>> li.append([])>>> li.append([])>>> for k in li: print(id(k))... 431546925643155645524315564808 |
不要使用索引来遍历序列。
别:
1 |
for i in range(len(tab)): print(tab[i]) |
做:
1 |
for elem in tab: print(elem) |
for 将为您自动大多数迭代操作。
使用枚举如果你真的需要指数和元素
1 |
for i, elem in enumerate(tab): print((i,elem)) |
小心使用“= =”来检查时真或假
1 |
if (var == True): |
不检查如果可以,想做就做,处理错误的吗
python支持者通常说“更容易比许可请求宽恕”。
别:
1 |
if os.path.isfile(file_path): file = open(file_path)else: # do something |
做的事:
1 |
try: file = open(file_path)except OSError as e: # do something |
或更好的 Python 2.6+:
1 |
with open(file_path) as file: |
这是更好的,因为它是更通用。您可以应用 try/except 几乎任何事情。你不需要关心如何阻止,只关心你是冒险的错误。
不检查类型
Python是动态类型,因此检查类型让你失去灵活性。,相反,使用duck typing通过检查的行为。如果你期望一个字符串函数,然后使用 str() 将任何对象转换成一个字符串。 如果你期望一个列表,使用 list() 将任何一个列表的iterable。
别:
1 |
def foo(name): if isinstance(name,str): print(name.lower()) def bar(listing) if isinstance(listing,list):: listing,exxtend((1,2,3)) return ",".join(listing) |
做的事:
1 |
def foo(name) : print(str(name),lower()) def bar(listing) : 1 = list(listing) 1.extend((1,2,3)) return ",".join(1) |
用过去的方式,foo会接受任何对象。bar将接受字符串、元组集合、列表等等。 廉价的干燥。
不要把空格和制表符
使用对象作为第一个家长
这是一个棘手的问题,但它会咬你随着你的程序。 有新旧课程Python 2.x。 旧,老了。 他们缺少一些功能,并能与继承尴尬的行为。 是可用的,你的任何的类必须“新风格”。 要做到这一点,使它继承object。
别:
1 |
class Father: pass class Child(Father): pass |
做的事:
1 |
class Father(object): passclass Child(Father): pass |
在 Python 3.x 所有类都是新的风格你不需要这样做。
不初始化类属性外的初始化方法
来自其他语言找到它诱人的因为那是你做什么在Java或PHP。 你写的类名称,然后列出你的属性,给他们一个默认值。 似乎在Python中工作,然而,这并不工作你的思维方式。 这样做将设置类属性(静态属性),然后当你将试图得到对象属性,它将给你它的价值,除非它是空的。 在这种情况下它将返回的类属性。 这意味着两大危害:
- 如果类属性改变,改变初始值。
- 如果你设置一个可变对象作为默认值,你会得到相同的 对象实例之间共享。
除非你不想静态:
1 |
class Car(object): color = "red" wheels = [Wheel(),Wheel(),Wheel(),Wheel()] |
做的事:
1 |
class Car(object): def _init_(self): self.color = "red" swlf.wheels = [Wheel(),Wheel().Wheel(),Wheel()] |
转载请注明:徐自远的乱七八糟小站 » 【Python语言中很多大牛也无法避免的常见陷阱】