类 对象
类 对象是c++和java中都有的内容,python定义类的简单语法如下:
class 类名:
…类变量或者方法
Python 的类定义有点像函数定义,都是以冒号:作为类体的开始,以统一缩进的部分作为类体的。如果不为类定义任何类变量和方法,那么这个类就相当于一个空类,如果空类不需要其他可执行语句,则可使用pass语句作为占位符。
class Emp:
pass
大概类似c++的class emp{};
Python默认的成员函数和成员变量都是公开的,Python 私有属性和方法没有类似别的语言的public,private等关键词来修饰
由于python的动态性,它有一些类的特殊用法:
因此它的类所包含的类变量可以动态增加或删除一一程序在类体中为新变量赋值就是增加类变量,程序也可在任何地方为己有的类增加变量;程序可通过del 语句删除己有类的类变量。
类似的, Python 对象的实例变量也可以动态增加或删除一一只要对新实例变量赋值就是增加实例变量,因此程序可以在任何地方为己有的对象增加实例变量;程序可通过del 语句删除己有对象的实例变量。
在类中定义的方法默认是实例方法,定义实例方法的方法与定义函数的方法基本相同,只是实例方法的第一个参数会被绑定到方法的调用者(该类的实例)-一因此实例方法至少应该定义一个参数,该参数通常会被命名为self。
注意:实例方法的第一个参数并不一定要叫self,其实完全可以叫任意参数名,只是约定俗成地把该参数命名为self,这样具有最好的可读性。
构造方法
在实例方法中有一个特别的方法__init__ ,这个方法被称为构造方法。构造方法用于构造该类的对象, Python 通过调用构造方法返回该类的对象(无须使用new ) 。
【注意,在我的python2中写道init是初始化函数,new是真正的构造方法,大概了解了一下:
__new__是在实例创建之前被调用的,它的任务就是创建实例然后返回该实例对象,是个静态方法。
init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候。是一个实例方法。
一些差别:
1、继承自object的新式类才有__new
2、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别
3、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例
4、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
init 和 new 最主要的区别在于:
1.init 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
2.new 通常用于控制生成一个新实例的过程。它是类级别的方法。
】
使用对象
Person 类代码定义了一个构造方法,该构造方法只是方法名比较特殊: init ,该方法的第一个参数同样是self,被绑定到构造方法初始化的对象。与函数类似的是, Python 也允许为类定义说明文档, 该文档同样被放在类声明之后、类体之
前
在定义类之后,接下来即可使用该类了。Python 的类大致有如下作用。
1.定义变量。
2.创建对象。
3.派生子类
对象访问方法或变量的语法是: 对象.变量|方法(参数〉。
例子:
class Person:
hair = 'black'
def __init__ (self, name ="Charlie", age=8):
self.name=name
self.age= age
def say(self , content) :
print(content)
if __name__ == '__main__':
p = Person()
p.hair='nice'
print(p.name,str(p.age),p.hair)
p.name='何梓贻'
p.age='19'
print(p.name+p.age)
p.say('我爱代码')
结果:
Charlie 8 nice
何梓贻19
我爱代码
解释:
通过Person 对象调用了say()方法,在调用方法时必须为方法的形参赋值。但say ()方法的第一个形参self 是自动绑定的,它会被绑定到方法的调用者( p ),因此程序只需要为say()
方法传入一个字符串作为参数值,这个字符串将被传给content 参数。
为p 对象动态增加实例变量只要为它的新变量赋值即可【联想字典增加键值对直接用pp[key]=value】
上面的代码添加:
p = Person()
p.interse = '编程'
print(p.interse)
输出
编程
删除变量:
del p.interse
print(p.interse)
输出
File “C:\Users\14172\PycharmProjects\pythonProject3\main.py”, line
51, in < module>
print(p.interse) AttributeError: ‘Person’ object has no attribute ‘interse’
可见python增加实例变量非常方便,不需要再在类中定义变量。
Python也允许为对象动态增加方法。比如:
def nice(self):
print('我哦哦哦实时啦啦啦',self)
p = Person()
p.ber = nice
p.ber(p)
结果:
我哦哦哦实时啦啦啦 <main.Person object at 0x0000026E5BC10FD0>
Process finished with exit code 0
也可以使用lambda表达式:
p.bar = lambda self: print ('lambda表达式…',self)
p.bar(p)
输出:
lambda表达式… <main.Person object at 0x00000137DB220FD0>
注意:
Python 不会自动将调用者绑定到第一个参数
因此程序需要手动将调用者绑定到第一个参数
实例方法和self绑定
对于在类体中定义的实例方法, Python 会自动绑定方法的第一个参数(通常建议将该参数命名为self) ,第一个参数总是指向调用该方法的对象。根据第一个参数出现位置的不同,第一个参数所绑定的对象略有区别。
》在构造方法中引用该构造方法正在初始化的对象。
》在普通实例方法中引用调用该方法的对象。
由于实例方法(包括构造方法〉的第一个self 参数会自动绑定,因此程序在调用普通实例方法、构造方法时不需要为第一个参数传值。
假设定义了一个Dog 类,这个Dog 对象的run()方法需要调用它的jump()方法,此时就可通过self 参数作为jump()方法的调用者。
方法的第一个参数所代表的对象是不确定的,**但它的类型是确定的一一它所代表的只能是当前类的实例;**只有当这个方法被调用时,它所代表的对象才被确定下来谁在调用这个方法,方法的第一个参数就代表谁。
【可以联想c++中用到的this也是一个指针,指向自己】
例子:
class Person:
def myy(self):
print("this is myy")
def myy2(self):
print("this is mmyy2+",end=" ")
self.myy()
if __name__ == '__main__':
p = Person()
p.myy2()
输出:
this is mmyy2+ this is myy
Process finished with exit code 0
!!注意:当Python 对象的一个方法调用另一个方法时,不可以省略self。也就是说,将上面的self.myy()方法改为myy()是不正确的。
在构造方法中, self 参数(第一个参数)代表该构造方法正在初始化的对象 例子:
class InConstructor
def __init__(self):
foo = 0
self.foo = 6
#在构造方法中定义一个foo 变量(局部变量)
#使用self 代表该构造方法正在初始化的对象
#把该构造方法正在初始化的对象的foo 实例变量设为6 这意味着该构造方法运回的所有对象的foo实例变量都等于6
类习题
1、以下类定义中哪些是类属性,哪些是实例属性?
class C:
num = 0
def init(self):
self.x = 4
self.y = 5
C.count = 6
num = 0 C.count = 6是类属性 self.x = 4 self.y = 5是实例属性
2.怎么定义私有⽅法?
用双下划线___
如def __num():
3、尝试执行以下代码,并解释错误原因:
class C:
def myFun():
print(‘Hello!’)
c = C()
c.myFun()
--应该加上myFun(self) 这样函数才会认识调用的实例对象,因为对于在类体中定义的实例方法, Python 会自动绑定方法的第一个参数,而这个函数并没有self参数
4、按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。
要求:
平日票价100元
周末票价为平日的120%
儿童票半价
class Ticket():
# your code here
normal = 100
weekend = 120
child = 50
def total(self,n,m,z):
print('一共价格',end="")
print(int(self.normal*n)+int(self.child*m)+int(self.weekend*z))
if __name__ == '__main__':
a1 = Ticket()
a1.total(2,1,0)
结果:
一共价格250
Process finished with exit code 0
魔法方法
python中一个特别的内容,需要深入掌握。
魔法方法总是被双下划线包围,例如__init__
- 基本的魔法方法
init(self[, …]) 构造器,当一个实例被创建的时候调用的初始化方法
2.析构方法: del
与init ()方法对应的是__del__()方法’init()方法用于初始化Python 对象,而__del__()则用于销毁Python 对象在任何Python 对象将要被系统回收之时,系统都会自动调用该对象的_del_()方法。
当程序不再需要一个Python 对象时,系统必须把该对象所占用的内存空间释放出来,这个过程被称为垃圾回收Python 会自动回收所有对象所占用的内存空间,因此开发者无须关心对象垃圾回收的过程。
3.dir
对象的dir ()方法用于列出该对象内部的所有属性(包括方法)名,该方法将会返回包含所有属性(方法)名的序列。
当程序对某个对象执行di r(object) 函数时,实际上就是将该对象的__dir__()方法返回值进行排序,然后包装成列表。
4.__diet__属性用于查看对象内部存储的所有属性名和属性值组成的字典, 通常程序直接使用该属性即可。程序使用__diet__属性既可查看对象的所有内部状态, 也可通过字典语法来访问或修改指定属性的值
5.如果开发者需要实现迭代器,只要实现如下两个方法即可。
iter(self) : 该方法返回一个法代器( iterator ),迭代器必须包含一个next () 方法,该方法返回迭代器的下一个元素。
reversed (self) : 该方法主要为内建的reversed()反转函数提供支持,当程序调用reversed()函数对指定迭代器执行反转时,实际上是由该方法实现的
如果程序不需要让迭代器反转迭代,其实只需要实现第一个方法即可。
魔法方法习题
1、上面提到了许多魔法方法,如__new__,init, str,rstr,getitem,__setitem__等等,请总结它们各自的使用方法。
new init str上面已有总结,
getitem (self, key):该方法获取指定索引对应的元素。该方法的key 应该是整数值或slice对象,否则该方法会引发KeyError 异常。
setitem (self, key, value) : 该方法设置指定索引对应的元素。该方法的key 应该是整数
值或slice 对象,否则该方法会引发KeyError 异常。
rstr:随机生成字符串
import rstr
print(rstr.rstr(‘nice’))
iccicprint(rstr.rstr(‘nice’))
eeeeiiprint(rstr.rstr(‘nice’,5))
icenc
可见每次输出的结果都不一样,可以有第二个参数来指定输出的字符个数
2、利用python做一个简单的定时器类
要求:
定制一个计时器的类。
start和stop方法代表启动计时和停止计时。
假设计时器对象t1,print(t1)和直接调用t1均显示结果。
当计时器未启动或已经停止计时时,调用stop方法会给予温馨的提示。
两个计时器对象可以进行相加:t1+t2。
只能使用提供的有限资源完成。
python的time模块不太了解,混乱地写了一下:
class timee:
judge = False
def start(self):
self.judge = True
deftime = time.time()
return deftime
def end(self):
if self.judge == False:
print('还未开始计时!')
return
else:
endtime = time.time()
return endtime
def now(self):
print('现在时间' + str(time.localtime()))
print(time.time())
time.sleep(5)
print(time.time())
if __name__ == '__main__':
t1 = timee()
t1.end()
t1.start()
t1.end()
t1.now()
t2 = timee()
print("")
t2.start()
print(t2.end()+t1.end())
结果: