Python--面向对象

一、基本概念

类(class):用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法;
对象:对象是类的实例,例如:人是一个类,小明是一个人,类的一个特例;
实例变量:通过构造方法初始化的属性,必须实例化之后才能使用,与实例绑定;
类变量:定义在类中的变量,不需要实例化就可以使用,与类绑定;
成员方法:类中定义的函数;
类方法:通过装饰器@classmethod定义的函数,与类变量类似;
静态方法:通过装饰器@staticmethod定义的函数,因为没有第一个初始参数,所以不能访问类的成员变量和成员方法;
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫做方法的覆盖(override),也称为方法的重写;
继承:指一个派生类(Derived Class)继承基类(Base Class)的成员变量和成员方法。继承也允许把一个派生类的对象作为一个基类对象对待。


二、类

2.1、类的定义

语法

class [类名]:
	[语法块]

程序示例

class EmptyClass:
	pass

2.2、类的使用

使用类之前需要实例化列,类实例化后会成为对象,创建对象和创建变量类似,需要先声明对象是哪个类,同时指明变量名称。

class EmptyClass:
	pass

empty = EmptyClass()
print(type(empty))

2.3、类的构造方法

在创建实例时,很多类可能需要有特定的初始状态,所以一个类可以定义一个特殊的方法,叫做构造函数。在Python中,构造函数就是类的__init__(self)(注意双下划线)方法。

class Dog:
	def __init__(self):
		print("汪汪汪!");

dog = Dog()

注意

  • 当一个类定义了__init__方法,类在实例化时会自动调用__init__方法,用于创建新的类实例;
  • 在Python中,除了静态方法和类方法外,所有方法第一个参数都是"self",不能漏掉;
  • 第一个参数"self"指的是实例本身,相当于C++中的"this"指针;
  • 构造方法的返回值必须是"None",否则虽然解释时不报错,但是实例化的时候会报错;

2.4、类中的属性

在构造方法中可以初始化一些属性,例如:

class Dog:
	def __init__(self, name):
		self.name = name
		self.age = 3

dog = Dog("旺财")

print(dog.name)
print(dog.age)

注意

  • 属性必须用self加点的方式赋值,不能直接定义变量。直接定义变量的生命周期只会在函数内,函数执行完变量就会被销毁;

2.5、类中的方法

在类中定义的函数称之为方法,例如:

class Dog:
    def __init__(self, name):
        self.name = name

	def play(self):
		print("汪汪汪!我是",self.name)

dog = Dog("旺财")
dog.play()

注意

  • 类中的方法和函数定义的方法基本相同,但是方法必须要定义在类中,并且第一个参数必须是"self";

2.6、私有属性

在构造函数中定义了属性,实例可以轻松地获取和修改属性的值。但是有时候我们需要限定实例随意地修改属性,这时候就要用到私有属性。
定义私有属性只需要在定义属性名字的时候使用双下划线开头即可,Python解释器就人为这个属性是私有的,外部不能随便访问这个属性。

class Dog:
    def __init__(self, name):
        self.__name = name

	def play(self):
		print("汪汪汪!我是",self.__name)

dog = Dog("旺财")
dog.play()

# 错误,私有属性不能用对象访问,需要通过成员方法访问
print(dog.__name)

私有属性常用于限制用户随意修改属性值,而需要遵循成员方法定下的规矩修改,例如:

class Dog:
    def __init__(self, name):
        self.__name = name
        self.__age = None
        print(self.__name,"生成成功")

    def set_age(self, age):
        if not isinstance(age,int):
            print("输入的年龄必须是数字")
            return False
        if age <=0:
            print("年龄必须大于0!")
            return False
        self.__age = age

    def play(self):
        print("汪汪汪!我今年", self.__age, "岁")


dog = Dog("旺财")
dog.set_age("Hello")
dog.set_age(-20)
dog.set_age(3)
dog.play()

在这里插入图片描述

在这个例子中,__age是私有属性,实例化后只能通过set_age方法设置年龄。在set_age方法中,我们限制了__age只能是int,并且其值要大于0,有效地限制了实例化后数据的内容,保证了__age是一个有效可用的数据。


2.7、私有方法

私有方法和私有属性类似,只能在类内部被调用,实例不能直接调用,私有方法的定义同样是以双下划线作为方法名的开头

class Dog:
    def __init__(self, name):
        self.__name = name
        self.__age = None
        print(self.__name,"生成成功")

    def set_age(self, age):
        if not isinstance(age,int):
            print("输入的年龄必须是数字")
            return False
        if age <=0:
            print("年龄必须大于0!")
            return False
        self.__age = age
	
	def __test(self):
		print("这是一个私有方法")
		print("只能在类内部调用")
		print("对象无法调用")

    def play(self):
        print("汪汪汪!我今年", self.__age, "岁")


dog = Dog("旺财")
dog.set_age(3)
dog.play()

# 错误,不能通过对象调用私有方法
dog.__test();

三、继承

继承,是一种对类进行分层级划分的概念。继承的基本思想是在一个类的基础上制定出一个新的类,这个新的类不仅可以继承原来类的属性和方法,还可以增加新的属性和方法。原来的类称为父类,新的类称为子类。

语法

class Animal:
	pass

class Dog(Animal):
	pass

class Cat(Animal):
	pass

定义要从哪个类继承,只需要在定义子类的名字后面的括号中填入父类名字,如果有多个父类,则用逗号,隔开。

注意

  • 在继承中,如果子类定义了构造方法,则父类的构造方法__init__不会被自动调用,需要在子类的构造函数中专门调用:super(Dog, self).__init__("旺财")
  • 子类不能继承父类中的私有方法,也不能调用父类的私有方法;

四、多态

继承可以帮助我们重复使用代码,但是有时候子类的行为不一定完全和父类一样,例如:

class Animal:
	def say(self):
		print("Animal")

class Dog(Animal):
	pass

class Cat(Animal):
	pass

dog = Dog()
dog.say()

cat = Cat()
cat.say()

# 输出
# Animal
# Animal

我们的目的是想让DogCat在调用say方法是输出不同的内容,狗应该“汪汪汪!”,猫应该“喵喵喵”,可以用过重写(覆盖)父类方法来实现:

class Animal:
	def say(self):
		print("Animal")

class Dog(Animal):
	def say(self):
		print("汪汪汪!")

class Cat(Animal):
	def say(self):
		print("喵喵喵")

dog = Dog()
dog.say()

cat = Cat()
cat.say()

# 输出
# 汪汪汪!
# 喵喵喵

多态:当子类和父类存在相同的方法时,子类的方法会覆盖父类的方法,这样代码在运行时总会调用子类的方法,这就是多态。多态的意思就是多种形态,多态意味着即使不知道变量所引用的对象是什么类型,也能对对象进行操作,对象会根据类的不同而表现出不同的行为。

判断是不是某个对象,可以使用isinstance(对象, 类)函数,例如:isinstance(dog, Dog),是则返回True,否则返回False;

子类对象既是子类对象,又是父类对象,所以常用父类对象作为函数形参,这样可以实现不修改函数就能直接被子类使用,例如:

class Animal:
	def say(self):
		print("Animal")
	
class Dog(Animal):
	def say(self):
		print("汪汪汪!")
		
class Cat(Animal):
	def say(self):
		print("喵喵喵")
	
def animal_say(animal:Animal):
	animal.say()

dog = Dog()
cat = Cat()

animal_say(dog)
animal_say(cat)

# 输出
# 汪汪汪!
# 喵喵喵

五、鸭子类型

在程序设计中,鸭子类型(Duck Typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口决定的,而是由当前方法和属性的集合决定的。

在鸭子类型中,我们关注的不是对象的类型本身,而是它如何使用。例如:

在不使用鸭子类型的语言中,我们可以编写一个函数,使它接受一个为鸭子的对象,并调用它的“走和叫”方法;

在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的“走和叫”方法;
如果这些需要被调用的方法不存在,那么将引发一个运行时的错误。任何拥有这样正确的“走和叫”方法的对象都可以被函数接受。

例如:

class Dog:
	def say(self):
		print("汪汪汪!")
		
class Cat:
	def say(self):
		print("喵喵喵")
	
def animal_say(animal):
	animal.say()

dog = Dog()
cat = Cat()

animal_say(dog)
animal_say(cat)

在这个例子中,DogCat并没有从Animal继承下来,但是都各自实现了say方法,这也是多态的一种实现方式。因为Python是一门动态语言,在函数没有被执行的时候,程序并不能断定数据的类型(虽然可以用函数注释做限制,但是这并不是强制性的),只有执行到相关的语句时才真的去调用相关的方法。虽然我们没有使用“继承”,但是仍然可以实现多态。


六、类变量和实例变量

实例变量是在构造方法中初始化的属性,实例变量必须实例化之后才能使用,相当于绑定在实例上;
类变量是定义在类中的变量,不需要实例化就能直接使用,相当于绑定在类上;

注意

  • 类变量也可以被实例调用,但是实例不能修改类变量,如果实例对类变量进行修改,Python解释器会新建一个同名的成员变量来代理实例中的类变量;
class Dog:

	# 类变量
    a = 10
    
    def __init__(self, name):
    	# 实例变量
        self.__name = name
        self.__age = None
        print(self.__name,"生成成功")

    def set_age(self, age):
        if not isinstance(age,int):
            print("输入的年龄必须是数字")
            return False
        if age <=0:
            print("年龄必须大于0!")
            return False
        self.__age = age

    def play(self):
        print("汪汪汪!我今年", self.__age, "岁")


print(Dog.a)
dog = Dog("旺财")
print(dog.a)

七、静态方法与类方法

静态方法和类变量有点类似,静态方法在定义类时就已经被分配定义好了。静态方法并不绑定类也不绑定实例,相当于给方法添加一个前缀。定义静态方法将引入一个新的概念 – 装饰器。

7.1、静态方法

class Animal:
	name = "动物"
	
	# 注意,装饰器和函数定义之间不能有空行
	@staticmethod
	def play():
		print("playing")


Animal.play()

注意

  • 定义静态方法的语法就是在定义函数的上面一行(不能有空行)添加一句@staticmethod
  • 静态方法不再有第一个默认参数self,所以静态方法本身也不能调用成员变量和成员方法;
  • 静态方法不需要实例化之后使用,和类变量一样直接使用即可,其他的和一般函数没有任何区别;

7.2、类方法

类方法,就是该方法绑定在定义的类上面,而不是绑定在实例上。

class Animal:
	name = "动物"

	# 注意,装饰器和函数定义之间不能有空行
	@classmethod
	def play(cls):
		print(cls.name, "playing")

Animal.play()

注意

  • 定义静态方法的语法就是在定义函数的上面一行(不能有空行)添加一句@classmethod
  • 和静态方法不同的是,类方法和成员方法一样都有一个初始的参数,但是这个参数不同于成员方法;
  • 成员方法的第一个参数指向的是实例,而类方法指向的则是定义的类本身,所以类方法可以读取和修改类变量;
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝勒里恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值