Python-面向对象
程序员文章站
2022-07-10 08:22:31
...
一.定义简单的类
1.定义简单的类
- 方法定义格式和函数几乎一样
- 区别在于第一个参数必须是self
class 类名:
def 方法1(self,参数列表)
pass
def 方法2(self,参数列表)
pass
- 类名要符合大驼峰命名法
2.创建对象
对象变量 = 类名()
class Cat:
def eat(self):
print("小猫要吃鱼")
def drink(self):
print("小猫要喝水")
tom = Cat()
tom.eat()
tom.drink()
/*
小猫要吃鱼
小猫要喝水
*/
注意:在面向对象开发中,引用概念是同样适用的
class Cat:
def eat(self):
print("小猫要吃鱼")
def drink(self):
print("小猫要喝水")
tom = Cat()
tom.eat()
tom.drink()
print(tom)
num = id(tom)
print("%x" %num)
/*
小猫要吃鱼
小猫要喝水
<__main__.Cat object at 0x0000008C41F6F2B0>
8c41f6f2b0
*/
class Cat:
def eat(self):
print("小猫要吃鱼")
def drink(self):
print("小猫要喝水")
tom = Cat()
print(tom)
num1 = id(tom)
print("%x" %num1)
jim = Cat()
print(jim)
num2 = id(jim)
print("%x" %num2)
jery = tom
print(jery)
num3 = id(jery)
print("%x" %num3)
/*
<__main__.Cat object at 0x00000012E837FA90>
12e837fa90
<__main__.Cat object at 0x00000012E837FAC8>
12e837fac8
<__main__.Cat object at 0x00000012E837FA90>
12e837fa90
*/
3.方法中的self参数
- 在python中,要给对象设置属性,非常容易,但不推荐使用(只需要在类外部代码中直接通过.设置一个属性即可)
- 对象属性封装应该封装在类的内部
class Cat:
def eat(self):
# 哪一个对象调用的方法,self就是那一个对象的引用
print("小猫%s要吃鱼" %self.name)
def drink(self):
print("小猫%s要喝水" %self.name)
tom = Cat()
tom.name="tom"
tom.eat()
jim = Cat()
jim.name="jim"
jim.drink()
/*
小猫tom要吃鱼
小猫jim要喝水
*/
4.初始化方法
- 当使用类名()创建对象,会自动执行以下操作:
- 为对象在内存中分配空间 --创建对象
- 为对象的属性设置初始值 --初始化方法(init)
就是_init_
方法
- 专门用来定义一个类具有哪些属性的方法,有点像java中的构造方法
class Cat:
def __init__(self):
print("初始化方法")
tom =Cat()
/*初始化方法*/
class Cat:
def __init__(self):
print("初始化方法")
self.name="tom"
def eat(self):
print("小猫%s爱吃鱼" %self.name)
tom =Cat()
print(tom.name)
tom.eat()
/*
初始化方法
tom
小猫tom爱吃鱼
*/
- 改造初始化方法
class Cat:
def __init__(self,new_num):
print("初始化方法")
self.name=new_num
def eat(self):
print("小猫%s爱吃鱼" %self.name)
tom =Cat("tom")
print(tom.name)
tom.eat()
jim = Cat("jim")
print(jim.name)
jim.eat()
/*
初始化方法
tom
小猫tom爱吃鱼
初始化方法
jim
小猫jim爱吃鱼
*/
5.内置方法
_del_方法:对象被从内存中销毁前,会被自动调用
_str_方法:返回对象的描述信息,print函数输出使用
像java中toString()方法
class Cat:
def __init__(self,new_num):
self.name=new_num
print("%s来了" %self.name)
def __del__(self):
print("%s去了" %self.name)
tom = Cat("tom")
del tom
print("-"*50)
/*
tom来了
tom去了
--------------------------------------------------
*/
class Cat:
def __init__(self,new_num):
self.name=new_num
print("%s来了" %self.name)
def __del__(self):
print("%s去了" %self.name)
def __str__(self):
return "我是小猫[%s]" %self.name
tom = Cat("tom")
print(tom)
/*
tom来了
我是小猫[tom]
tom去了
*/
二.私有属性和私有方法
- 在定义属性或方法时,在属性名或方法名前增加两个下划线,定义的就是私有属性或方法
1.私有属性和私有方法
class student:
def __init__(self,name):
self.name=name
self.__age=18
def secret(self):
print("%s的年龄有%d" %(self.name,self.__age))
stu1 = student("小明")
#访问不到 print(stu1.__age)
stu1.secret()
/*
小明的年龄有18
*/
2.伪私有属性和私有方法
- 在Python,没有真正意义上的私有,可以说是伪私有
class student:
def __init__(self,name):
self.name=name
self.__age=18
def __secret(self):
print("%s的年龄有%d" %(self.name,self.__age))
stu1 = student("小明")
print(stu1._student__age) #不推荐
#访问不到 print(stu1.__age)
stu1._student__secret()
/*
18
小明的年龄有18
*/
三.继承
1.单继承
- 子类拥有父类的所有方法和属性
class 类名(父类名)
pass
class Animal:
def eat(self):
print("吃")
def drink(self):
print("喝")
def sleep(self):
print("睡")
class Dog(Animal):
def bark(self):
print("叫")
tom = Dog()
tom.eat()
tom.drink()
tom.sleep()
tom.bark()
/*
吃
喝
睡
叫
*/
2.继承传递性
- B继承于A,C继承于B,那么C也继承于A
class Animal:
def eat(self):
print("吃")
def drink(self):
print("喝")
def sleep(self):
print("睡")
class Dog(Animal):
def bark(self):
print("叫")
class XiaoTianQuan(Dog):
def fry(self):
print("我会飞")
tom = XiaoTianQuan()
tom.fry()
tom.eat()
tom.drink()
tom.sleep()
tom.bark()
3.方法重写
- 子类拥有父类所有方法和属性
- 子类继承自父类,可以直接享受父类中已封装好的方法,不需要再次开发
- 覆盖父类的方法
- 对父类方法进行扩展
class Animal:
def eat(self):
print("吃")
def drink(self):
print("喝")
def sleep(self):
print("睡")
class Dog(Animal):
def bark(self):
print("叫")
class XiaoTianQuan(Dog):
def fry(self):
print("我会飞")
def bark(self):
print("叫的更神一样")
tom = XiaoTianQuan()
tom.bark()
/*
叫的更神一样
*/
class Animal:
def eat(self):
print("吃")
def drink(self):
print("喝")
def sleep(self):
print("睡")
class Dog(Animal):
def bark(self):
print("叫")
class XiaoTianQuan(Dog):
def fry(self):
print("我会飞")
def bark(self):
print("叫的更神一样")
# 使用super().调用原本在父类封装的方法
super().bark()
tom = XiaoTianQuan()
tom.bark()
/*
叫的更神一样
叫
*/
- 调用父类方法的另外一种方式
父类名.方法(self):
class Animal:
def eat(self):
print("吃")
def drink(self):
print("喝")
def sleep(self):
print("睡")
class Dog(Animal):
def bark(self):
print("叫")
class XiaoTianQuan(Dog):
def fry(self):
print("我会飞")
def bark(self):
print("叫的更神一样")
Dog.bark(self)
tom = XiaoTianQuan()
tom.bark()
四.私有属性和私有方法扩展
-
私有属性、方法是对象的隐私,不对外公开,外界和子类都不能直接访问
-
私有属性、方法通常用于做一些内部的事情
1.子类不能直接访问父类私有
class A:
pass
def __init__(self):
self.num1=10
self.__num2=20
def __test(self):
print("私有方法%d %d" %(self.num1,self.__num2))
class B(A):
def demo(self):
#在子类对象方法中不能直接访问父类私有属性 print("访问父类的私有属性 " %self.__num2)
#在子类对象方法中不能直接访问父类私有方法 self.__test()
pass
b= B()
print(b)
# 不能直接访问私有属性 print(b.__num2)
# 不能直接访问私有方法 b.test()
2.子类间接访问父类私有
class A:
pass
def __init__(self):
self.num1=10
self.__num2=20
def __test(self):
print("私有方法%d %d" %(self.num1,self.__num2))
def test(self):
print("公有方法: %d" %(self.__num2))
self.__test()
class B(A):
def demo(self):
#在子类对象方法中不能直接访问父类私有属性 print("访问父类的私有属性 " %self.__num2)
#在子类对象方法中不能直接访问父类私有方法 self.__test()
self.test()
b= B()
b.demo()
/*
公有方法: 20
私有方法10 20
*/
五.多继承
- 子类可以拥有多个父类,并且具有所有父类的属性和方法
- 孩子会继承自己父亲和母亲的特性
class 子类名(父类名1,父类名2...)
pass
class A:
def test(self):
print("a")
class B:
def demo(self):
print("b")
class C(A,B):
pass
c = C()
c.demo()
c.test()
/*
b
a
*/
- 开发时,尽量避免父类之间存在同名属性或者方法,尽量避免使用多继承
class A:
def test(self):
print("a self")
def demo(self):
print("a demo")
class B:
def demo(self):
print("b demo")
def test(self):
print("b self")
class C(A,B):#这里继承顺序改下输出就是B类中的两个方法了,具体,后面会说
pass
c = C()
c.demo()
c.test()
/*
a demo
a self
*/
- Python中的MRO–方法搜素顺序
- 针对类提供了一个内置属性
__mrg__
可以查看方法搜索顺序
class A:
def test(self):
print("a self")
def demo(self):
print("a demo")
class B:
def demo(self):
print("b demo")
def test(self):
print("b self")
class C(B,A):
pass
c = C()
# 从左往右找 找到就输出
print(C.__mro__)
- 新式类和旧式(经典)类
Object是python为所有对象提供的基类
新式类:以object为基类的类,推荐使用
经典类:不以以object为基类的类,不推荐使用
六.多态
- 不同的子类对象调用相同父类方法,产生不同执行结果
class Dog(object):
def __init__(self,name):
self.name=name
def game(self):
print("%s蹦蹦跳跳的玩耍" %self.name)
class XiaoTianQuan(Dog):
def game(self):
print("%s飞上天去玩" %self.name)
class Person:
def __init__(self,name):
self.name=name
def game_with_dog(self,dog):
print("%s和%s一起玩耍" %(self.name,dog.name))
dog.game()
#wangcai = Dog("旺财")
wangcai = XiaoTianQuan("飞天旺财")
xiaoming = Person("小明")
xiaoming.game_with_dog(wangcai)
/*
小明和飞天旺财一起玩耍
飞天旺财飞上天去玩
*/
七.类属性和类方法
1.类属性
- 类属性就是给类对象中定义的属性
- 通常用来记录与这个类相关的特征
- 类属性不会用于记录具体对象的特征
class Tool(object):
count = 0
def __init__(self,name):
self.name=name
Tool.count+=1
tool1 = Tool("斧头")
tool2 = Tool("扫把")
tool3 = Tool("拖把")
print(Tool.count)
/*
3
*/
- 如果使用对象.类属性 = 值 赋值,只会给对象添加一个属性,而不会影响类属性的值
class Tool(object):
count = 0
def __init__(self,name):
self.name=name
Tool.count+=1
tool1 = Tool("斧头")
tool2 = Tool("扫把")
tool3 = Tool("拖把")
tool3.count = 99
print(tool3.count)
print(Tool.count)
/*
99
3
*/
2.类方法
@classmethod
def 类方法名(cls):
pass
- 类方法需要用修饰器
@classmethod
来标识,告诉解释器这是一个类方法 - 类方法第一个参数是
cls
- 通过类名,调用类方法,调用方法时,不需要传递
cls
参数 - 在方法内部
* 可以通过cls
,访问类属性
* 也可以通过cls
,调用其他的类方法
class Tool(object):
count = 0
@classmethod
def show_tool_count(cls):
print(cls.count)
def __init__(self,name):
self.name=name
Tool.count+=1
tool1 = Tool("1")
tool2 = Tool("2")
tool3 = Tool("3")
Tool.show_tool_count()
/*
3
*/
3.静态方法
- 既不需要方法实例属性或者调用实例方法
- 也不需要访问类属性或者调用类方法
这个时候,可以把这个方法封装成一个静态方法
@staticmethod
def 静态方法名():
pass
class Dog(object):
@staticmethod
def run():
#不需要访问类属性/实例属性
print("我要跑")
Dog.run()
/*
我要跑
*/
八.单例
1.单例设计模式
-
设计模式是前人工作的总结和提炼
-
使用设计模式是未来可重用代码,让代码更容易被他人理解、保证代码可靠性
-
单例设计模式
目的:让类创建的对象,在系统中只有唯一的一个实例
每一次执行类名()
返回的对象,内存地址是相同的 -
单例应用场景
音乐播放对象,回收站对象,打印机对象等等
2.__new__
方法
-
使用类名()创建对象时,python的解释器首先会调用
__new__
方法为对象分配空间 -
__new__
是一个由object基类提供的内置的静态方法 -
作用为:在内存中为对象分配空间;返回对象的引用
-
Python解释器获得对象的引用后,将引用作为第一个参数,传递给
__init__
方法 -
重写
__new__
方法一定要return super().__new__(cls)
方法 -
否则Python解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
-
__new__
是一个静态方法,在调用时需要主动传递cls
参数
class MusicPlayer(object):
# *元组 **字典
def __new__(cls, *args, **kwargs):
print("创建对象,分配空间")
def __init__(self):
print("播放器初始化")
player = MusicPlayer()
print(player)
/*
创建对象,分配空间
None
*/
class MusicPlayer(object):
# *元组 **字典
def __new__(cls, *args, **kwargs):
print("创建对象,分配空间")
instance = super().__new__(cls)
return instance
def __init__(self):
print("播放器初始化")
player = MusicPlayer()
print(player)
/*
创建对象,分配空间
播放器初始化
<__main__.MusicPlayer object at 0x000000CB2A6E2E80>
*/
3.python中的单例
class MusicPlayer(object):
pass
player1 = MusicPlayer()
player2 = MusicPlayer()
print(player1)
print(player2)
/*
<__main__.MusicPlayer object at 0x0000007F1A5E2E80>
<__main__.MusicPlayer object at 0x0000007F1A62F0F0>
*/
class MusicPlayer(object):
instance = None
# *元组 **字典
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)
/*
<__main__.MusicPlayer object at 0x000000DAC5CFF048>
<__main__.MusicPlayer object at 0x000000DAC5CFF048>
*/
- 在每次使用
类名()
创建对象时,Python解释器都会自动调用两个方法
__new__分配空间
__init__对象初始化
在上面对__new__
方法改造,每次都会得到第一次被创建对象的引用,但是初始化方法还会被再次调用
class MusicPlayer(object):
instance = None
init_flag = False
# *元组 **字典
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self):
if self.init_flag:
return
print("初始化方法")
self.init_flag = True
player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)
/*
初始化方法
<__main__.MusicPlayer object at 0x000000010257F048>
<__main__.MusicPlayer object at 0x000000010257F048>
*/
上一篇: Shell脚本检查文件是否有改动