例题引导:使用魔法方法__new__构造一个摄氏度转换为华氏度的类:
解题思路:构建类-调用魔法方法-表达函数功能
参考答案:
class C2F(float):
def __new__(cls,arg = 0.0):
return float.__new__(cls,arg * 1.8 + 32)
学习引导:
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:
class Parent: #定义父类
def myMethod(self):
print('调用父类方法')
class Child(Parent): #定义子类
def myMethod(self):
print('调用子类方法')
c=Child() #子类实例
c.myMethod() #子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
#super()是用于调用父类(超类)的一个方法。
#调用子类方法
#调用父类方法
在python中,有一些内置好的特定的方法,这些方法在进行特定的操作时会自动被调用,称之为魔法方法,下面介绍几种常见的魔法方法。
class myMethod(str):
def __new__(cls,string):
string=string.upper()
return str.__new__(cls,string)
X=myMethod('DataScience')
print(X)
#DATASCIENCE
初始化函数,在创建实例对象为其赋值时使用,在__ new__ 之后,__ init __ 必须至少有一个参数self,就是这个 __ new__ 返回的实例,__ init__ 是在 __ new__ 的基础上可以完成一些其它初始化的动作,__ init__不需要返回值。
class Dog:
def __init__(self,color,brand):
self.color=color
self.brand=brand
puppy=Dog('黑色','拉布拉多')
print(puppy)
#<__main__.Dog object at 0x0000028EC0609DC8>
下面再来一个结合__ init__ 和__ new__两个魔法方法的例子:
class A(object):
pass
class B(A):
def __init__(self):
print('__init__被调用')
def __new__(cls):
print('__new__被调用')
print(id(cls))
return object.__new__(A)
#注意此处采用了参数A而不是cls,__new__没有正确返回当前类cls的实例
b=B()
print(b)
print(type(b)) #类型所继承的基类
print(id(A))
print(id(B))
'''
__new__被调用
2812126085768
<__main__.A object at 0x0000028EC0574108>
<class '__main__.A'>
2812126083880
2812126085768
'''
从运行结果可以看出,__ new__ 中的参数cls和B的id是相同的,表明__ new__ 中默认的参数cls就是B类本身,而在return时,并没有正确返回当前类cls的实例,而是返回了其父类A的实例,因此__ init__ 这一魔法方法并没有被调用,此时__ new__虽然是写在B类中的,但其创建并返回的是一个A类的实例对象。
现在将return中的参数A变为cls,再来看一下运行结果:
class A(object):
pass
class B(A):
def __init__(self):
print('__init__被调用')
def __new__(cls):
print('__new__被调用')
print(id(cls))
return object.__new__(cls)
#注意此处采用了参数A而不是cls,__new__没有正确返回当前类cls的实例
b=B()
print(b)
print(type(b)) #类型所继承的基类
print(id(A))
print(id(B))
'''
__new__被调用
2812126087656
__init__被调用
<__main__.B object at 0x0000028EC057C148>
<class '__main__.B'>
2812126086712
2812126087656
'''
可以看出,当__ new__ 正确返回其当前类cls的实例对象时,__ init__被调用了,此时创建并返回的是一个B类的实例对象。
获得已知对象的类 ( 对象.__ class__)。
基础格式如下:
class My:
pass
a=A()
print(a.__class__)
#<class '__main__.A'>
__ class__在下面这种情况中是有用的:即当一个类中的某个成员变量是所有该类的对象的公共变量时.
下面看一个例子:
class My:
count=0
def addcount(self):
self.__class__.count +=1
a=My()
a.addcount()
print(a.count)
print('*'*50)
b=My()
b.addcount()
print(b.count)
#1
#**************************************************
#2
从运行结果可以看出,虽然a和b是两个不同的My类的实例对象,但采用了__ class__ 之后,分别调用两个对象的addcount方法之后,获取到的对象的count属性却是在不断累加的,此时self.__ class__ .count不再是单纯的某个对象私有的属性,而是类的所有实例对象的共有属性,它相当于self.A.count。若将self.__ class__ .count += 1变为self.count += 1,此时__ class__的效果就十分明显了。
class My:
count=0
def addcount(self):
self.count +=1
a=My()
a.addcount()
print(a.count)
print('*'*50)
b=My()
b.addcount()
print(b.count)
#1
#**************************************************
#1
在将对象转换成字符串 str(对象) 测试的时候,打印对象的信息,__ str__ 方法必须要return一个字符串类型的返回值,作为对实例对象的字符串描述,__ str__ 实际上是被print函数默认调用的,当要print(实例对象)时,默认调用__ str__ 方法,将其字符串描述返回。如果不是要用str()函数转换。当你打印一个类的时候,那么print首先调用的就是类里面的定义的__ str__。
class My():
def __init__(self,name):
self.name=name
def __str__(self):
return('我是My类的实例对象my,我的名字叫%s'%self.name)
my=My('小王')
print(My)
print(my)
#<class '__main__.My'>
#我是My类的实例对象my,我的名字叫小王