文章目录
学习目标
- 说出面向对象和面向过程的特点
- 能够使用dir内置函数查看对象的方法
- 能够使用类创建对象
- 能够说出self的含义
- 能够说出魔法方法什么时候调用
- 能够说出内置属性的作用
- 能够说出实例属性和类属性的区别
- 能够定义和操作使用属性
一、面向对象介绍
- 面向过程:根据业务逻辑从上到下写代码
- 面向对象:将 变量与函数 绑定到一起,分类进行封装,每个程序只负责分配给自己的分类,这样能够更快速的开发程序,减少了重复代码
二、类和对象
- 类和对象是面向对象编程的两个核心概念
2.1 类
类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
- 特征其实就是一个变量,在类里我们称之为属性
- 行为其实就是一个函数,在类里我们称之为方法
- 类其实就是由 属性 和 方法 组成的一个抽象概念
2.2 对象
对象是由类创建出来的一个具体存在,可以直接使用。由哪一个类创建出来的 对象,就拥有在哪一个类中定义的属性和方法
2.3 类的设计
在程序开发中,要设计一个类,通常需要满足一下三个要素:
- 类名 这类事物的名字,按照大驼峰命名法(每个单词的首字母大写)起名
- 属性 这类事物具有什么样的 特征
- 方法 这类事物具有什么样的 行为
# 定义类:class关键字
# class 类名:类名按照大驼峰命名法(每个单词的首字母大写)起名
# 1. class <类名>
# 2. class <类名>(object)
class Student(object):
def __init__(self,name,age,height): # 在 __init__ 方法里,以参数的形式定义属性
self.name = name
self.age = age
self.height = height
def run(self):
print('正在跑步')
def eat(self):
print('正在吃东西')
# 使用 Student类 创建了两个实例对象 s1 s2
# s1和s2都会有name,age,height属性,同时都有run和eat方法
s1 = Student('小明',18,1.8)
s2 = Student('小美',19,1.65)
2.4 self语句的使用
class Student:
# 这个属性直接定义在类里,是一个元组,用来规定对象可以存在的属性,可以限制动态属性的设置
__slots__ = ('name','age')
def __init__(self,x, y):
self.name = x
self.age = y
# Student('张三',18) 这段代码具体做了什么呢?
# 1. 调用 __new__ 方法,用来申请s内存空间
# 2. 调用 __init__ 方法传入参数,并让 self 指向申请好的那段内存空间,填充数据
# 3. 变量 s1 也指向创建好的这段内存空间
s1 = Student('张三', 18)
# 直接使用等号给一个对象的属性赋值
# 如果这个属性以前不存在,会给对象添加一个新的属性
# 动态属性
s.city = '上海' # 给对象添加了一个city属性
# 如果这个属性以前存在,会修改这个属性
s.name = 'jack'
三、魔法方法
3.1 对象操作的魔法方法
# 魔法方法,也叫魔术方法,是类里的特殊的一些方法
# 特点
# 1. 不需要手动调用,会在合适的时机自动调用
# 2. 这些方法,都是是使用 __ 开始,使用 __ 结束
# 3. 方法名都是系统规定好的,在合适的实际自己调用
class Person(object):
# __init__ 魔法方法在创建对象时,会自动调用这个方法
def __init__(self,name,age):
self.name = name
self.age = age
# __del__ 魔法方法,当对象被销毁时,会自动调用这个方法
def __del__(self):
print('__del__方法被调用了')
# __repr__ 与 __str__ 魔法方法,当打印对象时,会返回该方法的返回结果(优先__str__)
def __repr__(self):
return 'hello'
def __str__(self):
return 'good'
# 使用 int() 内置函数时会被调用
def __int__(self):
return 11
# 使用 float() 内置函数时会被调用
def __float__(self):
return 11.9
# 使用:对象名(参数列表) 时会被调用
def __call__(self, *args, **kwargs):
pass
p = Person('zhangsan', 18)
# 如果不做任何的修改,直接打印一个对象,是文件的 __name__.类型 内存地址 内存地址
# 实质上,当打印一个对象的时候,会调用这个对象的 __str__ 或者 __repr__ 方法
# 如果两个方法都写了,会选择 __str__
print(p)
# 调用 __int__ 方法
print(int(p))
# 调用 __float__ 方法
print(float(p))
# 对象名() ==> 调用这个对象的 p.__call__(1, 2) 方法
p(1, 2)
3.2 运算符相关的魔法方法
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 在 == 运算符使用时被调用,用于判断两个对象是否值相等 (返回bool类型数据)
def __eq__(self,other):
print("调用了 __eq__ 方法")
return self.name == other.name and self.age == other.age
# 在 != 运算符使用时被调用,用于判断两个对象是否值不相等 (返回bool类型数据)
def __ne__(self,other):
print("调用了 __ne__ 方法")
return self.name != other.name or self.age != other.age
# 在 > 运算符使用时被调用,用于判断两个对象是否是大于关系 (返回bool类型数据)
def __gt__(self,other):
return self.age > other.age
# 在 >= 运算符使用时被调用,用于判断两个对象是否是大于等于关系 (返回bool类型数据)
def __ge__(self,other):
return self.age >= other.age
# 在 < 运算符使用时被调用,用于判断两个对象是否是小于关系 (返回bool类型数据)
def __lt__(self, other):
return self.age < other.age
# 在 <= 运算符使用时被调用,用于判断两个对象是否是小于等于关系 (返回bool类型数据)
def __le__(self,other):
return self.age <= other.age
# 在 + 运算符使用时被调用,用于执行两个对象相加的操作
def __add__(self, other):
return self.age + other.age
# 在 - 运算符使用时被调用,用于执行两个对象相减的操作
def __sub__(self,other):
return self.age - other.age
# 在 * 运算符使用时被调用,用于执行两个对象相乘的操作
def __mul__(self,other):
return self.age * other.age
# 在 / 运算符使用时被调用,用于执行两个对象相除的操作
def __truediv__(self,other):
return self.age / other.age
# 在 % 运算符使用时被调用,用于执行两个对象取模的操作
def __mod__(self,other):
return self.age % other.age
# 在 ** 运算符使用时被调用,用于执行两个对象幂次方的操作
def __pow__(self,other):
return self.age ** other.age
# p1 与 p2 不是同一个对象
p1 = Person('张三', 18)
p2 = Person('张三', 18)
# is 身份运算符,可以用来判断两个对象是否是同一个对象
# == 会调用对象的 __eq__ 方法,获取这个方法的比较结果
print(p1 is p2) # False
print(p1 == p2) # 如果对象不重写 __eq__ 方法,默认比较依然是内存地址
# != 本质是调用 __ne__ 方法(没有的话调用 __eq__方法取反)
print(p1 != p2) # 如果对象不重写 __ne__ 方法(且不重写__eq__方法),默认比较依然是内存地址
# > 本质是调用 __gt__ 方法
print(p1 > p2)
# >= 本质是调用 __ge__ 方法
print(p1 >= p2)
# < 本质是调用 __lt__ 方法
print(p1 < p2)
# <= 本质是调用 __le__ 方法
print(p1 <= p2)
# + 本质是调用 __add__ 方法
print(p1 + p2)
# - 本质是调用 __sub__ 方法
print(p1 - p2)
# * 本质是调用 __mul__ 方法
print(p1 * p2)
# / 本质是调用 __truediv__ 方法
print(p1 / p2)
# % 本质是调用 __mod__ 方法
print(p1 % p2)
# ** 本质是调用 __pow__ 方法
print(p1 ** p2)
四、内置属性
使用内置函数 dir 可以查看一个对象支持的所用属性和方法,Python中存在着很多的 内置属性(不需要import导入模块就能直接调用的属性值,形如:__内置属性名__)
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print(self.name+ '正在吃饭')
# 自定义的属性包括,name,age,eat ,eat可以理解为值是函数对象的属性
p = Person('张三', 18)
# 查看p对象的所有属性
print(dir(p))
# 比较重要的几个内置属性
__doc__:模块中用于描述的文档字符串
__name__:模块名
__file__:模块保存的路径
__dict__ : 类的属性(包含一个字典,由类的数据属性组成。使用类调用返回类的属性,使用对象调用返回对象的属性)
__module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
4.1 把对象当做一个字典使用
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
# 当使用对当前对象使用字典的赋值方式[]时,调用此方法
def __setitem__(self,key,value):
self.__dict__[key] = value
# 当使用对当前对象使用字典的读取方式[]时,调用此方法
def __getitem__(self,item):
return self.__dict__[item]
p['age'] = 20 # 调用 __setitem__ 方法
print(p['name']) # 调用 __getitem__ 方法
五、类属性和对象(实例)属性
class Person:
type = '人类' # 这个属性定义在类里,函数之外,我们称之为类属性
def __init__(self,name,age):
self.name = name
self.age = age
# 对象 p1 和 p2 是通过 Person 类创建出来的实例对象
# name 和 age 是 对象属性,在 __init__ 方法里,是以参数的形式定义的每一个实例对象都会单独保存在自己的存储空间内
# 每个实例对象的属性之间没有关联,互不影响
p1 = Person('张三', 18)
p2 = Person('李四', 19)
x = p1
print(p1.name)
print(x.name)
# 类属性可以通过类对象和实例对象获取
print(Person.type)
# 实例对象如果没有该实例属性,则向上到类中去找
print(p1.type)
print(p2.type)
# 类属性只能通过类对象来修改,实例对象无法修改类属性
p1.type = 'human' # 只是动态的给p1对象增加了一个type属性,而非修改类属性
Person.type = 'monkey' # 修改类属性
-
类与对象在内存中的存在形式
-
类属性、实例属性(类属性在内存中只保存一份实例属性在每个对象中都要保存一份)
六、私有属性和方法
在实际开发中,对象的某些属性或者方法可能只希望在对象的内部使用,而不希望在外部被访问到,这时就可以定义 私有属性 和 私有方法
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
self.__money = 1000 # 以两个下划线开头的属性名是私有变量,在类外部无法直接通过 对象.属性名的方式获取到该值
def get_money(self):
return self.__money
def set_money(self,money):
self.__money = money
# 以两个下划线开头的方法是私有方法,在类外部无法直接通过 对象.函数的方式调用该方法
def __demo(self):
pass
p1 = Person('张三',18)
print(p1.name,p1.age) # 可以直接获取到
print(p.__money) # 无法直接获取到私有变量
# 获取私有变量的方式:
# 1. 使用 对象._类名__私有变量名 获取
print(p1._Person__money) # 通过这种方式也能获取到私有属性
# 2. 在类中定义get和set方法来获取
print(p1.get_money())
# 3. 使用 property 来获取