【Python】编程笔记6

面向对象编程(Object Oriented Programming,OOP)

三大特性:封装、继承和多态

OOP 把对象作为程序的基本单元,一个对象包含了数据和
操作数据的函数(方法)。

一、类(class)和 实例(instance)

类是抽象的模板;实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

class Student(object):
    # 第一个参数self表示创建的实例本身,该函数用于初始化,构造函数
    def __init__(self, name, score):
        self.name = name
        self.score = score
    pass

bart = Student('Bart Simpson', 59)
print(bart.name)
print(bart.score)

二、数据封装

可以在类的方法定义时访问数据的函数。

class Student(object):
    # 第一个参数self表示创建的实例本身,该函数用于初始化,构造函数
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):
        print('%s: %s' % (self.name, self.score))
    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

bart = Student('Bart Simpson', 59)
bart.print_score()
print(bart.get_grade())

输出结果

Bart Simpson: 59
C

三、访问限制

为了让变量只有内部可以访问,外部不能访问,可以把属性的名称前加上两个下划线__==》私有变量(private)
==》代码更加健壮
==》要获取,则添加新的方法:

class Student(object):
    # 第一个参数self表示创建的实例本身,该函数用于初始化,构造函数
    def __init__(self, name, score):
        self.__name = name
        self.__score = score
    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))

    # 用于获取name数据
    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

    # 用于设置score数据,可以对参数做检查,避免传入无效的参数
    def set_score(self, score):
        if 0 <= score <= 100:
            self.__score = score
        else:
            raise ValueError('bad score')

    def get_grade(self):
        if self.__score >= 90:
            return 'A'
        elif self.__score >= 60:
            return 'B'
        else:
            return 'C'

四、继承和多态

从某个现有的 class 继承,新的 class 称为子类( Subclass),而被继承的 class 称为基类、父类或超类( Base class、 Super class)
==》

  • 子类获得了父类的全部功能;
  • 对子类修改可以实现子类的特性:修改方法或添加方法
  • 在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行;
# object是所有类的父类,若定义的类没有其他父类,则父类为object
class Animal(object):
    def run(self):
        print('Animal is running...')
class Dog(Animal):
    def run(self):  # 子类的 run()覆盖了父类的 run()
        print('Dog is running...')
    def eat(self):
        print('Eating meat...')
class Cat(Animal):
    def run(self):
        print('Cat is running...')
class Tortoise(Animal):
    def run(self):
        print('Tortoise is running slowly...')
dog = Dog()
dog.run()
cat = Cat()
cat.run()
print('----------------------------------------------------')
def run_twice(Animal):
    Animal.run()
    Animal.run()

run_twice(Animal())
run_twice(Dog())
run_twice(Cat())
run_twice(Tortoise())

输出结果

Dog is running...
Cat is running...
----------------------------------------------------
Animal is running...
Animal is running...
Dog is running...
Dog is running...
Cat is running...
Cat is running...
Tortoise is running slowly...
Tortoise is running slowly...

run_twice() 函数传入的任意类型,只要是 Animal 类或者子类,就会自动调用实际类型的 run()方法。==》多态
==》“开闭” 原则

  • 对扩展开放:允许新增 Animal 子类;
  • 对修改封闭:不需要修改依赖 Animal 类型的 run_twice()等函数。

静态语言 vs. 动态语言

  • 静态语言:run() 方法,若要传入 Animal 类型,则传入的对象必须是 Animal 类型或者它的子类,否则无法调用。
  • 动态语言:run() 方法不一定传入 Animal 类型,只需保证传入的对象有一个 run() 方法就可以了。==》“鸭子类型”:不要求严格的继承体系,一个对象只要有该方法即可。

五、获取对象信息

1、对象类型——type() 函数

## 基本类型
print(type(123))
print(type('str'))
print(type(None))
## 变量类型
print(type(abs))
print(type(dog))
## if 语句中判断两个变量的类型
print(type(123) == type(456))
print(type(123) == int)
print(type('abc')==type('456'))

输出结果

<class 'int'>
<class 'str'>
<class 'NoneType'>
<class 'builtin_function_or_method'>
<class '__main__.Dog'>
True
True
True

判断一个对象是否是函数

import types
def fn():
    pass
print(type(fn) == types.FunctionType)
print(type(fn) == types.BuiltinFunctionType)
print(type(lambda x: x) == types.LambdaType)
print(type((x for x in range(10))) == types.GeneratorType)

输出结果

True
False
True
True

2、isinstance() 函数

isinstance() 函数:判断一个对象是否是该类型本身,或者位于该类型的父继承链上

若继承关系为:object -> Animal -> Dog -> Husky。

a = Animal()
d = Dog()
h = Husky()
isinstance(h, Husky)    # True
isinstance(h, Dog)  	 # True
isinstance(h, Animal)   # True
isinstance(d, Dog) and isinstance(d, Animal)   # True
isinstance(d, Husky)    # False

能用 type()判断的基本类型也可以用 isinstance()判断;

isinstance('a', str)
# True

判断一个变量是否是某些类型中的一种;

isinstance([1, 2, 3], (list, tuple))
# True

3、dir() 函数

dir()函数:获取一个对象的所有属性和方法,返回一个包含字符串的 list。

print(dir('ABC'))

输出结果

['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

==》其中,类型__xxx__的属性和方法是有特殊用途的,其余的为普通属性或方法。

4、getattr()、 setattr() 以及 hasattr() 函数

场景:只有在不知道对象信息的时候,我们才会去获取对象信息。
getattr()、 setattr() 以及 hasattr() ==》直接操作一个对象的状态。

class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x
obj = MyObject()

## 测试该对象的属性
print(hasattr(obj, 'x'))   # 有属性'x'吗?
print(obj.x)
print(hasattr(obj, 'y'))   # 有属性'y'吗?
print(setattr(obj, 'y', 19))   # 设置属性'y'?
print(hasattr(obj, 'y'))   # 有属性'y'吗?
print(getattr(obj, 'y'))
print(obj.y)
print(getattr(obj, 'z', 404))  # 获取属性'z',如果不存在,返回默认值 404

## 测试该对象的方法
print(hasattr(obj, 'power'))  # 有属性'power'吗?
print(getattr(obj, 'power'))  # 获取属性'power'
fn = getattr(obj, 'power')    # fn 指向 obj.power
print(fn())

输出结果

True
9
False
None
True
19
19
404
True
<bound method MyObject.power of <__main__.MyObject object at 0x00000201083E2080>>
81

常见做法:假设我们希望从文件流 fp 中读取图像,我们首先要判断该 fp 对象是否存在 read 方法,如果存在,则该对象是一个流,如果不存在,则无法读取。 hasattr()就派上了用场。

def readImage(fp):
    if hasattr(fp, 'read'):
        return readImage(fp)
    return None

六、实例属性和类属性

1、实例属性

Python 中可根据类创建的实例可以任意绑定属性,绑定方法:通过实例变量,或者通过 self 变量。

class Student(object):
    def __init__(self, name):
        self.name = name
s = Student('Bob')
s.score = 90
print(s.name)  		# Bob
print(s.score) 		# 90

2、类属性

直接在 class 中定义属性 ==》类属性

实例属性优先级比类属性高,因此,调用实例属性时,若实例属性存在,会产生屏蔽类属性的现象

  • 调用方法:实例.属性
  • 调用方法:类.属性
class Student(object):
    name = 'Student'
s = Student()       # 创建实例 s
# 打印实例 name 属性,因为实例无 name 属性,所以会继续查找 class 的 name 属性
print(s.name)
print(Student.name)  # 打印类属性

s.name = 'Michael'
print(s.name)        # 实例属性存在
print(Student.name)

del  s.name			# 删除实例属性存在
print(s.name)

输出结果

Student
Student
Michael
Student
Student
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值