python的面向对象编程
类class
标签: Python
#类:类名、属性、方法
类名:狗类
属性:毛发,品种
方法:咬人,看家
定义方法
class Hero(): 经典类定义方法(旧式类,Python2中)
class Hero(object): 新式类定义方法(常用类,Python3中)
object是Python里面所有类的最顶级父类
eg.
class Hero(object):
#实例方法
def info(self):
print("6666")
#创建实例化对象
a=Hero()
#调用对象所属类中的方法
a.info()
其中info是一个实例方法,第一个参数一般是self,表示实例对象本身,其作用是一个变量,指向实例对象
#类的属性添加
1.最常见的添加属性的方法 __init__(self,······)
对象初始化方法(java中的构造方法)
Python里面提供的 两个下划线开始两个下划线结束的方法就是魔法方法,__init__
就是一个魔法方法,如果没写__init__
方法,Python会自动创建,但是不会执行任何操作,所以类里面无论是否编写__init__
方法,也一定会有__init__
class Person(object):
# Python给对象添加属性
#最常见的添加属性的方法 __init__(self,······)对象初始化方法
def __init__(self,name,age):
print("对象创建调用这个方法")
#self.属性 就是对象属性
self.name = name
self.age = age
one = Person("张三",18)
#访问one对象的属性
print(one.name)
print(one.age)
2.实例化后的对象.要添加的属性 表示对象属性
但是该方法可以无限制添加对象,为了规范定义对象的属性,我们尽量不使用该方法
class Person(object):
pass
one = Person()
#实例化后的对象.要添加的属性 表示对象属性
one.name = "本杰明"
one.age = 18
print("%s今年%d"%(one.name,one.age))
#查看对象属性
当类中含有__str__
魔法方法的时候,打印对象会输出此魔法方法中的返回值,调用此方法时需要用一个变量接受
在类中使用时
def __str__(self):
return "%s今年%d"%(one.name,one.age)
在类外调用时
word = one.__str__()
print(word)
例如
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
#如果我们不带__str__方法会输出对象的内存地址
#带__str__方法我们可以定义打印对象返回的数据
def __str__(self):
return "{name}今年{age}岁".format(name=self.name,age=self.age)
zhangsan = Person("张三",18)
print(zhangsan)
#del() 方法删除对象
#引用计数法(类似于java的gc线程回收时回收对象的计数法)
class Hero(object):
def __init__(self,name):
print("__init__()方法被调用")
self.name = name
def __del__(self):
print("__del__()方法被执行")
a = Hero(“大司马”)
b = a
c = b
建立了一个对象,默认保存在计算机内存中,一旦该对象不被使用(没有变量名引用该对象时),系统将要收回内存资源,对象会自动执行销毁机制__del__()魔法方法
例如,上述的 Hero(“大司马”) 该对象被a、b、c这三个变量名引用了三次,需要将这三个引用删除(del(a) del(b) del©),才能实行销毁机制__del__()
del 销毁创建的变量和变量所对应的数据指数
一旦内存引用为0的时候,解释器会回收当前资源
这种销毁机制叫引用计数法
引用计数法:
1.当有变量保存了一个对象的引用时(内存地址),此对象的引用计数+1
2.当使用 del()方法 或者 del关键字 删除变量指向的对象时,会减小对象的引用计数(如果对象的引用计数不为1,那么该对象的引用计数-1;当对象的引用计数为0时,对象就会被真正删除,内存回收)
#对象方法
所有的对象共用同一个类中定义的实例方法
class Person(object):
# Python给对象添加属性
#最常见的添加属性的方法 __init__(self,······)对象初始化方法
def __init__(self,name,age):
print("对象创建调用这个方法")
#self.属性 就是对象属性
self.name = name
self.age = age
#实例化方法
def run(self):
print("人类快跑")
def eat(self):
print("人类快吃")
def show_name(self):
#通过self访问实例化本身
print("我叫%s"%self.name)
one = Person("张三",18)
#访问one对象的方法
one.run()
one.eat()
one.show_name()
#注意
在类的内部获取 属性 和 实例方法 通过self获取
在类的外部获取 属性 和 实例方法 通过对象名获取
如果一个类有多个对象,每个对象的属性是各自保存的,都有各自独立地址
但是实例方法是所有对象共享的,只占用一份内存空间,类会通过self来判断是哪个对象调用了实例方法
class Person(object):
def __init__(self,name,age,height):
self.name = name
self.age = age
self.height = height
def run(self):
print("%s在跑"%self.name)
def show_age(self):
print("%d岁"%self.age)
def show_height(self):
print("%dcm"%self.height)
one = Person("本杰明",18,180)
two = Person("张三",20,175)
print(one.name,id(one.run))
print(two.name,id(two.run))
print(id(one))
print(id(two))
#练习(烤地瓜)
class BakedSweetPotato(object):
def __init__(self,cookedLevel,cookedString,condiments):
self.cookedLevel = cookedLevel
self.cookedString = cookedString
self.condiments = condiments
def cook(self):
print("把地瓜烤一段时间")
self.cookedLevel+=1
if 0<=self.cookedLevel<=3:
self.cookedString="生的"
elif 3<self.cookedLevel<=5:
self.cookedString="半生不熟"
elif 5<self.cookedLevel<=8:
self.cookedString="熟了"
elif self.cookedLevel>8:
self.cookedString="烤成碳了"
def addCondiments(self):
print("给地瓜添加配料")
if self.condiments:
pass
else:
print("没有添加佐料")
zuoliao = input("请添加佐料")
self.condiments.append(zuoliao.split(","))
def __str__(self):
return "地瓜的烤熟程度为{cookedLevel},{cookedString},添加的佐料有{condiments}".format(cookedLevel=self.cookedLevel,cookedString=self.cookedString,condiments=self.condiments)
one = BakedSweetPotato(0,"生的",[])
print(one)
one.cook()
print(one)
one.addCondiments()
print(one)
#类的继承
eg
Dog: 名字 品种 吃 喝 拉 撒
哈士奇Dog:名字 品种 吃 喝 拉 撒 拆家
金毛Dog:名字 品种 吃 喝 拉 撒 卖萌
程序中的继承:描述的是多个类之间的所属关系
如果一个类A里面的属性和方法可以重复使用,那么可以通过继承的方式传递给B类
例如
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self):
print("%s在吃狗粮"%self.name)
def drink(self):
print("%s在喝水"%self.name)
class HaDog(Dog):
def chai(self):
print("%s在拆家"%self.name)
one = HaDog("小天圈")
one.eat()
one.chai()
其中Dog是父类也是基类 HaDog是子类也是衍生类
#单继承
一个类只能继承一个父类
如上HaDog
#多继承
一个子类可以继承多个父类
如果想要将HaDog变为多继承
例如
class Dog(object):
pass
class JunDog(object):
pass
class HaDog(Dog,JunDog):
pass
注意HaDog(Dog,JunDog)中,哪个父类在前,同方法使用第一个父类
前一个继承的类一定要小于后边的类,前面的不能是后面的父级类
即当多个父类中含有同一个方法,使用mro的继承顺序使用第一个继承的父类方法(mro继承顺序:子类继承多个父类的前后顺序,谁在前继承谁)
使用 类名._mro_ 例如:print(HaDog.__mro__) 即可该类的查看mro顺序
遇到继承推算时,使用C3算法,即入度为0的方法推算,即没有指向的类时可以去掉(入度为0,从上到下)
#——————————————
#重写
#——————————————
在子类中重写父类的方法
例如
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self):
print("%s在吃狗粮"%self.name)
def drink(self):
print("%s在喝水"%self.name)
class JunDog(object):
def zhuaren(self):
print("%s会抓人"%self.name)
class HaDog(JunDog):
def zhuaren(self):
print("%s只会拆家"%self.name)
#重写后,怎么调用父类的同名属性和方法
父类名.方法或属性
使用父类的方法时,方法中要传递实例化对象即self
class Master(object):
def init(self):
self.kongfu = “天津”
def make_cake(self):
print(“使用%s手法煎饼”%self.kongfu)
def make_ice(self):
print(“天津冰淇淋”)
class Prentice(Master):
def __init__(self):
self.kongfu = "山东"
def make_cake(self):
print("使用%s手法煎饼" % self.kongfu)
#怎么调用父类的同名属性和方法
#父类名.方法或属性
#使用父类的方法时,方法中要传递实例化对象即self
Master.__init__(self)
print("使用%s手法煎饼" % self.kongfu)
def make_ice(self):
print("山东冰淇淋" )
Master.make_ice(self)
zq = Prentice()
print(zq.kongfu)
zq.make_cake()
zq.make_ice()
#super().父类的属性和方法
super([类名,self]).父类的属性和方法
其中类名默认为当前子类,中括号中可选择自己指定的类,按当前子类的继承顺序,继承该指定类的下一级类
class Master(object):
def __init__(self):
self.kongfu = "天津"
def make_cake(self):
print("使用%s手法煎饼"%self.kongfu)
class WhTedu(object):
def __init__(self):
self.kongfu = "武汉"
def make_cake(self):
print("使用%s手法煎饼"%self.kongfu)
class Prentice(Master,WhTedu):
def __init__(self):
self.kongfu = "山东"
def make_cake(self):
print("使用%s手法煎饼" % self.kongfu)
#怎么调用父类的同名属性和方法
#父类名.方法或属性
#使用父类的方法时,方法中要传递实例化对象即self
super().__init__()
print("使用%s手法煎饼" % self.kongfu)
super(Master,self).__init__()
print("使用%s手法煎饼" % self.kongfu)
zq = Prentice()
print(zq.kongfu)
zq.make_cake()
如果继承了多个父类,且父类都含有 同名 属性或者方法,使用super方法,默认执行第一个父类的同名属性或者方法
super()方法只支持新式类,Python2.3之后才有的多层继承和super()方法
调用时遵循类的继承顺序(mro顺序)
#私有权限
在 属性名 或者 方法名 的 前面 加上两个下划线
python是一个弱语言 没有绝对的访问权限,必须遵守Python的定义
私有属性的原则,Python没有访问控制符(public)
“”"
1.类的私有属性和私有方法,都不能通过对象直接访问,但是可以通过本类的内部进行访问
2.类的私有属性和私有方法,都不能被子类继承,也不能被子类访问
3.类的私有属性和私有方法,往往用来处理类的内部事情,不能通过对象处理起到安全作用
“”"
如果属性名和方法名前面没有两个下划线的话是 公有权限(不太准确 )
python中没有绝对的公有访问和私有访问
“”"
1.当使用 import 模块名 可以使用所有属性和方法,无公有私有说法
2.当使用 form 模块名 import 方法或属性 时,有公有和私有,且有特殊情况(一个下划线即可表示私有),所以定义私有属性时,必须遵循业界规范使用二个下划线
“”"
class yxt(object):
def __init__(self):
self.__money = 10000
self.kongfu = "啥都6"
def jie_money(self):
print("爸爸向儿子借了%d" %self.__money)
def __play(self):
print("全英雄全能6的飞起")
class zq(yxt):
pass
hh = zq()
hh.jie_money()
_dict_ 魔法方法:
1.类属性调用此魔法方法时,返回当前类所含有的所有类属性和方法
2.实例化对象调用此魔法方法时,返回此对象具有的所有属性
通过该方法我们可以发现Python中私有属性的秘密
私有属性被修改了名字,外部访问时格式为 _类名__私有属性名
例如
class A(object):
name = "A类"
__data = "2019"
def __init__(self):
self.age = 18
self.__money = 1000
print(A.__dict__)
print (A._A__data)
a = A()
print(a.__dict__)
print(a._A__money)
所以访问私有属性的方法可以为在该私有属性前面加上 _类名
即以 _类名__属性名 该格式访问私有属性
因此,Python中的私有属性是假的私有(伪私有属性):Python的类通过加双下划线来设置“私有属性”,原理是Python解释器将加了双下划线的“属性名”自动转换成“_类名__私有属性名”,所以外部访问该属性时获取不到,会触发AttributeError,从而实现Python的私有属性
(访问私有方法相同)
#怎么修改对象的属性和方法
“”"
1.外部对象名.属性名 = 新的数据 (直接修改)
2.内部self.属性名 = 新的数据 (直接修改)
3.对象名或者self.方法名 此方法名必须公有(间接修改)
“”"
class Master(object):
def __init__(self):
self.__money = 10000
self.kongfu = "啥都6"
#业界规范:通常定义get_xxx()方法和set_xxx()方法来获取和修改私有属性,其中xxx指私有属性
def get_money(self):
print(self.__money)
def set_money(self,count):
self.__money += count
ds = Master()
ds.get_money()
ds.set_money(10000)
ds.get_money()
#类属性和实例属性
“”"
1.实例属性:对象属性,一般定义在__init__() 方法里
不能被类对象调用,能被实例化对象调用
2.类属性
类属性就是类对象都拥有的属性,它被所有类对象和实例对象共有。
类对象:实例化对象 类本身也是对象
直接在类中创建,不能在方法中创建
可以被类对象和实例化对象使用
“”"
class People(object):
# 在类里面直接定义
name = "于谦"
def __init__(self):
self.age = 18
# 局部变量
height = 100
p = People()
# p实例化对象
print(p.name)
print(People.name)
print(p.age)
# print(p.height)
# print(People.age)
# print(People.height)
class A(object):
pass
print(type(A))
print(id(A))
#额外知识
type类是元类,所有类的父类 ==》object
python中的元类实例化所有创建出来的类
#类方法是类对象拥有的方法,需要使用装饰器@classmethod 来标识其为类方法,
对于类方法,第一个参数必须是类对象,一般为 cls 作为第一个参数,能通过类对象和实例化对象来调用
类方法的作用:用来访问和修改定义的类属性
class People(object):
__country = "China"
#类方法通过classmethod
def __init__(self):
name = "yxt"
@classmethod
def get_country(cls):
#cls同self一样
# print(id(cls))
# print(cls.__country)
return cls.__country
@classmethod
def set_country(cls,country):
cls.__country = country
def set_name(self,name):
self.name = name
print(id(People))
People.get_country()
a = People()
country = a.get_country()
a.set_country("usa")
print(a.get_country())
a.set_name("zq")
print(a.name)
b = People()
print(b.get_country())
#Python是一门弱语言,面向对象,面向过程
“”"
1.没有访问控制符
2.没有常量 Python中的常量的定义方法:通过把变量名全部大写来定义(可以被修改,规定不要修改)
3.定义变量不需要指定数据类型
4.面向对象没有多态说法
5.没有绝对私有
“”"
#Python中没有静态方法,对于Python中的类假写了一个静态方法
需要通过装饰器 @staticmethod 来修饰,静态方法不需要定义参数,可以通过类对象和实例化对象来访问
作用:为了符合高级语言特意定义的,无实际意义
可以不需要实例化对象直接通过类对象使用
静态方法如果使用类属性和对象属性
使用类属性:类名.属性(不用来访问私有属性)
使用对象属性:需要通过传参(参数为实例化对象),来间接访问
class People(object):
name = "剑豪"
__job = "中单"
def __init__(self):
self.age = "18"
@staticmethod
def show():
print(People.name)
print(People.__job)
@staticmethod
def show_age(obj):
print(obj.age)
#绝对不要用下面这个静态方法,因为该方法是我们先创建了一个实例化对象后才写的
#所有语言中 类的方法的功能必须在实例化对象之前定义完成
@staticmethod
def show_age1():
print(a.age)
People.show()
a = People()
print(a.age)
a.show()
a.show_age(a)
a.show_age1()
#所有高级语言都具有的特点:面向对象
#面向对象的三大特征:封装、继承、多态
#封装的意义:
“”"
1.将属性和方法放到一起作为一个整体(类),然后通过实例对象来处理
2.隐藏内部的实现细节(通过加添私有属性),只需要对象及其属性和方法在内部交互(使方法在类的内部启动,即实例化对象时就自动执行)
3.对于类的属性和方法需要增加访问控制
“”"
#多态
所谓多态就是定义时的类型和运行时的类型不一样,此时为多态,即同一个事物的不同表现形态
多态的概念经常用于强语言类型(Java/C#)
多态的触发条件
“”"
1.继承关系
2.重写
3.父类引用指向子类对象(向上造型)
“”"
#在Python中弱化了多态,无真正的多态,因为Python是一门弱语言,没有指向类型即不需要指定数据类型(int,char,类名等),无法向上造型
class Animal(object):
def eat(self):
print("动物吃")
class cat(Animal):
def eat(self):
print("猫吃鱼")
class Dog(Animal):
def eat(self):
print("狗吃屎")
class Pig(object):
def eat(self):
print("猪吃糠")
#在Python中使用多态
def show_eat(obj):
obj.eat()
show_eat(Dog())
#在Java中下面无法实现,因为Pig不属于Animal
show_eat(Pig())