首页 > 编程语言 >PYTHON 面向对象

PYTHON 面向对象

时间:2022-12-06 12:23:42浏览次数:33  
标签:__ PYTHON self class 面向对象 Animal age def

1.1 面向对象

三个基本特性:

  • 封装性(隐藏了内部细节,只保留有限的对外接口)
  • 继承性(代码的复用,父类(一般类,超类),子类(特殊类,派生类))
  • 多态性(子类继承父类,具有不同的状态或表现行为,即重写父类方法)

1.2 类和对象

类就是数据类型,封装了一类对象的数据和操作。

1.2.1 定义类

class 类名 (父类):
	类体

类名首字母大写,父类可以省略(默认继承object类)

class Animal(object):
    pass

class Animal: # 可以省略父类
    pass

1.2.2 创建对象

类实例化可生成对象,对象也称为实例。对象的生命周期包括创建,使用,销毁。由于有垃圾回收,所以一般不需要负责对象的销毁。

对象名 = 类(参数...)
class Animal(object):
    pass

a = Animal()  
print(a) # <__main__.Animal object at 0x0000021A2F913190>

打印的信息是调用了对象的__str()__方法,如果想要打印自己的信息,可以重写这个方法。

class Animal(object):
    def __str__(self):
        return "我是基类Animal对象"

a = Animal()
print(a) 

1.2.2 类的成员

类成员包括:

  • 成员变量
    • 实例(对象)变量
    • 类变量
  • 属性:
    • 属性指的是attribute(类中保存的数据变量)
    • getter,setter读写访问器,对于读写访问器python提供了property实现。
    • 有些书中把attribute称为成员变量或字段,把property称为属性
  • 成员方法
    • 实例方法
    • 类方法
    • 静态方法

注意:很多书中写的变量,属性,字段都是同一个事物的不同叫法。

1.2.3 实例变量

实例变量就是每个实例特有的数据。

class Animal(object):
    def __init__(self,name,sex,age):
        self.name = name  # 定义实例变量:self.name
        self.sex = sex
        self.age = age

    def __str__(self):
        return "name:{}, sex:{}, age:{}".format(self.name,self.sex,self.age)

a = Animal("小白",'男',2)
print(a)

其中:__init__(self) 是构造函数,用于初始化类的,这个方法名称是固定的。

self放在第一个位置,表示当前类的对象,就是当前正在创建的对象。在创建类的实例对象时不需要手动指定。

self.name 表示对象中的实例变量,即self对象里的变量。

1.2.3.1 访问实例变量

# 读:对象名.实例变量  
# 写:对象名.实例变量 = 值
a.name = "小黑"
print(a.name)

1.2.4 类变量

类变量是属于类本身的,所有实例对象共享这个变量。

  • 定义位置在类中(不在构造函数中)
  • 访问:类名.类变量名
class Animal(object):
    count = 0  # 在这儿定义,不要在构造函数中定义

    def __init__(self):
        Animal.count += 1


a = Animal()
print(Animal.count) # 1
b = Animal()
print(Animal.count) # 2

注意:

不要用 对象名.类变量 这种方式访问:

  • 它会先在实例中查找这个变量,如果没找到才去类命名空间中去查找。
  • 如果赋值则是创建对象的变量,而不会对类变量进行赋值。这是因为python是动态语言,可以用对象名.实例变量名来添加当前对象的实例变量。

1.2.5 实例方法

实例方法和实例变量一样,都是针对对象本身的。

创建实例方法:

class 类:
    def 方法名(self, 参数...):
        pass

其中self,是用于方法和实例的绑定。

调用实例方法:对象名.实例方法名(参数...)

class Animal(object):
    def __init__(self, age):
        self.age = age

    def age_add(self):  # 定义实例方法
        self.age += 1


a = Animal(3)
print(a.age)  # 3
a.age_add()   # 调用实例方法
print(a.age)  # 4

1.2.6 类方法

类方法属于类,不与实例绑定,但需要与类绑定。定义的第一个参数不是self,而是类的type实例,type是描述数据类型的类。python中所有的数据类型都是type的一个实例。

定义与访问:

class 类:
    @classmethod
    def 类方法名(cls, 参数...)
    	在类的内部访问类变量和类方法:
        cls.类变量
        cls.类方法()
    	pass
    
访问:
类.类方法名(参数)

其中 @classmethod 是固定的,使用装饰器声明该方法是类方法。

class Animal(object):
    count = 0

    @classmethod
    def modify_count(cls, value):
        print(cls) # <class '__main__.Animal'>
        print(type(cls)) # <class 'type'>
        cls.count = value  # cls就是Animal类


a = Animal()
Animal.modify_count(5)

注意:在类方法中,只能访问类变量和类方法,不能访问实例成员。

1.2.7 静态方法

静态方法不与实例绑定,也不与类绑定,就是把类用于它的的命名空间。

定义与访问:

class 类:
    @staticmethod
    def 静态方法名(参数):
        pass
访问:
类名.静态方法名(参数...)

@staticmethod 是装饰器,约束这个方法是静态方法。

class Animal(object):
    @staticmethod
    def add(a, b):
        print("动物计算器:{}+{}={}".format(a, b, a + b))


Animal.add(3,5) # 动物计算器:3+5=8

强调:

在一个类中定义静态方法只是为了提供一个基于类名的命名空间。

1.3 类的访问权限

类内的属性可以让外部引用称为公有(public)属性,而方法称为公有方法。

缺点:外部可以随意修改内部的属性值,数据不安全。

python提供私有属性与方法,禁止外部直接访问。

1.3.1 私有变量

在名称前加两个下划线,表示这是一个私有属性:

class Animal(object):
    def __init__(self):
        self.__private_var = 5
    
a  =Animal()
print(a.__private_var)  
# 读取出错:AttributeError: 'Animal' object has no attribute '__private_var'

python没有严格意义的私有方法,实际上python把名字换了:

换成了: _类名__变量名

print(a._Animal__private_var)  # 5

1.3.2 私有方法

同私有变量,就是名前加两个下划线即可。

1.4 定义属性

封装通常是对成员变量进行封装,严格来说应该定义私有变量,之后用getter,setter访问器访问。

把读写变成了函数。

使用getter,setter方法:

class Animal(object):
    def __init__(self):
        self.__age = 0  # 定义私有变量

    # 用getter,setter函数访问这个私有变量
    # getter
    def get_age(self):
        return self.__age

    # setter
    def set_age(self, age):
        # 可添加一些约束
        self.__age = age


a = Animal()
a.set_age(5)
print(a.get_age())

在python中提供了专门的定义getter,setter的装饰器(property)

  • getter -> @property
  • setter -> @属性名.setter

在定义时,要先定义getter, 再定义setter

class Animal(object):
    def __init__(self):
        self.__age = 0

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age > 10:
            print("赋值失败,年龄不能大于10!")
            return
        self.__age = age


a = Animal()
print(a.age) # 访问和变量的语法一样,但内部是一个函数。
a.age = 15
print(a.age)

1.5 继承

继承是面向象语言的基本特性,多态性的前提就是继承性。

1.5.1 继承

可以继承父类的公有成员变量和方法,不能继承私有的。

class 类名(父类):
    def __init__(self,参数...):
        super().__init__(参数...)
        ...

super() 表示父类的实例对象引用

super().__init__(参数) 这是调用父类的构造函数,用于初始化父类。注意这里没有self,因为super()就是父类的self了。

class Animal(object):
    def __init__(self, name, age):
        # 父类中定义了姓名和年龄变量
        self.name = name
        self.age = age


class Dog(Animal):
    def __init__(self, name, age, home):
        super().__init__(name, age)
        # 子类中并没有定义姓名和年龄,但子类继承了父类中的这两个变量
        self.home = home


dog = Dog('小白', 3, '张三')
print("{}{}岁了,是{}家的小狗".format(dog.name, dog.age, dog.home))
# 小白3岁了,是张三家的小狗

可以看出dog.name是访问继承下来的变量。

1.5.2 重写父类方法

父类的方法不能满足子类的需求,可以重写父类的方法。

class 父类:
    def 方法(..):
        pass
class 子类(父类)
	def 方法(..):  # 与父类的方法同名,子类对象调用时调用自己的,而不是继承的。
        pass
class Animal(object):
    def __init__(self):
        pass

    def eat(self):
        print("Animal在吃东西")


class Dog(Animal):
    def __init__(self):
        super().__init__()

    def eat(self):
        #super().eat()   如果需要父类eat方法的功能,可以用super()调用
        print("Dog在吃东西")


dog = Dog()
dog.eat() # Dog在吃东西

1.5.2 多继承

一个子类有多个父类:

  • 多继承会发生冲突,python访问一个成员,先在自己的类中查找,如果没有再从第一个父类中查找,如果没有再找第二个父类……,如果没有再从父类的父类中查找……
class 子类(父类1,父类2,父类3...):
    pass
class F():
    def run(self):
        print("F.run")


class F1(F): 
    def talk(self):
        print("F1.talk")


class F2(F):
    def talk(self):
        print("F2.talk")

    def music(self):
        print("F2.music")


class FF(F1, F2):
    pass

ff = FF()
ff.music()  # F2.music
ff.talk()   # F1.talk 虽然继承了两个talk但查找时按顺序先从父类1中查找。
ff.run()    # F.run

1.6 多态

多态有两个条件:

  • 继承性(一定发生子类与父类之间)
  • 重写父类方法

多态在python中意义不大(因为python是动态语言)。在java等静态语言中:

  • 编译期的变量声明是父类数据类型(因为具体实例化时不知道实例化的是哪种子类型,所以只能声明为父类类型,更具有通用性)。
  • 在运行期由于变量所引用的实例是子类的实例(父类数据类型的变量引用子类实例),实际调用的是子类中的方法。
class Shape:
    def draw(self):
        pass


class Rect(Shape):  # 继承
    def draw(self): #重写父类方法
        print("Rect.draw")


a: Shape = Rect() # 标记为父类变量
print(type(a))    # <class '__main__.Rect'>
a.draw()          # Rect.draw

以java为例进行理解:

package test;

class Shape {
	public void draw() {
		System.out.println("Shape.draw");
	}
}

class Rect extends Shape {
	public void draw() {
		System.out.println("Rect.draw");
	}
}

class Circle extends Shape {
	public void draw() {
		System.out.println("Circle.draw");
	}
}

public class Main {
	
	public static void draw(Shape pen) {
        //pen是一个基类的对象,但分配的实际对象可能是不同的形状
        //这就产生了多态
		pen.draw();
	}

	public static void main(String[] args) {
		draw( new Rect());  //Rect.draw
		draw( new Circle()); //Circle.draw
		
	}
}

1.7 类型检查

python支持多态,可以通过isinstance(obj, type) 来检查对象是不是某个类或父类的实例。

class Shape:
    def draw(self):
        pass


class Rect(Shape):
    def draw(self):
        print("Rect.draw")


a = Rect()
print(isinstance(a,Shape))  # True

1.8 鸭子类型

动态语言的多态意义不大,可以使用“鸭子类型”替代多态性设计。

“鸭子类型”就是多个类具有相同的接口(没有继承),就可以像多态一样应用。

# 虽然没有继承,但仍然可以实现类多态性

class Animal:
    def run(self):
        print("Animal.run")

class Dog:
    def run(self):
        print("Dog.run")

class Car:
    def run(self):
        print("Car.run")

def run(p):
    p.run()

run(Animal())
run(Dog())
run(Car())

'''
Animal.run
Dog.run
Car.run
'''

1.9 根类 object

python中所有类都继承自object类。

其中有两个方法经常用:

__str__()
__eq__(other)

1.9.1 __str__() 方法

打印对象时,对象调用这个方法生成字符串的表示形式(对象的类名,内存地址等信息)

可以重写这个方法实现自己需要的信息。

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def name(self):
        return self.__name

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age < 0:
            raise Exception("年龄非法")
        self.__age = age

    def __str__(self):
        return "Person [ name={}, age={} ]".format(self.name, self.age)


print(Person("张三", 20))  # Person [ name=张三, age=20 ]

1.9.2 __eq__() 方法

当用 ==比较两个对象时,本质上是用对像里面的__eq__()方法比较的。

可以重写比较方法。

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def name(self):
        return self.__name

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age < 0:
            raise Exception("年龄非法")
        self.__age = age

    def __str__(self):
        return "Person [ name={}, age={} ]".format(self.name, self.age)

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

a = Person("张三",10)
b = Person("张三",10)
print(id(a), id(b))
print(a == b)

虽然两个对象的地址不同(不是同一个对象),但他们比较(按姓名和年龄)却相同。

1.10 枚举类

枚举是有限的常量集合

1.10.1定义方法:

class 枚举类(enum.Enum):
    常量...

继承enum.Enum就可以了。

import enum
class Color(enum.Enum):
    BLACK = 1
    WHITE = 2
    GREEN = 3

color = Color.BLACK
print(color)          # Color.BLACK
print(color.value)    # 1
print(color.name)     # BLACK

其中:value是枚举值, name是枚举名

1.10. 2 限制枚举类

枚举类常量值应该是数字,而且不能重复。

  • 继承: enum.IntEnum
  • 用@enum.unique修饰
import enum


@enum.unique
class Color(enum.IntEnum):
    BLACK = 1
    WHITE = 2
    GREEN = 3


# 可以遍历
for i in Color:
    print(i.name, i.value)
    
'''
BLACK 1
WHITE 2
GREEN 3
'''

标签:__,PYTHON,self,class,面向对象,Animal,age,def
From: https://www.cnblogs.com/three-sheep/p/16954875.html

相关文章

  • python基础-异常处理
    1.异常与异常处理  异常就是程序中的错误,正常情况下程序是自上而下逐行执行的,当遇到异常时,就会报错退出执行;  异常处理就是在程序中可能出错的地方进行提前预捕获,并......
  • Python编程中,在 Eclipse 中使用 P8 编码规范工具
    python的编码在其出生时就有PEP8规范来指导,以下步骤是在eclipse上设置PEP8代码规范检查,并由eclipse自动调整代码格式1、eclipse->window->Preferences->PyDev->Editor->Code......
  • python中的 函数与模块简介
    一、函数概念一段小型程序,实现特定功能。例,>>>2**38>>>pow(2,3)8就是函数,是python的一个内建函数,可以直接调用。自定义函数时一样要遵循先定义后调用的原则,声明时可以......
  • python中五种异常机制的简介
    默认的异常处理器 代码如下:s='Hellogirl!'prints[100]print'continue' 如果我们没有对异常进行任何预防,那么在程序执行的过程中发生异常,就会中断程序,调用py......
  • python之 json文件转xlsx文件
    直接上干货JSON数据转化后的xlsx文件代码解析(可直接食用)"""@File:json_to_xlsx.py@Author:Logan@Date:2022/12/6@Desc:json数据保存未xlsx文件"""......
  • 【Python小随笔】将str类型的list列表,转换成List类型
    str_list="['001678,英大国企改革主题股票,YDGQGGZTGP,2022-12-05,1.6577,2.3077,1.15,4.62,3.72,1.57,15.88,34.04,46.95,115.66,33.43,152.94,2018-11-22,1,34.61......
  • 数据分析工具 Excel、PowerBI、Python、SQL、JVS哪一个更好用?
    先上对比分析产品对比使用低门槛实施效率功能覆盖度上线周期低使用成本企业分析场景Excel★★★★★★★★★★★☆☆☆☆★★★★★★★★★★★★☆☆☆PowerBI★★★☆☆......
  • python之xlsx合并单元格
    需求背景:工作中将数据保存xlsx文件之后,里面每一列中有很多重复的看着很不美观,需要将每一列中的相同值合并起来,是表格看起来美观简洁处理前处理后直接上代码(内涵注释......
  • 【python】求最大公约数、最小公倍数、回文数、素数
    1.最大公约数最大公因子,指两个或多个整数共有约数中最大的一个。如(12,16)的公约数有1,2,4,最大的为4。defgcd(x,y):(x,y)=(y,x)ifx>yelse(x,y)fo......
  • Python数据分析入门--Pandas库学习
    Pandas库学习相较于numpy库关注数据结构的表达,pandas库更关注数据的应用表达1.Pandas库的Series类型1.1Series类型的组成Series类型由一组数据及与之相关的数据索引......