1.类和对象(I)总结 类的定义、self的用法
2.类的继承、类的判断isinstance()、issubclass()、多重继承、类的组合
1.类的绑定(self的妙用)
例1:
>>> class Cat:
def say(self):
print("喵喵喵")
>>> class Dog:
def say(self):
print("啊呦,,,,")
>>> class Turtle:
def say(self):
print("不积跬步无以至千里。")
>>> class Garden:
t=Turtle()
c=Cat()
d=Dog()
def say(self):
self.t.say()
self.c.say()
self.d.say()
>>> g=Garden()
>>> g.say()
不积跬步无以至千里。
喵喵喵
啊呦,,,,
>>>
这里需要用到self.t.say(),而不是t.say(),t.say()会报错
>>> class Garden:
t=Turtle()
c=Cat()
d=Dog()
def say(self):
t.say() #会报错
c.say()
d.say()
>>> g=Garden()
>>> g.say()
Traceback (most recent call last):
File "", line 1, in
g.say()
File "", line 6, in say
t.say()
NameError: name 't' is not defined
例2:
c中定义的元素d中没有定义,所以会报错。
>>> d=C()
>>> d.x=234
>>> c.x
>>> d=C()
>>> d.x=234
>>> c.x
Traceback (most recent call last):
File "", line 1, in
c.x
AttributeError: 'C' object has no attribute 'x'
2.查看属性__dict__
dict左右有两个下划线
例3:
>>> c.__dict__
{'x': 520}
>>> d.__dict__
{'x': 234}
>>> d.y=660
>>> d.__dict__
{'x': 234, 'y': 660}
例4:
>>> class C:
def set_x(self,v):
self.x=v
>>> c=C()
>>> c.__dict__
{}
>>> c.set_x(250)
>>> c.__dict__
{'x': 250}
>>> c.x
250
3.最简单类元素定义
例5:
定义一个空的类,然后对类进行属性的赋值。
>>> class C:
pass
>>> C.x=250
>>> C.y="小甲鱼"
>>> C.z=[1,2,3]
>>> print(C.x)
250
>>>
>>> print(C.y)
小甲鱼
>>>
>>> print(C.z)
[1, 2, 3]
例6:
>>> d={}
>>> d['x']=250
>>> d['y']="小甲鱼"
>>> d['z']=[1,2,3]
>>> print(d['x'])
250
>>> print(d['y'])
小甲鱼
>>> print(d['z'])
[1, 2, 3]
>>>
>>>
>>> class C:
pass
>>> c=C()
>>> c.x=250
>>> c.y="小甲鱼"
>>> c.z=[1,2,3]
课后题:
1.请问方法绑定的意义是什么?
答:共享!
解析:一辆共享单车,如何识别是谁在骑它?无非就是通过扫码绑定
一样的道理,为了节约内存,Python 没必要为每一个对象的方法都做一次拷贝,但如何区分是谁在调用?
通过 self 参数的绑定来识别嘛
2. 下面代码中,调用 c.hello() 和 C.hello© 的结果是一样的,请问它们是完全等价的吗?
>>> class C:
... def hello(self):
... print("Hello FishC.")
...
>>> c = C()
>>> c.hello()
Hello FishC.
>>> C.hello(c)
Hello FishC.
答:是的。
解析:
是的!方法相比函数来说,确实就是多了这么一个绑定的操作。因此,C.hello© 属于函数调用,而 c.hello() 则属于方法调用。
3.请问下面代码会打印什么呢?
>>> class C:
... x = 100
... def get_x(self):
... print(x)
...
>>> c = C()
>>> c.x = 250
>>> c.get_x()
>>> # 请问这里会打印什么内容?
答:会报错(抛出异常 NameError: name ‘x’ is not defined)。
解析:在类的方法中直接访问 x 属性,并不会去对象或者类中找 x,根据 LEGB 原则,去找对应的变量。
理解了下面代码,大家应该就很清晰了:
>>> x = 123
>>> class C:
... x = 100
... def get_x(self):
... print(f"x = {x}")
... print(f"self.x = {self.x}")
...
>>> c = C()
>>> c.get_x()
x = 123
self.x = 100
>>> c.x = 250
>>> c.get_x()
x = 123
self.x = 250
4.请问下面代码会打印什么呢?
>>> class C:
... x = 100
... def get_x(self):
... print(self.x)
...
>>> c = C()
>>> c.x = 250
>>> c.get_x()
>>> # 请问这里会打印什么内容?
答:250
解析:这里 c.x = 250,设置的是对象的 x 属性,当对象设置了属性之后,就不会再去访问其类的同名属性了。
5.请问下面代码会打印什么呢?
>>> class C:
... x = 100
... def get_x(self):
... print(C.x)
...
>>> c = C()
>>> c.x = 250
>>> c.get_x()
>>> # 请问这里会打印什么内容?
答:100
解析:虽然 c.x = 250 设置的是对象的 x 属性,但是这里的细节是 print(C.x),所以打印的永远是类的 x 属性(而非对象的)。
6. 请问下面代码会打印什么呢?
>>> class C:
... def f(self):
... print("Hello FishC.")
...
>>> c = C()
>>> type(C.f) == type(c.f)
>>> # 请问这里会打印什么内容?
答:False。
解析:因为一个是函数(在类中定义,它还是一个函数),一个是方法(绑定了对象,那么它就是一个方法)。
>>> type(C.f)
>>> type(c.f)
7.请问下面代码会打印什么呢?
>>> class C:
... x = []
... def add_x(self, x):
... self.x.append(x)
...
>>> c = C()
>>> d = C()
>>> c.add_x(250)
>>> d.add_x(520)
>>> c.x
>>> # 请问这里会打印什么内容?
答:[250, 520]
解析:
列表这类容器啊,就是这样的。它是单独存储的,然后所有它的引用都是指向相同的位置。