1."init"方法不能return,或者说,return None:
class Foo:
def __init__(self):
print("I'm in init()...")
return 200
Foo()
>>>
I'm in init()...
Traceback (most recent call last):
File "C:\Users\wcw\Desktop\Testing.py", line 5, in <module>
foo()
TypeError: __init__() should return None, not 'int'
2."类属性"一般不要随意修改
"实例属性"可以随意修改
>>> class AA:
x=7
>>> aa=AA()
>>> aa.x
7
# 重新赋值,原来的aa.x被遮盖
>>> aa.x=100
# 实例属性变了
>>> aa.x
100
# 类属性依然没变
>>> AA.x
7
# 这里删除的指向100的指针
>>> del aa.x
# 原来的指针又还原了
>>> aa.x
7
# 类属性变了,实例变量跟着改变,前提是类属性指向的是"不可变"的值
>>> AA.x+=1
>>> aa.x
8
# 如果指向的是可变的"值",结果就是互相影响:
>>> class B:
y=[1,2,3]
>>> bar=B()
>>> bar.y
[1, 2, 3]
>>> bar.y.append(4)
>>> bar.y
[1, 2, 3, 4]
>>> B.y
[1, 2, 3, 4]
>>> B.y.append(5)
>>> B.y
[1, 2, 3, 4, 5]
>>> bar.y
[1, 2, 3, 4, 5]
# 新增类属性,那么实例也会有相应的属性,反过来就不行
>>> B.x="Hello"
>>> bar.x
'Hello'
>>> bar.z="World"
>>> bar.z
'World'
>>> B.z
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
B.z
AttributeError: type object 'B' has no attribute 'z'
>>> class AA:
x=7
# 返回的结果虽然一样,但是所代表的不一样
>>> AA.x
7
>>> AA().x
7
>>> type(AA)
<class 'type'>
>>> type(AA())
<class '__main__.AA'>
3."self"---代表实例,与"实例对象"区别在于,self主内,实例主外
self实际就是实例对象,二者相等,只不过self放在类里面代表实例对象.为什么不直接把实例对象放入类里面?因为self具有独立性,有self的类可以创建无数模板(实例),而如果放入实例对象,那么该类模板,只能为一个实例对象服务.
>>> class Girl:
def __init__(self,name):
self.name=name
print(self)
print(type(self))
# self的反馈和实例对象cang一模一样
>>> cang=Girl('teacher')
<__main__.Girl object at 0x00000000030A8B38>
<class '__main__.Girl'>
>>> cang
<__main__.Girl object at 0x00000000030A8B38>
>>> type(cang)
<class '__main__.Girl'>
- 实例
class Person:
def __init__(self,name):
self.name=name
def getName(self):
return self.name
def breast(self,n):
self.breast=n
def color(self,color):
print("{0} is {1}".format(self.name,color))
def how(self):
print('{0} breast is {1}'.format(self.name,self.breast))
girl=Person('canglaoshi')
girl.breast(90)
girl.color('white')
girl.how()
>>>
canglaoshi is white
canglaoshi breast is 90
- 实例变量替换self,只是用来理解,不要这么写,因为没有独立性:
class Person:
#这么写也可以
# def __init__(girl,name):
# girl.name=name
def __init__(self,name):
self.name=name
# 这么做也可以
# def get_name(girl):
def get_name(self):
# 使用实例变量替换self
return girl.name
girl=Person('canglaoshi')
print(girl.get_name())
>>>
canglaoshi
- 进一步的讨论:
class Foo:
def bar(self):
print(' This is a normal method of bar')
# 通常的做法,用实例去调用类方法
f=Foo()
f.bar()
>>>
This is a normal method of bar
# 直接用类调用
Foo.bar(f)
#Foo.bar(Foo())
>>>
This is a normal method of bar
- 通过类(获取的是非绑定的方法)和实例(获取的是绑定的方法)获取函数对象:
class Foo:
def bar(self):
print(' This is a normal method of bar')
f=Foo()
f.bar()
Foo.bar(f)
Foo.bar(Foo())
print(Foo.bar)
print(f.bar)
print(Foo.__dict__['bar'])
>>>
This is a normal method of bar
This is a normal method of bar
This is a normal method of bar
<function Foo.bar at 0x00000000005B7F28>
<bound method Foo.bar of <__main__.Foo object at 0x00000000030F8B70>>
<function Foo.bar at 0x00000000005B7F28>
4.描述器
什么是描述器?
Python中有几个特殊方法比较特殊,它们分别是:
__get__() 、 __set__() 和 __delete__()
简单地说,有这些方法的对象叫做描述器。(实质就是对象调用这些方法,就称描述器)
描述器是属性、实例方法、静态方法、类方法和继承中使用的 super 的背后实现机制,它在Python中使用广泛。这句话中的那些生疏的名词,以后都会用到,稍安勿躁。如何使用?
上述三个特殊方法,可以用下面的方式来使用——所谓的描述器协议。
descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None
关于描述器的内容,本节不重点阐述,这里提及它,目的是要解决“绑定方法”和“非绑定方法”的问题,所以,读者如果有兴趣深入了解描述器,可以去google。
弱水三千,只取一瓢。我们在这里也只看 get() 。
# Foo.__dict__['bar']是函数对象
# 实例为None,obj=Foo
>>> Foo.__dict__['bar'].__get__(None, Foo)
<unbound method Foo.bar> #Python 3显示结果:<function Foo.bar at 0x00000000006AAC
80>
对照描述器协议,我将 self 赋以了 None ,其返回结果和 Foo.bar 的返回结果是一样的。
让 self 为 None 的意思就是没有给定的实例,因此该方法被认为非绑定方法(unbound method)。
如果给定一个实例呢?
>>> Foo.__dict__['bar'].__get__(f, Foo)
<bound method Foo.bar of <__main__.Foo object at 0x02A9BFB0>>
这时候的显示结果和 f.bar 是相同的。
综上所述,可以认为:
- 当通过类来获取方法的时候,得到的是非绑定方法对象。
- 当通过实例获取方法的时候,得到的是绑定方法对象。
所以,通常用实例调用的方法,都是绑定方法。那么非绑定方法在哪里会用到呢?当学习“继承”相关内容的时候,它会再次登场。
小结:用类去调用方法和用实例去调用方法,实质上还是有区别的...
5.类方法---@classmethod
class Foo:
one=0
def __init__(self):
Foo.one+=1
# 修饰符
@classmethod
# 类方法第一个参数不是self,而是表示类对象
def get_class_attr(cls):
return cls.one
if __name__=='__main__':
f1=Foo()
print("f1:",Foo.one)# 1
f2=Foo()
print("f2",Foo.one)# 2
print(f1.get_class_attr())# 2
print("f1.one",f1.one)# 2
print(Foo.get_class_attr())# 2
print("*"*10)
f1.one=8
Foo.one=9
print(f1.one)# 8
# 实例调用的是"类方法",而不是调用实例的类的普通方法
print(f1.get_class_attr())# 9
print(Foo.get_class_attr())# 9
6.静态方法---@staticmethod:当类对象想调用外部函数时,可以把外部函数写到类里面,变成静态方法去调用,写法上更简洁.这里如果把外部函数写成普通方法,类对象去调用的时候,还需要传入实例.而静态方法是不需要传入self的,所以代码会更简洁
引言实例
def check_t():
T=3
return T
class Foo:
def __init__(self,name):
self.name=name
def get_name(self):
# 方法里面调用外部的函数
if check_t():
return self.name
else:
return "no person"
if __name__=='__main__':
f=Foo('Teacher Cang')
name=f.get_name()
print(name) # Teacher Cang
# 会报错,提示没有该属性
# 显然,类对象调用外部函数是失败的
print(Foo.check_t())
- 使用静态方法,类对象也可以调用
class Foo():
def __init__(self,name):
self.name=name
# 静态方法,用修饰符修饰
@staticmethod
# 静态方法是独立的,不需要self
def check_t():
T=3
return T
def get_name(self):
# 这么写也可以
# if Person.check_t():
# 实例方法
if self.check_t():
return self.name
else:
return "No person."
f=Foo('Jim Green')
# 实例调用完全没问题
print(f.get_name())# Jim Green
# 类对象调用也没问题
print(Foo.check_t()) # 3
网友评论