python面向对象
面向对象与面向过程,不多说
类和对象
类和对象是面向编程的两个核心概念,java中亦是如此
总而言之,类是模板,对象是实例
类的模板
class Human:
"""
此类主要是构建人类
"""
mind = '有思想' # 第一部分:静态属性 属性 静态变量 静态字段
dic = {}
l1 = []
def work(self): # 第二部分:方法 函数 动态属性
print('人类会工作')
# class 是关键字与def用法相同,定义一个类。
# Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。
# 类的结构从大方向来说就分为两部分:
静态变量。
动态方法。
面向对象基本语法
定义类:使用class来定义一个类,类名一般需要遵守大驼峰命名法
- class 类名:
- class 类名(object):
class Student(object): # 关注这个类有哪些属性和行为
# 这个属性直接定义在类里,是一个元组,用来规定对象可以存在的属性
__slots__ = ('name', 'age', 'height')
# 在__init__方法里,以参数的形式定义属性,我们称之为属性
def __init__(self, name, age, height):
self.name = name
self.age = age
self.height = height
# 还可定义一些方法
def run(self):
print('正在跑步')
def eat(self):
print('正在吃东西')
# 通过Student类创建对象
s1 = Student('小明', 20, 175) # 自动调用__init__方法
s1.run()
print(s1.hobby) # 注意:如果没有这个属性的话会报错
# 直接使用等号给一个属性赋值(这点与java不同,java是定死了的)
# 如果这个属性以前不存在,会给对象重新添加一个新的属性
# 如果这个属性以前存在的话,那么就会修改这个属性的值
s1.sleep = True
print(s1.sleep)
魔法方法1
也叫魔术方法,是类里面的特殊方法,不需要手动调用
特点:
- 不需要手动调用,会在合适的时机自动调用
- 这些方法,都是使用下划线__开始,使用下划线结束
- 方法名都是系统规定好的,在合适的时机自己调用
import time
class Person(object):
# 在创建对象时,会自动调用这个方法
def __init__(self, name, age):
print('__inti__方法被调用了')
self.name = name
self.age = age
# 当对象被销毁时,会自动调用这个方法
def __del__(self):
print('__del__方法被调用了')
def __str__(self):
return '姓名:{},年龄:{}'.format(self.name, self.age)
def __repr__(self):
return 'world'
def __call__(self, *args, **kwargs):
print('__call__方法被调用')
# args 是一个元组,保存(1,2)
fn = kwargs['fn']
# return fn(args[0], args[1])
return kwargs['fn'](args[0], args[1])
p1 = Person('小皮', 18)
# 如果不做任何修改,直接打印一个对象,是对象的类型以及内存地址
# 直接打印对象的话,会调用这个对象的__str__或者__repr__方法
# 如果上述的两个方法都重写了,会选择__str__方法
print(p1)
# time.sleep(10)
print(repr(p1)) # 调用内置函数repr会触发对象的__repr__方法
print(p1.__repr__()) # 也可以手动调用魔法方法
result = p1(1, 2, fn=lambda x, y: x + y) # 调用对象的__call__方法
print(result)
总结
当创建一个对象时,会自动调用__init__方法,当删除一个对象时,会自动调用__del__方法
魔法方法2
import time
class Person(object):
# 在创建对象时,会自动调用这个方法
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
print(f'__equ__方法被调用了,other ={other}')
if self.name == other.name and self.age == other.age:
return True
else:
return False
p1 = Person('小明', 18)
p2 = Person('小明', 18)
# p1和p2是同一个对象嘛
# 怎么比较两个对象是同一个对象呢?比较的是内存地址
print('ox%x' % id(p1)) # ox1df8370
print('ox%x' % id(p2)) # ox1e0e3a0
# is 身份运算符,可以从来判断两个人对象是否是同一个对象
print(p1 is p2) # False
print('p1 == p2', p1 == p2) # False
# 其实 == 会调用对象的__eq__方法,获取返回值,如果__eq__方法不重写,仍然比较的是内存地址
运算符相关的魔法方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
def __ne__(self, other): # 使用 != 运算符会使用这个方法
return '不等运算符'
def __gt__(self, other): # 使用 > 运算符会调用(如果没有重写这个方法,那么就会报错)
return '大于运算符'
def __ge__(self, other): # 使用 >= 运算符会调用(如果没有重写这个方法,那么就会报错)
return '大于等于运算符'
def __lt__(self, other): # 使用 < 运算符会调用(如果没有重写这个方法,那么就会报错)
return '小于运算符'
def __le__(self, other): # 使用 <= 运算符会调用(如果没有重写这个方法,那么就会报错)
return '小于等于运算符'
def __add__(self, other): # 使用 + 运算符会调用
return '加法运算符'
def __sub__(self, other): # 使用 - 运算符会调用
return '减法运算符'
def __mul__(self, other):
return '乘法运算符'
def __truediv__(self, other):
return '除法运算符'
def __str__(self):
return f'name:{self.name},age:{self.age}'
def __int__(self):
return self.age
p1 = Person("张三", 18)
p2 = Person("张三", 18)
print(p1 is p2) # False 判断两个是不是同一个对象
print(p1 == p2) # True 会调用__equ__方法
print(p1 != p2) # hello,会调用 __ne__方法或者__eq__方法取反
print(p1 > p2)
print(p1 >= p2)
print(p1 < p2)
print(p1 + p2)
print(p1 - p2)
# str() 将对象转换为字符串,会自动调用__str__方法,打印也会调用
print(str(p1)) # 转换为字符串 <__main__.Person object at 0x0000000000688400>
print(int(p1)) # 会调用__int__方法
内置属性
python类中自带的一些属性
class Person:
"""
这是类的文档注释
"""
# __slots__ = ('name', 'age') # 规定有哪些属性
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + ' 正在吃饭')
p = Person('张三', 18)
# print(dir(p)) # 查看对象的所有属性、行为
"""
内置属性
"""
# __class__
print(p.__class__) # <class '__main__.Person'>
# __dict__ 把对象的属性和值转成字典,等价于 dir(p)
print(p.__dict__) # {'name': '张三', 'age': 18}
# __doc__
print(p.__doc__) # 查看当前对象的文档,也可以通过Person.__doc__ 类名获取
# __module__
print(p.__module__) # 获取模块名 __main__
# __slots__
# print(p.__slots_)
把对象当做字典使用
dict的使用,类似java中的getter、setter方法
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def __setitem__(self, key, value):
print(f'__setitem__方法被调用了,key={key},value={value}')
self.__dict__[key] = value
def __getitem__(self, item):
return self.__dict__[item]
p = Person('张三', 18, '深圳')
print(p.__dict__) # 将对象转换成字典
# 不能直接把一个对象当做字典来使用
p['name'] = 'pihao' # []语法 会调用对象的__setitem__方法,所有要重写这个方法才能使用
print(p.name)
p.__dict__['name'] = 'haoming'
print(p.name)
# 默认是不能直接使用这种方法来获取属性值的,需要重写__getitem__方法
print(p['name'])
类属性和对象属性
类似java中的实例方法以及类方法(静态方法)
- 对象属性:每个实例对象都单独保存的属性
- 类属性: 保存在类中,所有的实例对象共有,只能通过类对象来修改值,不能通过实例对象来修改
class Person:
type = '人类' # 类属性
def __init__(self, name, age):
self.name = name # 对象属性
self.age = age
p1 = Person('张三', 19)
p2 = Person('李四', 20)
p1.type = 'human' # 注意:实例对象并不会修改类属性,而是给实例对象添加了一个的对象属性
Person.type = 'monkey' # 这样才是修改了
print(p1.type)
print(p2.type)
print(Person.type)
私有属性和私有方法
类似java中被private修饰的变量,只能在类中调用或者定义get|set方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
self.__money = 1000 # 以两个下划线开头的变量是私有变量,有点类似java中private修饰的变量
def test(self):
self.__money += 10 # 在类中可以访问私有属性
def get_money(self):
return self.__money
def set_money(self, money):
self.__money = money
def __demo(self):
print('我是__demo函数') # 以两个下划线开始的函数,是私有函数,在外部无法调用
p = Person('张三', 18)
print(p.name)
# print(p.__money) # 拿不到__money的值
# 获取私有变量的方式
# 1、使用对象._类名__私有变量名获取
print(p._Person__money) # 1000,没有绝对的私有
p.test()
print(p._Person__money) # 1010
# 2、定义get和set方法来获取
print(p.get_money())
p.set_money(100)
print(p.get_money())
# 3、使用property来获取(知道)
# p.__demo() # 不能调用,只能在类的内部调用
p._Person__demo() # 或者这样调用
类方法以及静态方法
类似java中被static修饰的方法,
- 静态方法:没有使用到实例对象的任何属性,那么你就可以声明为静态方法,常在工具类中使用
- 类方法:如果这个函数只用到了类属性,我们可以定义为一个类方法
import time
class Person(object):
type = 'human' # 定义一个类属性
def __init__(self, name, age):
self.name = name
self.age = age
# 实例方法
def eat(self, food):
print(f'{self.name}正在吃{food}')
# 如果一个方法里没有用到实例对象的任何属性,可以将这个方法声明为static静态方法
@staticmethod
def help():
print("使用说明.....")
# 如果一个方法只使用到了类属性,那么可以定义为一个类方法
@classmethod
def test(cls): # 这里的cls其实是Person类对象
print(cls.type)
# 实例对象调用
p = Person('小明', 18)
p.eat('披萨') # 小明正在吃披萨
Person.eat(p, '火锅') # 如果使用类对象调用的方法的话,需要手动指定实例self
# 静态方法调用
Person.help() # 静态方法调用,没有用到实例对象的任何属性
p.help()
# 类方法调用(可以使用类或者实例调用)
Person.test()
p.test()
继承
面向对象的三大特点:封装、继承、多态
- 封装:函数是对语句的封装,类是对函数和变量的封装
- 继承:类和类之间可以认为手动的建立父子关系,父类的属性和方法,子类可以使用
- 多态:是一种技巧,提高代码的灵活度
# 继承简单使用
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def sleep(self):
print(f'{self.name}正在睡觉')
class B(A): # 继承A类
def bark(self):
print(f'{self.name}正在叫')
a = B('大黄', 3)
# a = B() 会报错,首先它会调用__new__方法,再调用__init方法
a.bark()
python继承的注意事项
- python允许多继承,这点和java区分开,java只能单继承
- 如过不同的父类中有同名的方法,在调用的时候就是就近原则(就是在继承的括号里前面的优先),与继承的顺序有关
- 继承的时候是深度优先还是广度优先?(深度优先,了解),查看类的__mro__属性。就是继承的调用顺序
面向对象的相关方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
pass
p1 = Person('张三', 18)
p2 = Person('李四', 20)
print(p1 is p2) # is 运算符是用来判断两个对象是否是同一个对象,比较的是内存地址 id(p1) == id(p2)
if type(p1) == Person: # type(p1) 其实获取的就是类的对象
print('p1是Person类创建的对象')
# isinstance 用来判断一个对象是否是由指定的类(或者父类)实例化出来的
s = Student('Jack', 20)
print(isinstance(s, Student)) # True
print(isinstance(s, Person)) # True
# issubclass 用来判断一个类是否是另一个类的子类
print(issubclass(Student, Person)) # True
print(issubclass(Person, Student)) # False
多态
子类重写父类的方法
继承特点:如果一个类A继承自类B,那么由A创建出来的实例对象都能直接使用类B定义的方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def sleep(self):
print(f'{self.name}正在睡觉')
class Student(Person):
def __init__(self, name, age, school):
# 使用super直接调用父类的方法,推荐这种方式
super(Student, self).__init__(name, age)
self.school = school
def sleep(self):
print(f'{self.name}正在课间休息时睡觉')
s = Student('Jack', 20, 'xxx大学')
s.sleep()
多态的使用
多态是基于继承的,通过子类重写父类的方法,达到不同的子类对象调用相同的父类方法,得到不同的结果,提高代码的灵活度
不使用多态的问题
代码十分冗余
使用多态优化代码
class Dog:
def work(self):
print('狗狗正在工作')
class PoliceDog:
def work(self):
print('警犬正在攻击敌人')
class BlindDog:
def work(self):
print('导盲犬正在领路')
class DrugDog:
def work(self):
print('缉毒犬正在搜毒')
class Person:
def __init__(self, name):
self.name = name
self.dog = None
def work_with_dog(self):
if self.dog is not None and isinstance(self.dog, Dog):
self.dog.work()
p = Person('张三')
pd = PoliceDog()
p.dog = pd
p.work_with_dog()
pd = BlindDog()
p.dog = pd
p.work_with_dog()
pd = DrugDog()
p.dog = pd
p.work_with_dog()