根据代码组织方式不同,编程语言可以分为以下两种。
面向对象特征:封装、继承、多态
使用class创建类,模板如下:
class ClassName(bases):
class_suite
class是关键字,bases是要继承的父类,默认继承object类。
class _suite是类体,主要包含属性和方法。
类、属性和方法的命名约定惯例如下:
例:
class People:
name = "王李"
def update_name(self, name):
self.name = name
python的类分为两种
1.经典类
python2.x中类的定义的默认方式,不继承object类,其内部有属性和方法组成。经典类定义的典型方式如下:
class A:
pass
2.新式类
python3.x中类的定义的默认方式,必须继承object方法,其典型定义方式如下:
class A(object):
pass
新式类修复了经典类的一些bug(如多继承时的歧义等),并且提供了对类方法和静态方法的支持。
在python3.x中,如果没有显示指明要继承的父类,则默认继承object类。
class A:
pass
class A():
pass
class A(object):
pass
在python3.x中,无需继承,例子中的三种创建效果一样。自动继承object类。
新式类添加了一些内置属性和方法,如下所示:
__name__:属性的名字
__doc__:属性的文档字符串
__get__(object):获取对象属性值的方法
__set__(object, value):设置对象属性值的方法
__delete__(object, value):删除对象属性值的方法
类创建完之后,就应该创建该类的实例或对象了,该过程称之为实例化。当一个对象被创建后,就包含标识、属性和方法这三个方面的对象特征了。其中,对象标识用于区分不同的对象,属性和方法于类中的常用变量和成员函数相对应
声明一个类
class People:
def __init__(self,name,age,wight):
self.name = name
self.age = age
self.wight = wight
创建一个lisi对象
lisi = People("李四",20,'50kg')
print(lisi.name,lisi.age,lisi.wight)
属性分为类级别和实例级别两种。实例级别的属性值默认共享类级别的属性值。除非显式进行赋值操作。例:
class A():
age = 10
obj1 = A()
obj2 = A()
如上所示,存在三个实例,分别是类实例A和对象实例obj1、obj2。
obj1和obj2这两个对象实例共享类实例A的属性age:
print(obj1.age,obj2.age,A.age)#10 10 10
显式修改obj1的属性
obj1.age += 2
print(obj1.age,obj2.age,A.age)#12 10 10
修改类实例A的属性
A.age += 3
print(obj1.age,obj2.age,A.age)#12 13 13
修改了对象实例obj1的属性值age,其属性值和类实例A的属性值已经独立。而对象实例obj2的属性值从来没有修改过,所以它还是和类实例A的属性值保持一致。
python对于属性的设置采用“类.属性 = 值”或"实例.属性 = 值"的形式。如 obj1.age += 2 等价于 obj1.age =obj1.age + 2,该语句包含了属性获取及属性设置两个操作。
python语言中的属性操作遵循三个规则:
类的定义由属性和方法组成,属性是对数据的封装,方法则是对类行为的封装。属性按使用规范分为公有属性和私有属性,使用范围取决于属性名称。类的属性如下所示。
类的属性
属性类别 | 介绍 | 备注 |
---|---|---|
公有属性 | 类中和类外调用的属性。 | 若无特别说明。变量默认为公有属性。 |
私有属性 | 不能被类以外的函数调用的属性。 | 命名以双下划线“__”开始的成员变量就是私有属性,可以通过instance.__ClassName__atttibute方式访问 。 |
内置属性 | 由系统在定义类的时候默认添加的。 | 命名一般由前后各两个下划线“__”组成,如__doc__等。 |
内置属性
属性名 | 作用 |
---|---|
__name__ | 类的名字 |
__doc__ | 类的文档字符 |
__bases__ | 所有父类构成的元组 |
__dict__ | 类的属性 |
__module__ | 类定义所在的模块 |
__class_\ | 实例对应的类 |
内置实例属性
属性名 | 作用 |
---|---|
__class_\ | 实例对像所属的类名 |
__dict__ | 实例对像的属性 |
类方法也包括公有方法、私有方法、类方法和静态方法。
类的方法
方法类别 | 介绍 | 备注 |
---|---|---|
公有属性 | 不能被类直接调用,需要使用实例化对象调用。 | 若无特别说明。变量默认为公有属性。 |
私有方法 | 不能被外部的类和方法调用,其定义和私有属性的定义相同 | 需要在方法前面加上双下划线__ |
类方法 | 能被类所调用,也能被方法调用 | 被classmethod函数调用或被@classmethod装饰器修饰的方法 |
静态方法 | 相当于“全局方法” ,可以被类直接调用,也可以被所有实例化对象共享。 | 该方法通过调用staticmethod方法或被@staticmethod装饰器来声明,不需要"self"语句。 |
例:
class People:
def Play(self):
print("公有方法play")
self.__Study()
def __Study(self):
print("私有方法study")
def Breath(self):
print("类方法1 Breath")
Breath1=classmethod(Breath)
def Cry():
print("静态方法1 Cry")
Cry1 = staticmethod(Cry)
@classmethod
def Breath2(self):
print("类方法2 Breath")
@staticmethod
def Cry2():
print("静态方法2 Cry")
people = People()
people.Play()#People.Play()会报错
#people.__Study() 会报错
#People.__Study() 会报错
people.Breath()#People.Breath()会报错
people.Breath1()
People.Breath1()
people.Breath2()
People.Breath2()
People.Cry()# people.Cry()会报错
people.Cry1()
People.Cry1()
people.Cry2()
People.Cry2()
类方法于静态方法的区别
类的内部定义的类,主要目的是为了更好抽象世界。
class People:
code = 0
class Father:
code = 1
class Mother:
code = 2
zhangsan = People()
lisi = zhangsan.Father()#第一种实例化
print(lisi.code)#1
limi = zhangsan.Mother()#第二种实例化
print(limi.code)#2
在python语言中,所有以双下划线__包起来的方法,都统称为“魔术方法”。这些方法在实例化时会自动调用,比如__str__()、__init__()、__del__()等,使用魔术方法可以将复杂逻辑封装成简单API。
魔术方法的__init__()方法一般叫做构造函数,用于初始化类的内部构造和参数。如果不提供,Python语言会给出一个默认的__init__()方法
魔术方法的__del__()方法函数叫做析构函数,用于释放对象占用的资源。__del__()函数是可选的。如果不提供,Python语言会在后台提供默认析构函数。
魔术方法中,有些可以实现属性访问控制的功能,如__getattr__(self, name),__setattr__(self, name,value)方法等。
class People:
name = "人"
def __init__(self, n="非洲人"):
self.name = n
print("我是构造函数",self.name)
def __del__(self):
print("我是析构函数",self.name)
p = People()
ou = People("欧美人")
p.__del__()
print(p)
del p
del ou
#print(p) #no define error
#print(ou)#no define error
运行结果
我是构造函数 非洲人
我是构造函数 欧美人
我是析构函数 非洲人
<__main__.People object at 0x0000011A2B8DE9B0>
我是析构函数 非洲人
我是析构函数 欧美人
对于这些魔术方法,在创建对象时可以自动执行。当对象字典执行析构函数p.del()后,对象仍然存在,但是在调用del p后,对象就已经被回收删除,无法再次使用。
用实例方法执行某个功能时,如果需要使用另一个类的实例的方法来完成。则称这两个类存在依赖关系。
class Person:
def play(self, tools):
tools.run()
print("开始玩游戏")
class Computer:
def run(self):
print("打开电脑")
class Phone:
def run(self):
print("打开手机")
c = Computer()
p = Phone()
person = Person()
person.play(c)
person.play(p)
运行结果:
打开电脑
开始玩游戏
打开手机
开始玩游戏
一个类的属性类型是另一个类的类型,则称这两个类之间存在关联关系。根据单值、多值由分为一对一关联、一对多关联。
一对一关联
class Boy:
def __init__(self, name, grilFriend=None):
self.grilFriend = grilFriend
def play(self):
if self.grilFriend:
print(f"带女朋友{self.grilFriend.name}去玩")
else:
print("单身快乐")
class Girl:
def __init__(self, name):
self.name = name
g = Girl("小红")
b = Boy("小刘",g)
b.play()
b = Boy("小刘")
b.play()
运行结果
带女朋友小红去玩
单身快乐
一对多关联
class School:
def __init__(self, name):
self.teach_list = []
self.name = name
def recruit(self, teach):
self.teach_list.append(teach)
def attend_class(self):
for t in self.teach_list:
t.work()
class Teacher:
def __init__(self,name):
self.name = name
def work(self):
print(f"{self.name}在上课")
xph = School("小屁孩")
t1 = Teacher("太白")
t2 = Teacher("观音")
t3 = Teacher("扫地僧")
xph.recruit(t1)
xph.recruit(t2)
xph.recruit(t3)
xph.attend_class()
运行结果
================== RESTART: D:/Python/Project/Study/class9.py ==================
太白在上课
观音在上课
扫地僧在上课
继承类是在已有类基础上构建新类的机制,该新键类也成为子类。子类可以增加新的属性或功能也可以继承父类的功能。通过继承可以复用以前的代码,大大提高开发效率。
class People:
place = "地球"
def __init__(self):
print("我是构造函数")
def Study(self):
print("我爱机器学习")
class Japan(People):
place = "日本"
def __init__(self):
print("子类构造函数 日本省")
def Study(self):
print("日本省的人学习")
class China(People):
place = "中国"
def __init__(self):
print("子类构造函数 中国")
People.__init__(self)
def Study(self):
print("中国人学习")
class Ren(China, Japan):
pass
Uchan = Japan()
zhangheng = China()
Lini = Ren()
print(Uchan.place)
print(zhangheng.place)
print(Lini.place)
Uchan.Study()
zhangheng.Study()
Lini.Study()
运行结果:
================== RESTART: D:/Python/Project/Study/class10.py =================
子类构造函数 日本省
子类构造函数 中国
我是构造函数
子类构造函数 中国
我是构造函数
日本
中国
中国
日本省的人学习
中国人学习
中国人学习