类的定义
类名需要用’大驼峰命名法‘,即每个单词的首字母大写
class TestClass:
pass
类的使用
实例化对象
定义好类之后,将类实例化为一个对象
class Car:
name = 'Car' #定义实例属性name,表示所有实例对象共有的属性
bmw = Car() #实例化一个Car的对象
print(bmw.name)
#运行结果:
Car
私有属性
在python中有两种私有属性,分别是在属性前加一个下划线和两个下划线,一个下划线外部可以直接访问,二个下划线外部不可以直接访问
class Car:
_one = 'One'
__two = 'Two'
aodi = Car()
print(aodi._one)
#运行结果:
One
由于第二种私有属性不能直接访问,可以先通过 dir(Car) 用来查看Car类中的所有可用方法,然后就可以通过提示调用第二种私有属性
print(aodi._Car__two)
#运行结果:
Two
类方法
“方法”就是封装在类里的一种特殊的函数,可以通过实例化对象调用类方法,它表示该类所有实例所共有的行为
class Car:
def run(self):
print('%s在跑'%self.name)
#self表示实例对象本身,谁调用谁就是self
bmw = Car() #实例化一个Car对象
bmw.name='千里马' #给方法内的参数赋值,写在方法调用之前
bmw.run() #通过实例化对象调用run方法
#运行结果:
千里马在跑
魔法方法
__init__
初始化
在Python中有很多以双下划线开头且以双下划线结尾的固定方法,他们会在特定的时机被触发执行,init_ 就是其中之一,它会在实例化之后自动被调用。以完成实例的初始化。
class Car:
def __init__(self,name,catch): #初始化方法,传入两个实例的参数
self.name = name #实例的name指向传入的参数name
self.catch = catch
def buy(self):
print('%s的价格是%d¥'%(self.name,self.catch))
aodi = Car('奥迪',200000)
aodi.buy()
#运行结果
奥迪的价格是200000¥
__del__
析构
在实例化对象的引用结束时,会自动调用已有的析构函数。
class Buy:
def __init__(self):
print('初始化程序')
def __del__(self): #使用析构函数,在实例化对象引用数为0时,他才执行
print('销毁完成')
mai = Buy()
print('运行完成')
#运行结果
初始化程序
运行完成
销毁完成
再谈析构,当使用del 删除对象时,会调用他本身的析构函数,提示开发者,对象被销毁了,方便调试。进行一些必要的清理工作
mai = Buy()
del mai #提前销毁实例化对象
print('运行完成')
#运行结果
初始化程序
销毁完成
运行完成
__str__
和__repr__
这里的str和repr都是底层魔法方法被拿出来调用,使实例直接被打印时也会有返回值,%s调用的是str方法,更适合用户,%r调用的是repr方法,更适合开发者
class Rectangle:
def __init__(self,length,width):
self.length = length
self.width = width
def area(self):
areas = self.length * self.width
return areas
def __str__(self): #str会运行在repr之前,运行了str就不会再运行repr
return 'length is %s, width is %s '%(self.length, self.width)
def __repr__(self):
return 'area is %s'%self.area()
a = Rectangle(12,13)
print(a)
#运行结果:
length is 12, width is 13
两者的区别:浅谈python中__str__和__repr__的区别
如果两者都在类中,优先str方法
__call__
方法
正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 call 方法
class Rectangle:
def __init__(self,length,width):
self.length = length
self.width = width
def __call__(self, *args, **kwargs):
return '调用了__call__方法'
a = Rectangle(12,13)
print(a())
#运行结果:
调用了__call__方法
__new__
方法
友情链接:https://www.jianshu.com/p/08d7956601de
最先被调用的方法,返回父类的new方法后,程序才会向下执行,new方法会在init方法之前执行
class Rectangle:
def __init__(self):
print('This is __init__')
def __new__(cls, *args, **kwargs):
print('This is __new__')
return super().__new__(cls)
a = Rectangle()
#运行结果:
This is __new__
This is __init__
单例模式
使用new方法可以写成单例模式,即每次实例化只生成一个内存地址
class Earth:
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'instance'): #判断里面有没有instance属性
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self,name):
self.name = name
print(self.name)
a = Earth('test')
b = Earth('abcd')
#运行结果:
test
abcd
描述符
描述符,如果一个类中有__get__, set, 和__delete__这些方法中的任何一个,被定义在一个对象中,这个对象就是一个描述符,描述符的作用是,会在实例进行相关操作的时候进行响应
class JiChu:
def __get__(self, instance, owner):
print('Create an body')
def __set__(self, instance, value):
print('Gets %d EXP, Levels Up!'%value)
def __delete__(self, instance):
print('Game Over!')
class Player:
j = JiChu()
def name(self):
print('Grue')
a=Player()
a.j #在实例调用类属性时,会触发__get__方法
a.j = 1 #在实例更改类属性时,会触发__set__方法
del a.j #在实例删除类属性时,会触发__delete__方法
#运行结果:
Create an body
Gets 1 EXP, Levels Up!
Game Over!
运算方法
__add__
方法 使两个实例之间进行加法运算
class Rectangle:
def __init__(self,length,width):
self.length = length
self.width = width
def __add__(self, other): #other 用于接收另一个实例
add_length = self.length + other.length
add_width = self.width + other.width
return add_length,add_width
a = Rectangle(3, 4)
b = Rectangle(5, 6)
print(a + b)
#运行结果:
(8, 10)
除此之外还有以下方法,其它运算的使用方法都是大同小异
运算符方法
__add__(self,other) # x+y
__sub__(self,other) # x-y
__mul__(self,other) # x*y
__mod__(self,other) # x%y
__iadd__(self,other) # x+=y
__isub__(self,other) # x-=y
__radd__(self,other) # y+x
__rsub__(self,other) # y-x
__imul__(self,other) # x*=y
__imod__(self,other) # x%=y
其他方法
这些方法主要用于查询相关信息
[外链图片转存失败(img-BLKa28gq-1564409417999)(E:\Fire\笔记\assets\1548256554171.png)]
1、__class__
查看类名
格式: obj.__class__
2、__dict__
查看全部属性,返回属性和属性值键值对形式
格式:obj.__dict__
3、__doc__
查看对象文档,即类中(用三个引号引起来的部分)
格式:cls.__dict__
4、__bases__
查看父类
格式:cls.__base__
5、__mro__
查看多继承的情况下,子类调用父类方法时,搜索顺序
格式:subcls.__mro__
和obj.__class__.__mro__
定制属性访问
查
hasattr()有无指定值
查询有无指定值,返回bool类型
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
print(hasattr(a, 'name'))
#运行结果:
True
getattr()查询属性
查询指定实例属性,返回属性值
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
print(getattr(a, 'name'))
#运行结果:
zhanghao
a . __getattribute__('length')
# 返回属性值,效果同上
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
print(a.__getattribute__('name'))
#运行结果:
zhanghao
改&增
setattr()有则改,无则增
更改指定的属性,有则改,无则增
class Rectangle:
def __init__(self,name,age):
self.name = name
self.age = age
a = Rectangle('zhanghao')
setattr(a,'name','test')
setattr(a,'age',17)
print(a.name, a.age)
#运行结果:
test 17
a .__setattr__('length', 5)
#效果同上
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
a.__setattr__('name', 'test')
a.__setattr__('age', '17')
print(a.name, a.age)
#运行结果:
test 17
删
delattr()指定删除
删掉某个实例属性
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
delattr(a,'name')
print(a.name)
#运行结果:
AttributeError: 'Rectangle' object has no attribute 'name'
a .__delattr__('bbb')
#效果同上
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
a .__delattr__('name')
print(a.name)
#运行结果:
AttributeError: 'Rectangle' object has no attribute 'name'
del 删除实例
class Rectangle:
def __init__(self,name):
self.name = name
a = Rectangle('zhanghao')
del a
print(a.name)
#运行结果:
NameError: name 'a' is not defined
继承
定义一个子类可以使用父类的全部属性及方法,这种方式叫做继承
class Father: #父类
def cool(self):
print('cool')
class Son(Father): #子类
def eat(self):
print('eating')
s = Son()
s.eat()
s.cool()
#运行结果
eating
cool
多继承
一个子类可以继承多个父类,在调用方法或属性时,优先调用括号内左边父类的方法,左先右后
class Father:
def cook(self):
print('good cook')
class Mother:
def cook(self):
print('nice cook')
class Son(Father, Mother):
def eat(self):
print('eating')
s = Son()
s.eat()
s.cook()
#运行结果
eating
good cook
重写
如果不想使用父类中的方法可以在子类中进行重写
class Mother:
def cook(self):
print('nice cook')
class Son(Mother):
def cook(self): #重写父类的cook方法
print('eating')
s = Son()
s.cook()
#运行结果
eating
super用法
如果重写之后还想用父类的方法,就可以用上super()
class Mother:
def cook(self):
print('nice cook')
class Son(Mother):
def cook(self):
super().cook()
print('eating')
s = Son()
s.cook()
#运行结果:
nice cook
eating
装饰器
装饰器可以在不改变原有的函数基础上,给函数增加新功能,写代码遵循开发封闭原则,已实现功能的代码内部不能修改,但外部可以扩展,因此就用到了装饰器
def fn(fun): #回调,函数名作为参数
print('正在验证')
fun() #调用作为参数的函数
print('通过')
return fun #闭包,嵌套函数,外层函数返回里层函数名
@fn # ===> fn1 = fn(fn1),fn1(被装饰函数的名字)被当作参数传入了fn,函数fn执行完成后会把值给到fn1,因此fn1能够直接调用
def fn1():
print('身份为f1')
fn1()
#运行结果:
正在验证
身份为f1
通过
内置装饰器
@property
将方法变为属性,可以像访问属性一样访问它,即不用加括号就可以使用类方法
class Rectangle:
def __init__(self,length,width):
self.length = length
self.width = width
@property
def area(self):
return '矩形的面积为:%s' % (self.length * self.width)
a = Rectangle (10, 23)
print(a.area)
#运行结果:
矩形的面积为:230
@staticmethod
静态方法和class类断开联系, 不接收实例属性,在调用self的时候会报错
class Rectangle:
@staticmethod #变为静态方法
def fun2():
print('这是静态方法')
a = Rectangle()
a.fun2()
#运行结果:
这是静态方法
@classmethod
通常情况下一般的了方法调用时如果不加实例名,是不能访问类方法或类属性的,装饰类方法就可以解决这类问题
class Rectangle:
a = 10
b = 20
def __init__(self,length,width):
self.length = length
self.width = width
def area(self):
return '矩形的面积为:%s' % (self.length * self.width)
@classmethod # 类方法,可以访问类属性,类方法
def test(cls):
print(cls(cls.a,cls.b).area())
a = Rectangle (10, 23)
a.test()
#运行结果:
矩形的面积为:200
类装饰器
类也可以做装饰器,但是需要定义 call 方法,即将类变为一个可调用的方法
class TestClass:
def __init__(self, func):
self.func = func
def __call__(self):
print('类')
return self.func
@TestClass
def fun_test():
print('这是个测试函数')
fun_test()
#运行结果:
类
常见问题:
- 如果要在父类中使用之类的方法,那么导入包的语句不能写在父类之外, 如下:
# father.py
class Father:
def __init__(self):
pass
def run(self):
# 不能在父类之外导入,否则会报ImportError
from .son import Son
son = Son()
son.run()
# son.py
from .father import Father
class Son(Father):
def __init__(self):
super().__init__()
def run():
print("爸爸去哪儿")