Python
基础
面向对象
面向对象基础
类和对象
类
类
是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念。例如:飞机的图纸。
特征:属性
行为:方法
对象
对象
是类创建出来的真实存在的事物,例如:某架飞机。
实例
一般创建对象也叫实例化对象,即为一个实例
。但有一种抽象对象,创建出的对象不是实例。
创建类和对象
创建类
def ClassName():
pass
# 一般使用大驼峰命名。
PEP8中规范:
类名一般使用首字母大写的约定。
在接口被文档化并且主要被用于调用的情况下,可以使用函数的命名风格代替。
注意,对于内置的变量命名有一个单独的约定:大部分内置变量是单个单词(或者两个单词连接在一起),首字母大写的命名法只用于异常名或者内部的常量。
例:
class Washer():
def wash(self):
print("洗衣机洗衣服")
上例也定义了一个方法
,方法的定义与函数基本相同。
创建对象
obj_name = ClassName()
例:
# 定义一个类
class Washer():
def wash(self):
print("洗衣机洗衣服")
# 创建对象
haier = Washer()
# 对象调用实例方法
haier.wash()
#输出
洗衣机洗衣服
self
self
指的是调用该函数的对象,一般打印为内存地址。
对象不同,即内存地址不同,即self不同。
# 定义类
class Washer():
def wash(self):
print("洗衣机洗衣服")
print(self)
# 创建2个对象
haier = Washer()
geli = Washer()
# 分别调用实例方法
haier.wash()
geli.wash()
#输出
洗衣机洗衣服
<__main__.Washer object at 0x000002264128BB20>
洗衣机洗衣服
<__main__.Washer object at 0x000002264128BB50>
属性
类外添加属性
obj_name.attribute = value
例:
# 使用上述Washer类
# 创建一个对象
haier = Washer()
haier.width = 500
haier.height = 800
类外获取属性
obj_name.attribute
例:
# 使用上述Washer类
# 使用上述haier实例和属性
print(haier.width)
print(haier.height)
#输出
500
800
类内获取对象属性
# 定义类
class Washer():
def print_info(self):
# 类里面获取实例属性
print(self.width)
print(self.height)
# 创建对象
haier1 = Washer()
# 添加实例属性
haier1.width = 500
haier1.height = 800
haier1.print_info()
#输出
500
800
魔法方法
_init_()
__init__()
方法可以初始化属性。上述属性都是在类外定义的, 这个魔法方法可以让属性在类内初始化定义。
例:
# 定义一个类
class Washer():
def __init__(self,width,height):
self.width = width
self.height = height
def print_info(self):
print(self.width)
print(self.height)
# 创建一个对象,并使用实例方法
haier = Washer(500,800)
haier.print_info()
# 输出
500
800
# 不接受参数的初始化属性
class Washer():
def __init__(self):
self.width = 500
self.height = 800
_str_()
通常用print打印对象的时候,会打印其内存地址。如果使用__str__()
方法,可以打印该方法中返回的数据。
例:
# 定义一个没有__str__方法的类
class Washer():
def __init__(self):
self.width = 500
# 创建一个对象
haier = Washer()
# 打印这个对象
print(haier)
# 输出
<__main__.Washer object at 0x0000014A5051BFA0>
# 定义一个有__str__方法的类
class Washer():
def __init__(self):
self.width = 500
def __str__(self):
return "这是一个洗衣机"
# 创建一个对象
haier = Washer()
# 打印这个对象
print(haier)
# 输出
这是一个洗衣机
_del_()
当删除一个对象是,Python解释器会默认调用__del__()
方法。
例:
# 定义一个没有__del__方法的类
class Washer():
pass
# 创建一个对象
haier = Washer()
# 删除这个对象
del haier
# 定义一个有__del__方法的类
class Washer():
def __del__(self):
print("该对象已经被删除")
# 创建一个对象
haier = Washer()
# 删除这个对象
del haier
# 输出
该对象已经被删除
继承
继承
继承
继承通常为子女继承父母的财产。在面向对象编程中为子类
继承父类
的属性和方法。
新式类和旧式类
旧式类,或称经典类。不由任意内置类型派生出的类。已经被Python3.0以后的版本淘汰。
class ClassName():
pass
新式类,继承自object类。object
类为基类
。子类也叫做派生类
。
class ClassName(object):
pass
# Pyhton3.0以后的版本,默认继承object类,不写也会继承。
单继承和多继承
单继承
子类只继承一个父类,该种继承为单继承
。
例:
# 模拟一家有一个面条技术
# 定义一个父类
class Father(object):
def __init__(self):
self.recipe = "祖传面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义一个子类
class Son(Father):
pass
# 使用子类创建一个对象,并调用父类方法和属性
jachin = Son()
print(jachin.recipe)
jachin.make_noodles()
#输出
祖传面条配方
使用祖传面条配方制作面条
多继承
一个子类继承了多个父类,为多继承
。
# 模拟一家有一个祖传面条配方
# 儿子还在学校外学了一个面条配方
# 定义父亲父类
class Father(object):
def __init__(self):
self.recipe = "祖传面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义学校父类
class School(object):
def __init__(self):
self.recipe = "通用面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义一个子类
class Son(School,Father):
pass
# 使用子类创建一个对象,并调用父类方法和属性
jachin = Son()
print(jachin.recipe)
jachin.make_noodles()
# 继承多个父类,遇见同名属性和方法。
# 会默认调用第一个父类的属性和方法。
# 输出
通用面条配方
使用通用面条配方制作面条
继承多个父类,遇见同名属性和方法,会默认调用第一个父类的属性和方法。
重写父类同名属性和方法
子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。
# 模拟一家有一个祖传面条配方
# 儿子还在学校外学了一个面条配方
# 现在儿子将两个配方研究,创造了自己独创的秘方。
# 定义父亲父类
class Father(object):
def __init__(self):
self.recipe = "祖传面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义学校父类
class School(object):
def __init__(self):
self.recipe = "通用面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义一个子类
class Son(School,Father):
def __init__(self):
self.recipe = "独创面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 使用子类创建一个对象,并调用父类方法和属性
jachin = Son()
print(jachin.recipe)
jachin.make_noodles()
#输出
独创面条配方
使用独创面条配方制作面条
__mro__属性
__mro__
属性可以查看该对象所属类的继承关系。该算法用拓扑排序
构成。
class X(object):pass
class Y(object):pass
class A(X, Y):pass
class B(Y):pass
class C(A, B):pass
print(C.__mro__)
#输出
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.B'>, <class '__main__.Y'>, <class 'object'>)
调用父类同名属性和方法
如果子类仍然想调用父类的方法,可以重新写一个方法,让该方法调用父类的方法。但要注意,调用父类的属性则需要用父类重新初始化。
# 模拟一家有一个祖传面条配方
# 儿子还在学校外学了一个面条配方
# 现在儿子将两个配方研究,创造了自己独创的秘方。
# 儿子目前会三种配方,顾客需要哪个就用哪个。
# 定义父亲父类
class Father(object):
def __init__(self):
self.recipe = "祖传面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义学校父类
class School(object):
def __init__(self):
self.recipe = "通用面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义一个子类
class Son(School,Father):
def __init__(self):
self.recipe = "独创面条配方"
def make_noodles(self):
self.__init__()
print("使用"+self.recipe+"制作面条")
def make_father_noodles(self):
Father.__init__(self)
Father.make_noodles(self)
def make_school_noodles(self):
School.__init__(self)
School.make_noodles(self)
# 使用子类创建一个对象,并调用父类方法和属性
jachin = Son()
print(jachin.recipe)
jachin.make_noodles()
jachin.make_father_noodles()
jachin.make_school_noodles()
# 输出
独创面条配方
使用独创面条配方制作面条
使用祖传面条配方制作面条
使用通用面条配方制作面条
super()
上条调用父类的属性和方法虽然能实现,但是如果更改父类的类名,便需要大量修改代码,造成了代码的冗余。并且,当出现多继承时,都调用父方法,会出现钻石继承
的问题。
故可以使用super()
函数减少冗余。
super()若不传入参数,便会根据__mro__
属性的顺序选择第一个有相同方法的父类进行方法调用。
super()若传入参数,第一个参数为自己或一个父类名,第二个参数为self
。若选择一个父类名,那么调用顺序就从__mro__
属性中找到该父类名,按顺序从它下一个类开始选择。
例:
# 模拟一家有一个祖传面条配方
# 儿子还在学校外学了一个面条配方
# 现在儿子将两个配方研究,创造了自己独创的秘方。
# 儿子目前会三种配方,顾客需要哪个就用哪个。
# 定义父亲父类
class Father(object):
def __init__(self):
self.recipe = "祖传面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义学校父类
class School(object):
def __init__(self):
self.recipe = "通用面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
# 定义一个子类
class Son(School,Father):
def __init__(self):
self.recipe = "独创面条配方"
def make_noodles(self):
self.__init__()
print("使用"+self.recipe+"制作面条")
def make_father_noodles(self):
super(School,self).__init__()
super(School,self).make_noodles()
def make_school_noodles(self):
super().__init__()
super().make_noodles()
# 使用子类创建一个对象,并调用父类方法和属性
jachin = Son()
print(jachin.recipe)
jachin.make_father_noodles()
jachin.make_school_noodles()
# 输出
独创面条配方
使用祖传面条配方制作面条
使用通用面条配方制作面条
多层继承
多层继承就是子类的子类可以继承祖先的属性和方法。
# 模拟一家餐馆,爷爷创立门派。
# 父亲,孙子都继承了爷爷的能力。
class Grandfather(object):
def __init__(self):
self.recipe = "祖传面条配方"
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
class Fahter(Grandfather):
pass
class Son(Fahter):
pass
# 利用Son创建一个对象
jachin = Son()
jachin.make_noodles()
# 输出
使用祖传面条配方制作面条
私有属性和私有方法
定义私有属性和私有方法
Python中,设置私有属性和私有方法,可让父类有些属性和方法可以不继承给子类。
设置私有权限的方法:在属性名和方法名前加上两个下划线__
class Grandfather(object):
def __init__(self):
self.recipe = "祖传面条配方"
self.__private_assets = "200000000RMb"
def __private_noodle(self):
print("不可传")
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
class Fahter(Grandfather):
pass
# 利用Son创建一个对象
jachin = Fahter()
print(jachin.__private_assets)
# 输出
发生异常:
'Fahter' object has no attribute '__private_assets'
jachin.__private_noodle()
# 输出
发生异常:
'Fahter' object has no attribute '__private_noodle'
私有属性和私有方法只能在类里面访问和修改。
获取和修改私有属性值
在Python中,习惯使用定义方法名get_xx用来获取私有属性,定义set__xx用来修改私有属性。
class Grandfather(object):
def __init__(self):
self.recipe = "祖传面条配方"
self.__private_assets = "200000000RMb"
def get_private_assets(self):
return self.__private_assets
def set_private_assets(self,money):
self.__private_assets = money
def __private_noodle(self):
print("不可传")
def make_private_noodle(self):
print("我现在偷偷给你说")
self.__private_noodle()
def make_noodles(self):
print("使用"+self.recipe+"制作面条")
class Father(Grandfather):
pass
# 利用Father创建一个对象
jachin = Father()
jachin.set_private_assets("30RMB")
print(jachin.get_private_assets())
jachin.make_private_noodle()
# 输出
30RMB
我现在偷偷给你说
不可传
多态
多态
多态指的是一类事物有多种形态。
多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果
使用方法
class Animal(object):
def calls(self):
pass
class Dog(Animal):
def calls(self):
print("bark")
class Bee(Animal):
def calls(self):
print("buzz")
class Bird(Animal):
def calls(self):
print("tweet")
class Person(object):
def play_with_animal(self,animal):
animal.calls()
huahua = Dog()
jiji = Bee()
tutu = Bird()
jachin = Person()
jachin.play_with_animal(huahua)
jachin.play_with_animal(jiji)
jachin.play_with_animal(tutu)
# 输出
bark
buzz
tweet
类属性和实例属性
类属性
设置类属性
类属性
就是类对象
所拥有的属性,它被该类的所有实例对象所共有。
类属性可以使用类对象
或实例对象
访问。
因此,当需要记录某项数据需要保存一致时,则定义类属性。
实例属性
要求每个对象为其开辟一份独立的内存空间来记录数据,但类属性
为全类所共有,改一份,全类都会被改。
class Dog(object):
feet = 4
xiaotianquan = Dog()
xiaomei = Dog()
print(Dog.feet)
print(xiaotianquan.feet)
print(xiaomei.feet)
# 输出
4
4
4
修改类属性
类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性, 表示的是为该实例对象创建了一个实例属性。
class Dog(object):
feet = 4
xiaotianquan = Dog()
xiaomei = Dog()
# 修改类属性
Dog.feet = 2
print(Dog.feet)
print(xiaotianquan.feet)
print(xiaomei.feet)
# 用实例对象修改
xiaotianquan.feet = 3
print(Dog.feet)
print(xiaotianquan.feet)
print(xiaomei.feet)
# 输出
2
2
2
2
3
2
实例属性
实例属性就是通常通过__init__()
魔法方法创建的属性,它不能通过类访问。
类方法和静态方法
类方法
类方法特点
需要使用装饰器@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数。
使用场景
当方法中需要使用类对象
,比如访问私有类属性时,定义类方法。
类方法一般和类属性配合使用。
class Dog(object):
__feet = 4
@classmethod
def get_feet(cls):
return cls.__feet
xiaotianquan = Dog()
print(xiaotianquan.get_feet())
# 输出
4
静态方法
静态方法特点
- 需要通过装饰器
@staticmethod
来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。 - 静态方法 也能够通过
实例对象
和类对象
去访问。
使用场景
- 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
- 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
class Dog(object):
@staticmethod
def info_print():
print('这是一个狗类,用于创建狗实例....')
wangcai = Dog()
# 静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print()
Dog.info_print()
# 输出
这是一个狗类,用于创建狗实例....
这是一个狗类,用于创建狗实例....