Python面向对象编程
类和实例
Python是一门面向对象的编程语言,所以也有类的概念,类是一系列具有相同特征和行为事物的统称,Python中使用class关键字定义类。
类的定义
语法:
class 类名():
代码
...
示例:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self):
print("我的名字是{name}".format(name=self.name))
获取类的名字:
我们定义了一个名字叫Student的类,可以__name__
属性来访问它。
print(Student.__name__) # Student
实例化对象
语法:
对象名 = 类名()
示例:
# 创建对象
s = Student("张三", 10)
print(s) # <__main__.Student object at 0x000002A925707288>
类中的self
可以看到类中定义的每个方法都有self参数,指的是调用该函数的对象,该参数在方法被调用时是不需要传参的,self参数是对类的当前实例的引用,用于访问属于该类的变量。
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self):
print(self)
# print("我的名字是{name}".format(name=self.name))
s = Student("张三", 10)
print(s) # <__main__.Student object at 0x0000020349307148>
# self和对象的地址一致
s.get_name() # <__main__.Student object at 0x0000020349307148>
添加和获取对象属性
类外面添加对象属性:
对象名.属性名 = 值
示例:
class Student():
def study(self):
print("正在学习")
s = Student()
s.name = "张三"
s.age = 18
类外面获取对象属性:
对象名.属性名
示例:
class Student():
def study(self):
print("正在学习")
s = Student()
s.name = "张三"
s.age = 18
print(f'姓名为{s.name}') # 姓名为张三
print(f'年龄为{s.age}') # 年龄为18
类里面获取对象属性:
self.属性名
示例:
class Student():
def study(self):
print("正在学习")
def print_info(self):
print(f'您的姓名是{self.name}')
print(f'您的年龄是{self.age}')
s = Student()
s.name = "张三"
s.age = 18
s.print_info()
类属性
类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有,可以通过类名或者对象访问。
class Dog(object):
age = 5
print(Dog.age) # 5
dog1 = Dog()
print(dog1.age) # 5
修改类属性
语法:
类名.变量名 = 变量值
示例:
class Dog(object):
age = 5
Dog.age = 10
print(Dog.age) # 10
dog1 = Dog()
print(dog1.age) # 10
注:不能通过实例对象修改,如果通过 对象名.属性=属性值
的方式,则表示创建了一个实例属性。
类方法和静态方法
类方法
使用装饰器 @classmethod
来将方法标记为类方法,对于类方法,第一个参数必须是类对象,一般以 cls
作为第一个参数。
- 当方法中需要使用类对象(如访问私有类属性)时,定义类方法。
- 类方法一般和类属性配合使用。
示例:
class Dog(object):
__age = 10
@classmethod
def get_age(cls):
return cls.__age
dog1 = Dog()
res = dog1.get_age()
print(res) # 10
静态方法
当方法中既不需要使用实例对象(如实例属性),也不需要使用类对象(如类属性,类方法)时,可以定义静态方法。静态方法不需要参数传递,有利于减少不必要的内存占用和性能消耗。
- 静态方法使用装饰器
@staticmethod
来进行装饰,静态方法既不需要传递类对象也不需要传递实例对象。 - 静态方法也可以通过实例对象和类对象去访问。
示例:
class Dog(object):
@staticmethod
def test_method():
print('这是一个静态方法')
dog1 = Dog()
dog1.test_method() # 这是一个静态方法
Dog.test_method() # 这是一个静态方法
魔法方法和属性
在python中,具有特殊功能的函数被称为魔法方法。
__init__()
不带参数的__init__
方法
__init__()
函数在创建对象时被执行,用来初始化对象,不需要手动调用。__init__(self)
中的self参数,不需要传递,pyhont解释器会自动把当前对象的引用传递过去。
示例:
class Person:
# 定义__init__,添加实例属性
def __init__(self):
# 添加实例属性name和age
self.name = "tom"
self.age = 18
def print_info(self):
# 调用实例属性
print(f'姓名是{self.name}') # 姓名是tom
print(f'年龄是{self.age}') # 年龄是18
p1 = Person() # 自动执行类中的 __init__ 方法
# 调用实例方法
p1.print_info()
带参数的__init__
方法
在__init_
方法中传递参数。
示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def test_func(self):
print(f'我的名字是{self.name}, 年龄{self.age}')
p1 = Person("tom", 18) # 自动执行类中的 __init__ 方法
p1.test_func()
__str__()
如果类中定义了__str__()
方法,那么在打印对象时,会输出该方法的返回值。
没有定义__str__()
方法时:
默认打印对象的内存地址。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("tom", 18)
print(p1) # <__main__.Person object at 0x000001DF61EF5308>
当定义了__str__()
方法时:
打印__str__
方法的返回值。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "这是类的说明"
p1 = Person("tom", 18)
print(p1) # 这是类的说明
__repr__()
repr() 函数可以将对象转化为解释器读取的形式。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'姓名:{self.name},年龄:{self.age}'
p1 = Person("tom", 18)
print(repr(p1)) # 姓名:tom,年龄:18
当__repr__()
和__str()
同时存在时,打印对象打印的是__str__()
的返回值
__del__()
当对象在内存中被释放时,会默认调用__del__()
方法。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self):
print('对象已经删除')
p1 = Person("tom", 18)
__call__()
当类中定义了__call__()
方法,就可以使类实例对象像调用普通函数那样调用
class Person:
def __call__(self, name, age):
print(f'调用对象的__call__方法, {name}, {age}')
p1 = Person()
p1("张三", 18) # 对象p1可以调用
__eq__()
当我们使用==
来进行比较操作的时候,实际上是调用的__eq__()
这个方法。该方法默认有两个参数我们可以重写该方法来实现我们想要的比较结果,该方法默认有self和other两个参数。
def __eq__(self, other):
示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if self.name == other.name and self.age == other.age:
return True
return False
p1 = Person("tom", 18)
p2 = Person("tom", 18)
print(p1 == p2)
__new__()
当实例化一个类的时候首先调用的是__new__()
方法,在__init__()
方法之前执行。__init__()
负责将类实例化即初始化对象,而在__init__()
执行之前,先执行__new__()
负责创造一个实例对象。
__new__()
需要接受一个参数cls,cls表示需要实例化的类。__new__()
必须要有返回值,返回实例化出来的实例,__init__()
的self参数就是__new__()
返回的实例
class Person(object):
def __init__(self, name, age):
print("init function")
self.name = name
self.age = age
def __new__(cls, name, age):
print(cls) # <class '__main__.Person'>
print("new function")
# 调用父类的__new__()方法返回实例,这里cls是Person类
return object.__new__(cls)
p1 = Person("tom", 18)
注意:
__new__()
接受的参数要和__init__()
接受的参数一致。__new__()
可以使用*args
和**kwargs
来接受不限定的参数。- 如果返回的不是本类对象,不会触发
__init__()
方法。
单例模式的实现:
class Singleton(object):
__obj = None
def __new__(cls, *args, **kwargs):
if cls.__obj is None:
cls.__obj = object.__new__(cls)
return cls.__obj
obj1 = Singleton()
print(obj1) # <__main__.Singleton object at 0x000002501E8E3E88>
obj2 = Singleton()
print(obj2) # <__main__.Singleton object at 0x000002501E8E3E88>
单例模式和构造方法:
class Singleton(object):
__obj = None
def __new__(cls, *args, **kwargs):
if cls.__obj is None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self, name):
self.name = name
obj1 = Singleton("tom")
obj2 = Singleton("jerry")
print(obj1.name) # jerry
print(obj2.name) # jerry
__dict__
属性
Python中的类,都会从object里继承一个__dict__
属性。
类名直接调用__dict__
,会输出由该类中所有类属性(方法等)组成的字典。
类的实例对象调用 __dict__
,会输出由类中所有实例属性组成的字典。
class A(object):
a = 0
def __init__(self):
self.b = 1
a1 = A()
print(A.__dict__) # {'__module__': '__main__', 'a': 0, '__init__': <function A.__init__ at 0x0000019DE4889168>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
print(a1.__dict__) # {'b': 1}
__class__
属性
获取当前对象所属的类。
class A(object):
a = 0
def __init__(self):
self.b = 1
a1 = A()
print(a1.__class__) # <class '__main__.A'>
__bases__
属性
获取一个类直接继承的所有父类,返回的是一个元组。
class A(object):
a = 0
def __init__(self):
self.b = 1
class B(A):
pass
a1 = A()
print(B.__bases__) # (<class '__main__.A'>,)
继承
python中的类可以继承一个或者继承多个父类,继承类被称之为派生类或者子类,被继承的类是父类,也可以称之为基类或超类。
注:python中所有的类都默认继承object类。
单继承
单继承语法:
class A:
pass
# B继承A
class B(A):
pass
示例:
class Animal(object):
def __init__(self):
self.name = "tom"
def eat(self):
print('%s is eating' % self.name)
def drink(self):
print('%s is drinking' % self.name)
def sleep(self):
print('%s is sleeping' % self.name)
class Cat(Animal):
def eat_fish(self):
print('%s is eating fish' % self.name)
tom = Cat()
# 调用父类的方法
tom.drink() # tom is drinking
# 调用自己的方法
tom.eat_fish() # tom is eating fish
注: 父类的 __init__()
方法也会被子类继承,如果子类存在 __init__()
方法会覆盖对父类的__init__()
方法的继承
多继承
多继承语法:
class A:
pass
class B:
pass
class C(A, B):
pass
注:当一个类继承多个父类时,默认使用第一个父类的同名属性和方法。
示例:
class Animal(object):
def __init__(self):
self.name = "tom"
def eat(self):
print('%s is eating' % self.name)
def drink(self):
print('%s is drinking' % self.name)
def sleep(self):
print('%s is sleeping' % self.name)
class Human(object):
def __init__(self):
self.name = "zhangsan"
def sleep(self):
print('%s is sleeping' % self.name)
class Cat(Human, Animal):
def eat_fish(self):
print('%s is eating fish' % self.name)
cat1 = Cat()
# 优先继承第一个父类同名的属性和方法
cat1.sleep() # zhangsan is sleeping
子类重写父类同名的属性和方法
如果子类和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候调用的是子类自己的属性和方法。
示例:
class Animal(object):
def __init__(self):
self.name = "tom"
def eat(self):
print('%s is eating' % self.name)
class Cat(Animal):
def __init__(self):
self.name = "small tom"
def eat(self):
print('%s is eating' % self.name)
def eat_fish(self):
print('%s is eating fish' % self.name)
cat1 = Cat()
cat1.eat() # small tom is eatingss
拓展:查看一个类的继承关系 类名.__mro__
print(Cat.__mro__) # (<class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>)
子类调用父类同名的属性和方法
class Animal(object):
def __init__(self):
self.name = "tom"
def eat(self):
print('%s is eating' % self.name)
class Cat(Animal):
def __init__(self):
self.name = "small tom"
def eat(self):
# 如果先调用了父类的属性和方法,父类的属性和方法会覆盖子类的属性,所以这里需要调用子类自己的init初始化
self.__init__()
print('%s is eating' % self.name)
def eat_fish(self):
print('%s is eating fish' % self.name)
def eat_func(self):
# 调用父类的同名方法和属性之前,需要调用父类的init方法
Animal.__init__(self)
Animal.eat(self)
cat1 = Cat()
cat1.eat() # small tom is eating
cat1.eat_func() # tom is eating
cat1.eat() # small tom is eating
# 如果Cat类的eat方法中没有调用init则这里调用的是父类的eat方法
# cat1.eat() # tom is eating
super()
除了上述方式调用父类同名的属性和方法之外,Python还提供了 super()
函数来调用父类的属性和方法。
语法:
# 方式1
super(子类名, self).方法名()
# 方式2
super().方法名()
示例:
class Animal(object):
def __init__(self):
self.name = "tom"
def eat(self):
print('%s is eating' % self.name)
class Cat(Animal):
def __init__(self):
self.name = "small tom"
def eat(self):
print('%s is eating' % self.name)
def eat_func(self):
# 方式1: super(子类名, self).方法名()
# super(Cat, self).__init__()
# super(Cat, self).eat()
# 方式2: super().方法名()
super().__init__()
super().eat()
cat1 = Cat()
cat1.eat_func() # tom is eating
私有属性和私有方法
定义私有属性和方法
如果某些属性和方法不希望被外部访问,可以将这些属性和方法设置成私有的,在Python中,可以在属性和方法名前面加上两个__
来阻止外部访问。
示例:
class Animal(object):
def __init__(self):
self.name = "tom"
self.age = 20
self.__money = 10000
def eat(self):
print('%s is eating' % self.name)
def __info(self):
print('这是私有方法!')
class Cat(Animal):
def eat(self):
print('%s is eating' % self.name)
cat1 = Cat()
print(cat1.age) # 20
# AttributeError: 'Cat' object has no attribute 'money'
# print(cat1.__money)
# AttributeError: 'Cat' object has no attribute '__info'
# cat1.__info()
获取和修改私有属性
class Animal(object):
def __init__(self):
self.name = "tom"
self.age = 20
self.__money = 10000
# 获取私有属性
def get_money(self):
return self.__money
# 设置私有属性
def set_money(self):
self.__money = 100
class Cat(Animal):
def eat(self):
print('%s is eating' % self.name)
cat1 = Cat()
print(cat1.get_money()) # 10000
cat1.set_money()
print(cat1.get_money()) # 100
@Property装饰器
Python内置的@property
装饰器可以把一个方法当成属性调用。
示例1:
class People:
def __init__(self, height, weight):
self.height = height
self.weight = weight
@property
def info(self):
return self.weight / (self.height ** 2)
p1 = People(1.8, 70)
# 加了@property后,可以用调用属性的形式来调用方法,不可以在使用括号的方式调用
print(p1.info)
示例2:
实现某些属性不能随意的修改。
class People:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self, val):
if type(val) is not str:
raise TypeError("请传入str类型")
self.__name = val
@name.deleter
def name(self):
print("不允许删除")
p1 = People("tom")
print(p1.name) # tom
p1.name = "jerry"
print(p1.name) # jerry
del p1.name # 不允许删除
多态
多态是使用对象的一种方式,一般存在继承关系中,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。
class Dog(object):
def work(self):
pass
class SmallDog(Dog):
def work(self):
print('small dog run...')
class BigDog(Dog):
def work(self):
print('big dog run...')
class Person(object):
def work_dog(self, dog):
dog.work()
s_dog = SmallDog()
b_dog = BigDog()
p1 = Person()
p1.work_dog(s_dog) # small dog run...
p1.work_dog(b_dog) # big dog run...
反射
反射可以获取类型的信息。反射有常见的四个方法:hasattr、getattr、setattr、delattr。
hasattr()
判断对象中是否有指定的属性或方法。
class Person:
address = "北京"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print("this is func")
p1 = Person("tom", 20)
# 第二个参数是字符串形式的属性或方法
print(hasattr(p1, "name")) # True
print(hasattr(p1, "age")) # True
print(hasattr(p1, "func")) # True
print(hasattr(p1, "address")) # True
getattr()
获取对象指定的属性或方法。
getattr(object, name, default=None)
- object: 对象名
- name: 字符串形式的属性或方法
- default: 默认是None,如果设置了该参数,当没有指定的属性或方法时,会返回该参数设置的值。否则会报错。
示例:
class Person:
address = "北京"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print("this is func")
p1 = Person("tom", 20)
print(getattr(p1, "name")) # tom
print(getattr(p1, "address")) # 北京
f = getattr(p1, "func")
print(f) # <bound method Person.func of <__main__.Person object at 0x000001D969517608>>
f() # this is func
# 没有gender,也没有设置default参数,所以会报错
# print(getattr(p1, "gender")) # 'Person' object has no attribute 'gender'
# 设置了default参数,会返回设置的值
print(getattr(p1, "gender", "男")) # 男
setattr()
为对象添加属性或方法。
def abc(self):
print("名字是%s"%self.name)
class Person:
address = "北京"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print("this is func")
p1 = Person("tom", 20)
# 添加属性
setattr(p1, "gender", "女")
print(p1.__dict__) # {'name': 'tom', 'age': 20, 'gender': '女'}
# 添加方法
setattr(p1, "test_abc", abc)
p1.test_abc(p1) # 名字是tom
delattr()
删除对象中的属性,不能删除方法。
class Person:
address = "北京"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print("this is func")
p1 = Person("tom", 20)
delattr(p1, "name")
print(p1.__dict__) # {'age': 20}
# AttributeError: func
delattr(p1, "func")
从类的角度
class A:
address = "北京"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print("func A")
if hasattr(A, "address"):
print(getattr(A, "address"))
if hasattr(A, "func"):
obj = A("tom", 20)
getattr(obj, "func")()
getattr(A, "func")(obj)
从模块的角度
my_module.py
如下
name = "jerry"
def func():
print("my module func")
class A:
address = "北京"
def __init__(self, name):
self.name = name
def func(self):
print("class A func")
其他模块导入my_module
如下:
import my_module
# print(getattr(my_module, "name"))
# getattr(my_module, "func")()
# 找到my_module下的C类,实例化一个对象
obj1 = getattr(my_module, "A")("tom")
# 找到my_module下的C类,通过反射获取address
print(getattr(my_module.A, "address"))
# 找到my_module下的C类,实例化一个对象,进行反射操作
obj2 = getattr(my_module, "A")("tom")
print(obj2.name)
print(getattr(obj2, "name"))
内置函数isinstance和issubclass
isinstance()
判断一个对象是否是一个已知的类型,判断的是对象和类的关系。
class A:
pass
class B(A):
pass
objB = B()
# 判断对象与类的关系
print(isinstance(objB, B)) # True
print(isinstance(objB, A)) # True
isinstance() 与 type() 区别:
- type() 不会认为子类是一种父类类型,不会考虑继承关系。
- isinstance() 会认为子类是一种父类类型,会考虑继承关系。
issubclass()
判断一个类是否是另一个类的子类。
class A:
pass
class B(A):
pass
class C(B):
pass
# 判断类与类的关系
print(issubclass(B, A)) # True
print(issubclass(C, A)) # True