python面向对象笔记

简介: 一、封装(属性/私有方法/公有方法/静态方法/构造函数...) # 定义一个类 class Animal: # 私有成员(用_开头的约定为私有成员 - 注:仅仅是君子协定) _age = 0 # 构造函数 def __init__(self, na...

一、封装(属性/私有方法/公有方法/静态方法/构造函数...)

# 定义一个类
class Animal:
    # 私有成员(用_开头的约定为私有成员 - 注:仅仅是君子协定)
    _age = 0

    # 构造函数
    def __init__(self, name):
        # 建议所有私有成员在这里初始化(不管是已定义的,还是"动态"添加的)
        self.name = name  # 动态添加的私有成员
        self._age = 1  # 已经定义好的私有成员

    # 静态方法
    @staticmethod
    def eat():
        print("Animal can eat food")

    # 公有方法
    def to_string(self):
        return "name:" + self.name

    # 私有方法(用_开头的约定为私有方法 - 注:仅仅是君子协定)
    def _some_method(self):
        return "this is a private method of :" + self.name

    # setter示例
    def set_age(self, age):
        if age < 0 or age > 100:
            print("age is invalid!")
        self._age = age

    # getter示例
    def get_age(self):
        return self._age

    def run(self):
        print(self._some_method())
        print("I am running")

    def test(self):
        print("test1")

    # 注:这样会覆盖上面的test(self版本)
    def test(self, hello):
        print("test2:" + hello)


animal = Animal("A new animal")
print(animal.to_string())  # 方法调用
animal.eat()  # 静态方法调用1(不推荐)
Animal.eat()  # 静态方法调用2
print("animal._age=" + str(animal.get_age()))
animal.set_age(10)  # 调用setter
print(animal.get_age())  # 调用getter,输出10
animal.run()  # 公有方法里调用私有方法
animal._age = 30  # 直接修改私有成员(不推荐)
animal._age2 = 40  # 注意:这里实际上给实例animal"动态"添加了一个_age2属性
print(animal.get_age())  # 这里输出的仍然是10
print("_age2:" + str(animal._age2))  # 这里输出的动态添加的_age2属性值
print(animal.test("hi"))
#print(animal.test())  # 这里会报错,因为test(self,hello)这个版本要求hello参数有值
print(animal._some_method())  # 直接调用私有方法(不推荐)

输出:

name:A new animal
Animal can eat food
Animal can eat food
animal._age=1
10
this is a private method of :A new animal
I am running
30
_age2:40
test2:hi
None
this is a private method of :A new animal

几个要点:

1、约定大于配置:比如构造函数约定为__init__;私有方法/成员约定为"_"开头(注:只是君子协定,硬要调用的话,外部是可以直接调用的);实例方法约定第1个参数为self  

2、重载的处理,不象java里要定义多个方法签名,python里就一个版本,但是通过可变参数来实现(后面还要细讲)

3、动态语言,实例在运行过程中,可随时动态添加属性

另外注意:不要轻易使用__(二个连续的下划线)做为方法或变量的前缀或后缀,"__XXX__"在python里通常有特定含义,如果使用"__"开头的变量或写法,可能会遇到各种奇葩问题。

 

二、重载

传统的OOP语言,比如java,重载只能是定义多个不同方法签名的method,来实现重载,但是python可以做得更简单,用参数默认值就可以变相实现。

# 定义一个类
class Calculator:
    # 加法
    def add(self, a=0, b=0, c=0, d=0):
        print("args:", a, b, c, d)
        return int(a) + int(b) + int(c) + int(d)


cal = Calculator()
print(cal.add(1, 2))
print(cal.add(1, 2, 3))
print(cal.add(1, "2", 3, "4"))

print("\n")

cal = Calculator #注意这里,如果漏了(),结果会大不同
print(cal.add(1, 2))

 输出:

args: 1 2 0 0
3
args: 1 2 3 0
6
args: 1 2 3 4
10


args: 2 0 0 0
2  

注意:16行,如果漏了(),cal = Calculator,实际上只是cal只是相当于类Calculator的别名,这样调用add(1,2)时,类似于静态方法调用,1会认为是第一个参数self,所以输出就成了2.

如果不确定参数个数,还可以这么做:

# 定义一个类
class Calculator:
    # 约定:*参数,表示参数个数不限定
    def add(self, *args):
        result = 0
        for arg in args:
            result += int(arg)
        return result


cal = Calculator()
print(cal.add(1, 2, 3))
print(cal.add("1", 2, "3"))

输出:

6
6

  

三、继承

3.1 基本示例

class Fruit:
    def __init__(self, name):
        print("Fruit constructor...")
        self.name = name

    def to_string(self):
        print("Fruit to_string...")
        return "name:" + self.name

    # 抽象方法
    def get_color(self):
        print("Fruit get_color...")
        raise NotImplementedError


class RedApple(Fruit):
    def __init__(self, name):
        print("Apple constructor...")
        # 调用父类的构造函数
        Fruit.__init__(self, name)

    def get_color(self):
        return self.name + " is red"


fruit = Fruit("unknown")
print(fruit.to_string())
# print(fruit.get_color())  # 报错,因为没实现
print("\n")

redApple = RedApple("red apple")
print(redApple.get_color())
print(redApple.to_string())

print("\n")
print("1、redApple is instance of RedApple ? ", isinstance(redApple, RedApple))
print("2、redApple is instance of Fruit ? ", isinstance(redApple, Fruit))
print("3、fruit is instance of Fruit ? ", isinstance(fruit, Fruit))
print("4、fruit is instance of RedApple ? ", isinstance(fruit, RedApple))
print("5、RedApple is subclass of Fruit ? ", issubclass(RedApple, Fruit))
print("6、Fruit is subclass of Fruit ? ", issubclass(Fruit, Fruit))
print("7、Fruit is subclass of RedApple ? ", issubclass(Fruit, RedApple))

 输出:

Fruit constructor...
Fruit to_string...
name:unknown


Apple constructor...
Fruit constructor...
red apple is red
Fruit to_string...
name:red apple


1、redApple is instance of RedApple ?  True
2、redApple is instance of Fruit ?  True
3、fruit is instance of Fruit ?  True
4、fruit is instance of RedApple ?  False
5、RedApple is subclass of Fruit ?  True
6、Fruit is subclass of Fruit ?  True
7、Fruit is subclass of RedApple ?  False

注:抽象方法是通过抛出未实现的异常来实现的。如果想类似java定义抽象类,把__init__方法抛出未实现异常就行。

3.2 多继承

python支持多继承,这点与java有很大区别

class P1:
    def a(self):
        print("P1-a")

    def b(self):
        print("P1-b")

    def x(self):
        print("P1-x")


class P2:
    def a(self):
        print("P2-a")

    def b(self):
        print("P2-b")

    def y(self):
        print("P2-y")


# 多继承示例
class S1(P1, P2):
    def a(self):
        print("S1-a")


class S2(P2, P1):
    def a(self):
        print("S2-a")


s1 = S1()
s1.a()
s1.b()  # P1-b
s1.x()
s1.y()

print("\n")

s2 = S2()
s2.a()
s2.b()  # P2-b
s2.x()
s2.y()

print("\n")

print("s1 isinstance of P1:", isinstance(s1, P1))
print("s1 isinstance of P2:", isinstance(s1, P2))
print("s1 isinstance of S1:", isinstance(s1, S1))
print("s1 isinstance of S2:", isinstance(s1, S2))

输出:

S1-a
P1-b
P1-x
P2-y


S2-a
P2-b
P1-x
P2-y


s1 isinstance of P1: True
s1 isinstance of P2: True
s1 isinstance of S1: True
s1 isinstance of S2: False

注意多承继的顺序,如果“爸爸们”之间有重名方法,将会按照继承顺序,谁在前面,就调用谁的。eg:def S(A,B) 子类S继承自A,B,如果A,B中都有方法x,调用S.x时,因为A排在B的前面,所以调用到的就是A.x方法。从上面的输出就可以得到印证。

3.3 接口、abc模块、属性

3.1中抽象类/方法是通过抛出异常来实现的,有点粗暴,下面介绍一种更优雅的方法,python内置的abc模块

from abc import *


# 接口示例
class IRun(ABC):
    # 抽象方法
    @abstractmethod
    def run(self):
        pass


class Animal(ABC):
    # 抽象属性
    @property
    @abstractmethod
    def name(self):
        pass


class Dog(Animal, IRun):
    def __init__(self, name):
        self._name = name;

    # 属性的getter
    @property
    def name(self):
        return self._name

    # 属性的setter (注:每个property都会生成一个对应的@xxx.setter)
    @name.setter
    def name(self, value):
        self._name = value

    # 接口的方法实现
    def run(self):
        print(self.name + " is running")


dog1 = Dog("a")
dog1.run()
dog2 = Dog("b")
dog2.run()
print(isinstance(dog1, IRun))
print(id(dog1), id(dog2), id(dog1) == id(dog2))  # 判断2个实例是否相等

  输出:

a is running
b is running
True
4314753736 4314753792 False

 

最后送一波福利: https://github.com/faif/python-patterns  这是python实现的所有设计模式,对oop感兴趣的推荐研究。

作者: 菩提树下的杨过
出处: http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
目录
相关文章
|
12月前
|
Java 程序员 C++
Python 面向对象详解!
本文详细介绍了Python中的面向对象编程(OOP),包括类、对象、继承、封装、多态和抽象等核心概念。通过具体示例,解释了如何使用类定义对象的属性和方法,以及如何通过继承实现代码重用。文章还探讨了封装和多态的重要性,并介绍了私有属性和抽象类的使用方法。最后,总结了OOP的四大支柱:封装、抽象、继承和多态,强调了这些概念在Python编程中的应用。适合Java程序员扩展Python编程知识。
306 2
|
3月前
|
编解码 数据安全/隐私保护 Python
抖音批量发布视频工具,自动上传视频作品笔记,python发布软件
这个抖音批量发布工具包含三个主要模块:主上传程序、配置文件和视频预处理工具。主程序
|
3月前
|
API 数据安全/隐私保护 Python
小红书批量发布协议, 抖音自动批量发布软件脚本,笔记作品视频自动发布工具【python】
这个工具框架包含了小红书和抖音的批量发布功能,支持图片和视频处理、定时发布等功能
|
3月前
|
Web App开发 数据安全/隐私保护 Python
抖音快手小红书哔哩哔哩,批量发布作品笔记视频工具,自动发布作品上传笔记视频【python】
这个工具实现了四大平台的视频批量上传功能,包含完整的异常处理和日志记录。使用时需要配置
|
3月前
|
存储 JSON API
小红书批量发布笔记工具,小红书批量上传软件,python框架分享
这个框架包含了配置文件、工具函数、API封装和主程序四个模块。使用时需要先配置账号信息,
|
5月前
|
人工智能 Ruby Python
python__init__方法笔记
本文总结了Python中`__init__`方法的使用要点,包括子类对父类构造方法的调用规则。当子类未重写`__init__`时,实例化会自动调用父类的构造方法;若重写,则需通过`super()`或直接调用父类名称来显式继承父类初始化逻辑。文中通过具体代码示例展示了不同场景下的行为及输出结果,帮助理解类属性与成员变量的关系,以及如何正确使用`super()`实现构造方法的继承。
205 9
|
6月前
|
数据采集 JSON API
Python 实战:用 API 接口批量抓取小红书笔记评论,解锁数据采集新姿势
小红书作为社交电商的重要平台,其笔记评论蕴含丰富市场洞察与用户反馈。本文介绍的小红书笔记评论API,可获取指定笔记的评论详情(如内容、点赞数等),支持分页与身份认证。开发者可通过HTTP请求提取数据,以JSON格式返回。附Python调用示例代码,帮助快速上手分析用户互动数据,优化品牌策略与用户体验。
1025 3
|
6月前
|
数据采集 JSON API
Python 实战!利用 API 接口获取小红书笔记详情的完整攻略
小红书笔记详情API接口帮助商家和数据分析人员获取笔记的详细信息,如标题、内容、作者信息、点赞数等,支持市场趋势与用户反馈分析。接口通过HTTP GET/POST方式请求,需提供`note_id`和`access_token`参数,返回JSON格式数据。以下是Python示例代码,展示如何调用该接口获取数据。使用时请遵守平台规范与法律法规。
|
7月前
|
Python
Python 高级编程与实战:深入理解面向对象与并发编程
本文深入探讨Python的高级特性,涵盖面向对象编程(继承、多态、特殊方法、类与实例属性)、异常处理(try-except、finally)和并发编程(多线程、多进程、异步编程)。通过实战项目如聊天服务器和异步文件下载器,帮助读者掌握这些技术,编写更复杂高效的Python程序。
|
10月前
|
关系型数据库 开发者 Python
Python编程中的面向对象设计原则####
在本文中,我们将探讨Python编程中的面向对象设计原则。面向对象编程(OOP)是一种通过使用“对象”和“类”的概念来组织代码的方法。我们将介绍SOLID原则,包括单一职责原则、开放/封闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则有助于提高代码的可读性、可维护性和可扩展性。 ####

推荐镜像

更多