1.函数的默认参数只初始化一次
函数的默认值只会创建一次,之后不会再变了,使用对象(列表、字典、实例)作为默认值,会导致函数混乱,如下面的函数在后续调用中积累传递给它的参数
def f(a, L=[]):
L.append(a)
return L
if __name__ == '__main__':
print(f(1))
print(f(1))
print(f(1))

可以使用下面的办法进行规避:
def f1(a, t=None):
t = t or []
t.append(a)
return t

2. is与==
- == 是比较两个对象的内容是否相等,即两个对象的“值“”是否相等,不管两者在内存中的引用地址是否一样。
- is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。即is比较两个条件:1.内容相同。2.内存中地址相同。
- 使用is注意python对于小整数使用对象池存储问题,和字符串的intern机制存储问题,并且命令行运行和Pycharm运行有点不一样,因为Pycharm对解释器进行了优化。
- python中对于None值的比较:使用is,即,要用is或is not none: she is none; she is not None;
-
布尔值:不要用==比较布尔值,
-
Python中,万物皆对象!万物皆对象!万物皆对象!(很重要,重复3遍)
每个对象包含3个属性,id,type,value
id就是对象地址,可以通过内置函数id()查看对象引用的地址。
type就是对象类型,可以通过内置函数type()查看对象的类型。
value就是对象的值。
# is和==的区别
str1 = 'aaaa'
str2 = 'bbbbb'
str3 = 'bbbbb'
str4 = str3
print(str1 == str2, str2 == str3, str3 == str4)
print("str2的地址:", id(str2), "
str3的地址:", id(str3), "
id(str2) == id(str3):", id(str2) == id(str3))

# 引用地址不一样,但是只要值一样即可==成立。
val1 = 2000
val2 = 2001
val3 = val1 + 1
print("val1的地址:", id(val1), "
val2的地址:", id(val2), "
val3的地址:", id(val3),
"
id(val2) == id(val3):", id(val2) == id(val3), "
val2 == val3:", val2 == val3)

# 3.对于类的实例比较
class Student(object):
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
print("can run")
stu1 = Student("tom",19)
stu2 = Student("tom",19)
stu3 = stu2
print(id(stu1)==id(stu2),stu1 == stu2) #False False
#注意这里stu1和stu2的值是不等的,虽然初始化创建对象格式一样。
print(id(stu2)==id(stu3),stu2 == stu3) # True True
关于is
1.is成立的前提要是内容相同,内存中地址相同 st1 ='aaaaa' st2 = 'bbbbb' st3 = 'bbbbb' st4 = st3 print(st1 is st2, st2 is st3,st3 is st4)#False True True print(id(st1),id(st2),id(st3),id(st4))


以上两题涉及到对象,用is
3.类型判断用isinstance,不用type
type()不会认为子类是一种父类类型。isinstance()会认为子类是一种父类类型。
class Foo(object):
pass
class Bar(Foo):
pass
if __name__ == '__main__':
print(type(Foo()) == Foo)
print(type(Bar()) == Foo)
print(isinstance(Foo(), Foo))
print(isinstance(Bar(), Foo))

4.对子类继承的变量,要显式定义和赋初值
class A(object):
x = 1
class B(A):
pass
class C(A):
pass
if __name__ == '__main__':
B.x = 2
print(A.x, B.x, C.x)



如果希望类C中的x不引用自A类,可以在C类中重新定义属性x,这样C类就不会引用A类的属性x了,它们之间值的变化就不会相互影响了

5. 赋值、浅拷贝和深拷贝
- =: 跟原对象完全相同,原对象改了啥,新对象也改了啥;
- deepcopy: 原对象改了啥,新对象都不变
- copy: 列表的列表会被修改

copy浅拷贝:拷贝一个对象,但是对象的属性还是引用原来的,对于可变类型,比如列表和字典,只是复制其引用。基于引用所作的改变会影响到被引用对象。只要原来的对象改变,被浅拷贝的就会改变。
deepcopy深拷贝:创建一个新的容器对象,包含原有对象元素(引用)全新拷贝的引用。外围和内部元素都是拷贝对象本身,而不是引用。原来的对象改变了,不会影响到新的深拷贝的。


注意:对于数字,字符串和其他原子类型等,没有被拷贝的说法。如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。使用copy和deepcopy时,需要了解其使用场景,避免错误。

运行结果:


运行结果:



6. 字符串处理,字符集
7. 正则表达式的使用
7.1 re.match()
尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。


7.2 re.search()
扫描整个字符串并返回第一个成功的匹配。


7.3 re.sub()
替换字符串中的匹配项。
re.sub(pattern, repl, string, count=0, flags=0)
- pattern : 正则中的模式字符串。
- repl : 替换的字符串,也可为一个函数。
- string : 要被查找替换的原始字符串。
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
- flags : 编译时用的匹配模式,数字形式。


7.4 re.group()
re.group(0)与re.group()相同返回全部字符串,1以后才是re.groups()中的各个组。
import re
m = re.match('(www)-(d?)', 'abc-123')
sentence = 'we are humans'
matched = re.match(r'(.*) (.*) (.*)', sentence)
if __name__ == '__main__':
print(m.group()) # abc-1
print(m.groups()) # ('abc', '1')
print(m.group(0)) # abc-1
print(m.group(1)) # abc
print(m.group(2)) # 1
print(matched.group()) # we are humans
print(matched.groups()) # ('we', 'are', 'humans')
7.5 re.split()
split 方法按照能够匹配的子串将字符串分割后返回列表。Python自带的split函数只能指定一个分割符,需要使用多个分割符时,可以使用re.split()。


7.6 re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。注意: match 和 search 是匹配一次 findall 匹配所有。


import re
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符( 、 )之外的任何单个或多个字符
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.groups() : ", matchObj.groups())
print("matchObj.group(0) : ", matchObj.group(0))
print("matchObj.group(1) : ", matchObj.group(1))
print("matchObj.group(2) : ", matchObj.group(2))
print("matchObj.group(3) : ", matchObj.group(3))
else:
print("No match!!")

