简单例子1
内建函数setattr() getattr() hasattr() 即使类中没有setattr 和 getattr魔术方法也不会报错 不同于len(A()), 如果类中没有len方法则会报错 setattr时,第2个位置的参数,可以是属性,也可以是方法,例如增加x属性,也可以是方法x。
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n1457" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"> class Point:
def init(self, x, y):
self.x = x
self.y = y
def str(self):
return "Point({}, {})".format(self.x, self.y)
def show(self):
print(self)
p = Point(1, 2)
动态增加或修改
print('*******')
print(setattr(p, 'x', 99)) # None
print(setattr(p, 'z', 100)) # None
print(p.dict)
获取
print(getattr(p, 'y')) # 2
print(getattr(p, 'q', None)) # None
print(getattr(p, 'dict'))
{'x': 99, 'y': 2, 'z': 100},属性获取
print(p.dict)
{'x': 99, 'y': 2, 'z': 100}, 实例字典获取
判断
print(hasattr(p, 'a')) # False
print(hasattr(p, 'x')) # True</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1459" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"> # 综合例子
通过实例判断,获取属性
if hasattr(p, 'show'):
getattr(p, 'show')() # Point(99, 2)
getattr返回一个绑定方法show,调用show方法。
通过 实例 判断,动态增加属性(用的少)
if not hasattr(p, 'sub'):
setattr(p, 'sub', lambda point1, point2: Point(point1.x - point2.x, point1.y - point2.y))
print(p.sub(Point(1, 2, ), Point(3, 3))) # Point(-2, -1)
通过 类 判断,动态增加类属性
if not hasattr(Point, 'add'):
setattr(Point, 'add', lambda point1, point2: Point(point1.x + point2.x, point1.y + point2.y))
print(p.dict) # 实例字典中有sub方法
print(Point.dict) # 类字典中有add方法,没有sub方法</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1461" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"> # 只用来测试(不优雅)
class Point:
def init(self, x, y):
self.x = x
self.y = y
def str(self):
return "Point({}, {})".format(self.x, self.y)
def show(self):
print(self.x, self.y)
def len(self):
return 10
p = Point(1, 2)
感觉这两个差不多
print(Point.dict) # 类字典。魔术方法,存在类字典中
print(dir(Point)) # 父类和实例的各种方法及属性,包括魔术方法,不包括x, y, z ,有序列表
print(p.dict) # 只有x,y,实例字典只存放init中的内容
print(dir(p)) # 最全,父类和实例的各种方法及属性,包括魔术方法,包括x, y, z, 有序列表
print(p.dir()) # 同dir(p), 无序列表
print(Point.dir(p)) # 同dir(p), 无序列表。类调用方法(魔术和普通),都不会注入第一参数
p.dict['x'] = 99 # 相当于调用setattr方法
print(p.dict)
p.z = 100 # 相当于调用setattr方法
print(p.dict) # 增加一个z
print(p.z) # 相当于调用getattr方法
</pre>
-
魔术方法setattr getattr delattr getattribute
setattr
-
调用setattr 的情景
init 函数中,self.x = x
在类的外面 obj.x = 50
在类的外面 setattr(obj, 'x', 50)
不会调用setattr 的情景
obj.dict['x'] = 50
setattr 魔术方法
-
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1479" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 这个方法可以拦截对实例属性的增加,修改操作,如果设置生效,实例的字典为空 # 实例通过.点号设置属性,例如设置self.x = x属性,就会调用
class Point:
z = 6
def init(self, x, y):
self.x = x # 这时会调用setattr
self.y = y
def setattr(self, key, value):
self.dict.setitem(key, value)
等价于 self.dict[key] = value
p = Point(1, 2)
p.x = 20
print(p.dict) # {'x': 20, 'y': 2}因为初始化时也会调用2次
setattr
setattr , 但是如果实例的属性要加到实例的dict中, 需要自己手动完成, 如果不手动添加,则默认dict是清空的 </pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1481" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">
如果只增加setattr方法,则实例字典会被清空
可以通过实例字典设置属性,但是取不出来属性,即无法使用obj.x
class Point:
z = 6
def init(self, x, y):
self.x = x # 这时会调用setattr
self.y = y
def setattr(self, key, value):
print("setattr {} = {}".format(key, value))
p = Point(1, 2)
print(Point.dict) # 有值
print(p.dict) # 如果只增加setattr方法,实例字典被空的
因为实例字典被清空了,而且也不会调用内键函数getattr(),所以报错
print(p.x) # 报错
print(p.y) # 报错
print(p.z) # 6
p.x = 50 # 还会调用setattr
print(p.x) # 刚设置完x属性,但还是取不到x属性,因为实例字典还是空的
print(p.dict) # {}
p.dict['x'] = 60 # 只有在实例的字典中添加x属性,才可以取到x属性,但是不会调用setattr
print(p.dict) # 字典中有值{'x': 60}
print(p.x) # 60</pre>
getattr
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1484" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 如果只增加getattr方法和原来没有什么变化,相当于没增加,一般不这么用
class Point:
z = 6
def init(self, x, y):
self.x = x # 这时会调用setattr
self.y = y
def getattr(self, item):
return "missing {}".format(item)
p = Point(1, 2)
print(Point.dict) # 有值
print(p.dict) # 如果只实现了getattr方法,实例字典中有值{'x': 1, 'y': 2}
print(p.x) # 1
print(p.y) # 2
print(p.z) # 6
p.m = 50 # 因为没有实现setattr方法,所以调用的是内键函数setattr()
print(p.m) # 50
print(p.dict) # 实例字典中有值{'x': 1, 'y': 2, 'm': 50}
p.dict['x'] = 60 # 只有在实例的字典中添加x属性,才可以取到x属性,但是不会调用setattr
print(p.dict) # 实例字典中有值x被改成{'x': 60, 'y': 2}
print(p.x) # 60
</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1487" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># getattr 魔术方法
查找属性顺序
instance.dict -> instance.class -> 继承类 —> object字典
class Base(object):
n = 0
z = 200
class Point(Base):
z = 6
x = 100
def init(self, x, y):
self.x = x
self.y = y
def getattr(self, item):
return "missing {}".format(item)
p = Point(1, 2)
print(Point.dict)
print(p.dict)
虽然父类没有实现setattr
但是object中实现了setattr
print(p.x) # 1
print(p.y) # 2
print(p.z) # 6
print(p.n) # 0
print(p.t) # missing 找了一圈找不到就会调用 getattr方法,
</pre>
setattr getattr综合应用的例
-
大多数情况都是这两种魔术方法同时使用
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1494" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># 其实不用实现这两个魔术方法,就可以满足开发需求
lass Point:def init(self, x, y):
self.x = x # 这时会调用setattr
self.y = y
p = Point(1, 2)
print(p.x) # 1
print(p.y) # 2
p.z = 9
print(p.z) # 9
</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1496" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># 如果想使用__setattr__ 和 __getattr__,则正常使用的例子
class Point:
z = 6
def __init__(self, x, y):
self.x = x # 这时会调用__setattr__
self.y = y
def __getattr__(self, item):
return item
def __setattr__(self, key, value):
# 直接操作字典不会递归
self.__dict__[key] = value
p = Point(1, 2)
print(Point.__dict__) # 有值
print(p.__dict__) # 有值
print(p.x) # 1
print(p.y) # 2
print(p.z) # 6
p.x = 50 # 还会调用因为实现了__setattr__,所以会调用__setattr__,内部打印字符串就可以看到
print(p.x) # 50
print(p.__dict__) # 有值
p.__dict__['x'] = 60 # 实例的字典中添加x属性,但是不会调用__setattr__,内部打印字符串就可以看到
print(p.__dict__) # 有值
print(p.x) # 60</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1499" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 内键函数与魔术方法的区别例子
setattr()函数,当类中实现了setattr方法时,会走类中的这个方法
getattr()函数,当类中实现了getattr方法时,并且实例的字典中没有要获取的属性时,才会走类中的这个方法
class Point:
z = 6
def init(self, x, y):
self.x = x # 这时会调用setattr
self.y = y
def getattr(self, item):
print('111111')
return 'item: {}'.format(item)
def setattr(self, key, value):
直接操作字典不会递归
print('222222')
self.dict[key] = value
p = Point(1, 2)
p.x = 50 # 调用setattr
print(p.x) # 实例的字典中取到了50,没调用getattr
print(p.m) # 实例的字典中没有m属性,才会调用getattr
setattr(p, 'n', 99) # 调用setattr
print(p.n) # 取实例的字典中n属性,没调用getattr
print(p.m) # 实例的字典中没有m属性,才会调用getattr
print(getattr(p, 'n')) # 从字典中取
print(getattr(p, 't')) # 调用getattr</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1501" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 测试用例,正常代码不这么写
class Point:
z = 6
def init(self, x, y):
self.x = x # 这时会调用setattr
self.y = y
def getattr(self, item):
return "missing {}".format(item)
def setattr(self, key, value):
print("setattr {} = {}".format(key, value))
p = Point(1, 2)
print(Point.dict) # 有值
print(p.dict) # 空的
因为实例字典被清空了,但是类字典没有被清空,所以取不到x,y,但是能取到z
print(p.x) # missing x
print(p.y) # missing t
print(p.z) # 6
p.x = 50 # 还会调用setattr
print(p.x) # 刚设置完x属性,但还是取不到x属性,因为实例字典还是空的
print(p.dict) # {}
p.dict['x'] = 60 # 只有在实例的字典中添加x属性,才可以取到x属性,但是不会调用setattr
print(p.dict) # 字典中有值{'x': 60}
print(p.x) # 60
</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1503" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">class Base:
n = 0 class Point(Base):
z = 6
d = {}
def init(self, x, y):
self.x = x # 这时会调用setattr
setattr(self, 'y', y)
self.dict['a'] = 5
def getattr(self, item):
print("missing {}".format(item))
return self.d[item]
def setattr(self, key, value):
print("setattr {} = {}".format(key, value))
self.d[key] = value
p = Point(1, 2)
print('+++++++++++++')
print(Point.dict)
print(p.dict)
print(p.x) # missing x 当找到类的字典时,'d'下面有'x', 但是外面没有'x', d': {'x': 1, 'y': 2}
print(p.z) # 6
print(p.n) # 0
print(p.t) # missing t
print(p.a) # 5 </pre>
delattr( 了解)
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1506" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">class Point:
z = 6
def init(self, x, y):
self.x = x
self.y = y
def delattr(self, item):
return print('Can not del {}'.format(item))
p = Point(1, 2)
del p.x
p.z = 15
del p.z
不能删除了</pre>
getattribute(了解)
实例的所有属性访问,第一个都会调用这个方法,它阻止了属性的查找顺序,
该方法应该返回计算后的值,或者抛出一个Attribute Error异常
它的return值将作为属性查找的结果
如果抛出AttributeError, 则会直接调用 getattr方法,因为属性没有找到
属性查找顺序
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1517" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># instance.getattribute ->instance.dict -> instance.class -> 祖类 —> object字典</pre>
使用方法
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1519" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># getattribute方法中为了避免出现无限递归,它的实现应该永远调用基类的同名方法以访问需要的任何属性,例如:object.getattribute(self, name),
一般不要使用这个方法</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1520" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">class Point(Base):
z = 6
def init(self, x, y):
self.x = x
self.y = y
def getattr(self, item):
return("missing {}".format(item))
def getattribute(self, item):
return object.__getattribute(self, item)
return super().getattribute(item)
p = Point(1, 2)
print('+++++++++++++')
print(Point.dict)
print(p.dict)
print(p.x) # 1
print(p.z) # 6
print(p.n) # 0
print(p.t) # missing t </pre>
增加子类功能的3种方法
1、直接继承然后修改,2、给子类增加一个装饰器, 3、Mixin Mixin就是其他类混合进来,同时带来了类的属性和方法,本质上是多继承,是一种组合的设计模式。和装饰器比较,两者的装饰效果一样,但是Mixin是类,可以继承。 Mixin类的使用原则:
Mixin类中不应该显示的出现init方法
Mixin类通常不能独立工作,因为它是准备混入别的类中,实现部分功能
-
Mixin类的祖先类也应该是Mixin类
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1531" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># 直接继承
class Document: #因为有print方法未实现,所以称为抽象基类
def init(self, content):
self.content = contentdef print(self):
raise NotImplementedError
class Word(Document):
def print(self):
print(self.content, 'word style')
class Pdf(Document):
def print(self):
print(self.content, 'pdf style')
class Test(Document): #在python中,这个子类可以不实现父类中的print方法,
# 但是在其他语言中,如果继承自父类,但是父类的抽象方法,未能全部实现,
# 则这个子类也属于抽象类,抽象类不可以实例化
pass
w = Word('tutu')
w.print()
#装饰器
class Document:
def __init__(self, content):
self.content = content
class Word(Document):
pass
# 装饰器1
def printable(cls):
def wrapper(content):
cls.print = lambda: print(content)
return cls
return wrapper
# 装饰器2
def printable(cls):
def wrapper(content):
def fn():
print(content)
cls.print = fn
return cls
return wrapper
# 装饰器3 **********************************
def printable(cls):
def fn(self): # 这3行等价于 cls.print = lambda self: print(self.content)
print(self.content)
cls.print = fn
return cls
# 装饰器4,注意使用print时,不要出现递归
def printable(cls):
def _print(self): # 写在类的外面的,但是需要给类添加的方法,第一个参数必须为self
print(self.content)
cls.print = _print
return cls
@printable #PrintableWord = printable(PrintableWord)
class PrintableWord(Word):pass
p = PrintableWord('abs')
p.print()
# Mixin,多继承
# PrintableMixin一般值需要里面的print方法,里面一般不写__init__
class Document:
def __init__(self, content):
self.content = content
class Word(Document):
pass
class PrintableMixin:
def print(self): #这个两个print不会出现递归,因为第一个print相当于有一个隐藏的名字,
# 只能通过这两种方法调用,PrintableMixin.print(instance) p.print()
print(self.content)
class PrintableWord(PrintableMixin, Word):pass
p = PrintableWord('abs')
p.print()
#print(PrintableMixin.__dict__)
# Mixin增强
class Document:
def __init__(self, content):
self.content = content
class Word(Document):
pass
# Mixin功能,多继承
class PrintableMixin:
def print(self):
print(self.content)
class SuperPrintableMixin(PrintableMixin):
def print(self):
print('增强之前打印:', self.content)
super().print()
print('增强之后打印:')
class PrintableWord(SuperPrintableMixin, Word): pass
p = PrintableWord('abs')
p.print()
</pre>
python2.7与python本质区别(了解)
python2.7中与python3的不同: 都不同python3 type(A), dir(A) a.class
dir() 函数的用法 dir(A) 收集对象的属性
模块化
模块化是组织代码的方式,封装代码,封装就是边界
在其他编程语言中,库、包、模块是同一种概念,是代码组织方式
在python中:
模块module:python文件
包package:是指模块组织在一起的,和包同名目录及其相关文件
导入语法
-
import 只能加模块名
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1552" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># 完全限定名称访问path
import os.path # 导入os.path, os加入当前名字空间
print(dir()) # 里面只有os,没有os.path</pre> -
import as
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1555" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">import os.path as osp # 导入os.path并赋值给osp
print(dir()) # 里面只有osp</pre> -
局部导入
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1558" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">def testimport():
import os.path
print(dir()) # os存在里面
testimport()
print(globals().keys()) # os不存在里面
</pre> -
总结
导入顶级模块,其名称会加入到本地名词空间中,并绑定到其模块对象
导入非顶级模块,只将其顶级模块名称导入到本地名词空间。导入的模块必须使用完全限定名称来访问。
如果使用了as, as后的名称直接绑定到导入的模块对象,并将该名称加入到本地名词空间
-
其他例子:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1570" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">from functools import wraps as wr, partial
print(dir()) # [..., 'wr', 'partial']</pre>四种方式获得同一个对象的 exists
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1572" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">import os
print(os.path.exists)
print(exists)
print(os.path.dict['exists']) # 字符串,os.path被导入之后,可以取dict
print(getattr(os.path, 'exists')) # 字符串, module对象也可以使用getattr来获得属性</pre> -
from 必须加模块 import 类名,函数名,模块名
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1575" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">from pathlib import Path # 导入类Path
print(Path, id(Path))
import pathlib as p1
print(p1.Path, id(p1.Path)) # p1.Path 与 Path 是同一个对象,id相同</pre>
自定义模块
模块名:由字母数字下划线组成,不能以数字开头,不能有中文
不要使用系统模块名,以避免冲突,通常模块名为全小写,下划线来分割。
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1579" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># test1.py
class A:
def showmodule(self):
print(1, self.module, self)
print(2, self.dict)
print(3, self.class.dict)
print(4, self.class.name)
a = A()
a.showmodule() # self.module = 'main'
test2.py
import test1
a = test1.A()
a.showmodule() # self.module = 'test1'
test3.py
from test1 import A as cls
a = cls()
a.showmodule() # # self.module = 'test1'</pre>
模块搜索顺序
会从sys.path中,从前到后依此查找,并不搜索这些目录的子目录
路径可以是字典、zip文件、egg文件。egg文件是由setuptools库创建的包, 第三方库常用的格式。zip文件是添加了元数据(版本号,依赖项等)信息的文件
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1584" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">print(*sys.path, sep='\n')</pre>
sys.path路径搜索顺序为
程序主目录,程序运行主程序脚本所在的目录文件
PYTHONPATH目录,环境变量PYTHONPATH设置的目录
标准库目录,python自带的库模块所在的目录
第3方库
模块会出现重复导入嘛?
模块不会存在重复导入的现象,所有加载的模块都会记录在sys.modules 中,
sys.modules是存储已经加载所有模块的字典,里面包含os, os.path
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1598" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># test1.py
class A:
def showmodule(self):
print(1, self.module, self)
print(2, self.dict)
print(3, self.class.dict)
print(4, self.class.name)
a = A()
a.showmodule()
test2.py
import test1
print('*****')
import test1 # 只能看到一次1,2,3, 4的打印,只有第一次导入打印了,
print(sys.modules) # 可以看到test1在里面了。
</pre>
name main
解释器初始化时,会初始化sys.modules字典,然后加载builtins模块、main模块、sys模块,及sys.path
name
每个模块都有这个特殊变量来存储当前模块的名称,如果不指定,则默认为源代码文件名,如果是包则有限定名。import导入模块,name默认是模块名。
当从标准输入(命令行方式巧代码)、运行脚本($ python test.py)、交互式读取时,这3种情况都会将name设置为main,模块的顶层代码在main,这个作用域中执行
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1607" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">if name == 'main':
print('in main')
else:
print('in imported module')</pre>
if name == 'main':作用
对于非主模块,测试本模块内的函数、类
-
避免主模块变更的副作用
顶层代码没有封装,主模块使用时没有问题。但是,一旦有了
新的主模块,旧的主模块成了被导入模块,由于原来代码没有封装,一并执行了
模块属性
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python " cid="n1618" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">file 源文件绝对路径,字符串
name 模块名
package 如果模块是包,同name; 否则可以设置为顶级模块的空字符串
spec 显示模块规范
cached 编译后的字节码文件路径,字符串</pre>
在m1文件中导入m2,并且查看m2属性的两种方法
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1620" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">import m1.m2 as m2 # m1下面同时存在m2模块和m2包,找到的是m2包
print(dir(m2)) # 获得m2的属性名,返回列表,如果在m2里面的init文件中,加入属性B,则可以看到
print('************')
for name in dir(m2):
print(getattr(m2, name))
m2模块相当于一个字典,从字典中获得name属性。例如:
name doc file等
等价于
print('***********')
for k, v in m2.dict.items():
print(v)
问题:如果m2中有变量A,为什么dir(m2),看不到A,如果在m2中输入dir(),就可以看到A?因为先找到的是m2包
</pre>
包
- 总结:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1626" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 如果想在目录下面写代码,需要写入目录下的初始化文件中
当目录作为模块使用,则会执行初始化文件中的代码
模块不是包,但是,包是一种特殊的模块
模块就是命名空间,其内部的顶层标识符,都是它的属性,可以通过dict或者dir(module)查看。</pre>
-
模块的加载与加入到命名空间的对比
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1630" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">import sys
import m.m1.m2
print(dir()) # 只有'm'
print(sorted(filter(lambda x: x.startswith('m'), sys.modules.keys())))'m', 'm.m1', 'm.m1.m2'都在,依次加载m,m1,m2的初始化文件
from os import stat
print(dir()) # 没有osprint(os.path()) # 为什么用不了?os没在当前的命名空间,虽然os已经被加载过了
改成
import os.stat
print(os.path) # 可以使用因为os,加入到了当前命名空间了</pre> -
绝对导入与相对导入
在包内部各个模块之间相互调用,建议使用相对导入
在包外部使用,包内部模块,建议使用绝对导入
-
绝对导入:import 或者from语句后面没有. 绝对导入的搜索顺序是,
先到sys.modules中查看是否已经被加载,被加载直接取出,如果没有被加载,则按照sys.path中的顺序搜索,然后加载到sys.modules模块中,sys.path的搜索顺序是当前运行模块的根路径,PYTHONPATH路径,标准库和第三方库。
-
相对导入:
只能from语句后面有.
1个点表示当前目录内
2个点表示上一级目录
3点表示上上级目录
一旦一个模块中使用相对导入,就不可以作为主模块运行了
相对导入是为了保证包内部资源的相互引用,而不是为了直接运行,正确的使用方式是在顶层模块中使用这些包。
-
-
- 与all
在模块m11中定义普通变量、保护变量、私有变量、特殊变量:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1661" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">A = 5
_B = 6
__C = 7
my = 8</pre>在模块m1中导入模块m11
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1663" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">import m11
print(m11.A, m11._B, m11.__C, m11.my) # 没有被隐藏都可以访问也就是说模块内所有变量都不做特殊处理</pre>
如果导入时使用*:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python " cid="n1665" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># 在m1模块中写入代码,并且运行m1
from m11 import * # 问题:问什么使用.m11就不可以呢?
print(dir()) # 只能看到普通变量A,带下划线的都看不到了</pre>如果在模块m11中加入all, 则all中有什么,命名空间就有什么变量
all是一个列表,里面元素是字符串,每个元素只能是当前模块中的属性名。
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1668" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">all = ['A', '_B']
A = 5
_B = 6
__C = 7
my = 8在m1中运行
from m11 import *
print(dir()) # ['A', '_B']</pre> -
例子:从顶层模块访问包中属性的方法
如果使用了*, 就尽量使用all, 避免导入过多的模块,而产生冲突
一般使用from module import name1, name2
已知:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1676" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># m 的init.py中写入
print(name)
x = 5m1文件中写入
print(name)
y = 5
</pre>问题:顶层模块test.py如何访问到m1中的y?
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1678" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"># 方法1
在test文件中写入
from m import m1
print(m1.y)
# 方法2(不可以因为m.m1没在命名空间,容易错的导入)
import m
print(m.m1.y)
# 方法3
# 在m的__init__文件中写入 ,__all__ = ['x', 'm1'], __all__中包含的字符串名字是__init__.py中的属性名,和m包下面的模块名m1.
from m import *
print(dir()) # ['x', 'm1']
print(m1.y)
# 方法4
# 在m的__init__文件中写入
# from . import m1
from m import * # __init__.py中有什么变量,就导入了什么变量
print(m1.y)</pre>
-
模块变量的修改
模块对象是同一个,因此模块的变量也是同一个,对模块变量的修改会影响所有的使用该模块使用者,特别是常量,引用类型的还好。
另外可以通过猴子补丁的方式修改模块的变量、类、函数。
打包分发
使用setup.py打包
在项目根目录下建立一个setup.py文件(和m包同级),在里面填写脚本
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1688" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">from distutils.core import setup
setup(name='m',
version='1.0',
description='Python test m',
author='JW',
author_email='',
url='',
packages=['m', 'm.m1', 'm.m1.m2'],
)
packages里面填写,所有包名</pre>
创建源代码分发包
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1690" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 在项目根目录下生成dist文件里面有m-1.0.tar.gz
$ python setup.py sdist
安装写好的包,方法1
$ pip install m-1.0.tar.gz
安装写好的包,方法2
先解压,里面含有setup.py文件
$ python setup.py install
</pre>
对于需要编译的语言,需要先编译再安装
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1692" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">$ python setup.py build
会在根目录下生成一个build文件夹,在lib下是编译好的文件</pre>
setup.py生成各种压缩包的命令
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1695" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"> python setup.py bdist --format=rpm
python setup.py bdist --format=egg
python setup.py bdist_wheel</pre>
插件化开发
参考笔记10模块化03插件化开发.pdf
面向对象补充
未实现和未实现异常
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1701" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># NotImplemented, 是NotImplementedError实例,是个单值,类似与None
NotImplementedError,是一个类
print(type(NotImplemented)) # <class 'NotImplementedType'>
print(type(NotImplementedError)) # <class 'type'></pre>
slots魔术方法
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1703" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># slots内存不够用时使用,需要很多实例,例如:点类,适用属性和值都简单的类,</pre>
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1704" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">使用slots
不可以动态增加属性
实例没有dict属性了
不影响继承实例的字典
class A:
x = 1
slots = ('y', 'z') # 一般用元组
slot = 'y', 'z' # 与上面等价
slot = ['y', 'z']
slot = 'y' # 也是一个元组
def init(self):
self.y = 5
self.z = 10
def show(self):
print(self.x, self.y)
a = A()
a.show()
print('A:', A.dict)
print('a:', a.dict) 没有这个属性了
</pre>
slots不影响继承
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1706" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 继承
class A:
x = 1
slots = ('y', 'z') # 一般用元组
slot = 'y', 'z' # 与上面等价
slot = ['y', 'z']
slot = 'y' # 也是一个元组
def init(self):
self.y = 5
self.z = 10
def show(self):
print(self.x, self.y)
class B(A):
pass
print('********')
b = B()
print('B:', b.dict) # {}
</pre>
内建函数tracemalloc
tracemalloc -Trace memory allocations
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1709" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 内建模块,具体信息参考官方文档
import tracemalloc
tracemalloc.start() # 开始跟踪内存分配
d = [dict(zip('xy', (5, 6))) for i in range(1000000)] # 237M
t = [tuple(zip('xy', (5, 6))) for i in range(1000000)] # 191M
snapshot = tracemalloc.take_snapshot() # 快照,当前内存分配
top_stats = snapshot.statistics('lineno') # 快照对象统计,按行统计内存
top_stats = snapshot.statistics('filename') # 参看当前文件总内存
for stat in top_stats:
print(stat)</pre>
运算符重载中的反向方法
add 与iadd
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1713" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">class A:
def init(self, x):
self.x = x
def add(self, other):
print('add')
return self.x + other.x
def iadd(self, other):
print('iadd')
return A(self.x + other.x)
def radd(self, other):
print('radd')
if hasattr(other, 'x'):
return self.x + other.x
else:
raise NotImplementedError
def str(self):
return str(self.x)
repr = str
print('***********')
a = A(4)
c = A(5)
print(a + c) # add 9
print(c + a) # add 9
a += c # iadd 9
print(a)
c += a # iadd 9
print(c)
</pre>
调用iadd的情况,B类中没有实现add方法,A类中实现了
radd方法,想计算b + a
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1716" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 一种实现
class A:
def init(self, x):
self.x = x
def add(self, other):
print('add')
return self.x + other.x
def iadd(self, other):
print('iadd')
return A(self.x + other.x)
def radd(self, other):
print('radd')
if hasattr(other, 'x'):
return self.x + other.x
else:
raise NotImplementedError
def str(self):
return str(self.x)
repr = str
class B:
def init(self, x):
self.x = x
def add(self, other):
if isinstance(other, type(self)):
return self.x + other.x
else:
return NotImplemented
a = A(2)
bb = B(3)
print('*************')
print(bb + a) # bb.add(a) 找到NotImplemented, 所以反转计算a + bb,近而调用a.radd(bb)
print('+++++++++++')
bb += a # bb没有iadd 找到add, 抛出NotImplemented,所以找到a.radd
print(bb)
</pre>
另一种实现
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1718" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">class A:
def init(self, x):
self.x = x
def add(self, other):
print('add')
return self.x + other.x
def iadd(self, other):
print('iadd')
return A(self.x + other.x)
def radd(self, other):
print('radd')
if hasattr(other, 'x'):
return self.x + other.x
else:
raise NotImplementedError
def str(self):
return str(self.x)
repr = str
class B: # 默认未实现add
def init(self, x):
self.x = x
a = A(2)
bb = B(3)
print(bb + a)
print('+++++++++++')
bb += a
print(bb)</pre>
实现 1 + a
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1720" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 1 + a 方法1
class A:
def init(self, x):
self.x = x
def add(self, other):
print('add')
return self.x + other.x
def iadd(self, other):
print('iadd')
return self.x + other.x
def radd(self, other):
print('radd')
if hasattr(other, 'x'):
return self.x + other.x
elif isinstance(other, int):
return self.x + other
else:
raise NotImplemented
def str(self):
return str(self.x)
repr = str
a1 = A(3)
print(1 + a1) # 1.add(a), 但是这个加法的返回值是NotImplemented,
解释器发现是这个值,就发生反转相当于计算a1 + 1,所以就从a对象找radd
</pre>
方法2
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1722" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;"># 如果不是整型,返回自己, 1+a 另一种实现
class A:
def init(self, x):
self.x = x
def add(self, other):
print('add')
return self.x + other.x
def iadd(self, other):
print('iadd')
return self.x + other.x
def radd(self, other):
print('radd')
if hasattr(other, 'x'):
return self.x + other.x
else:
try:
other = int(other)
except ValueError:
other = 0
return self.x + other
def str(self):
return str(self.x)
repr = str
a1 = A(8)
print(1 + a1)
print('abc' + a1)
</pre>
python中的对象模型
python中任何对象都有类型,可以使用type() 、class查看
继承所有类都继承自object,type类也继承自object,object的父类是空
python中所有类的类型都是type(元类),实例的类型是生成实例的类。
无参构造与值
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n1734" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">print(None)
print(Exception) # 无参构造是一个类
print(NotImplemented)</pre>