[python基础] Part_4 类

类的定义

类名需要用’大驼峰命名法‘,即每个单词的首字母大写

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()
#运行结果:

常见问题:

  1. 如果要在父类中使用之类的方法,那么导入包的语句不能写在父类之外, 如下:
# 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("爸爸去哪儿")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值