6.python入门-面向对象

面向过程编程:将程序分解为一系列的步骤,每个步骤都是一个函数,以事物发生过程为主要目标进行编程(什么正在发生)。程序的状态通常由全局变量来维护,而函数则被用来封装可重用的代码块。

函数式编程,函数式的思想:函数内部需要的数据均通过参数的形式传递。强调函数的纯度和不可变性。

面向对象编程,面向对象的思想:将数据和操作数据的方法组合在一起,形成一个对象。每个对象都有自己的状态(data)和行为(methods),并且可以通过调用其他对象的方法来改变自身状态或执行其他操作。面向对象编程的核心概念包括类、对象、继承、封装和多态性。

6.1 类与对象

类与对象的关系即模板与产品:模板只能有一个,但对象可以有很多个

面向对象实现功能的步骤:

  1. 定义类,在类中定义方法,在方法中去实现具体的功能。
  2. 实例化类给一个对象,通过对象去调用并执行方法。

名词解释

  1. 类是对一些具有相同属性特征和行为的事物的分类,它是抽象的。
  2. 属性:属性是指类或对象中的变量,用于存储对象的特征状态,比如年龄、身高、性别、姓名等都叫做属性。
  3. 方法:用来描述事物的行为,用函数来完成这些行为。比如说话、走路、吃饭等
  4. 实例(对象):一个对象即是一个类的实例化后实例,是具体的。一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象可以有不同的属性,能调用类中共同的方法。
  5. 实例化:把一个类转变为一个对象的过程就叫实例化。

1. 类

我们可以使用关键字 class 定义类,关键字后面紧跟类的名称、分号和类的实现。

1. 类名称首字母大写&驼峰式命名
2. 在类种编写的函数称为方法,每个方法的第一个参数是self(类的方法与普通的函数唯一区别)
3. py3之后默认类都继承object,

旧式类:

class Ab Doct:
    pass

新式类:

class Ab Doct(object):
    pass

2. 对象

对象 = 类() ,基于类实例化出来”一块内存“,默认里面没有数据;

__init__初始化方法(也称构造方法),在类实例化过程中会自动执行,可以在内存中初始化一些属性数据。

  • 不需要初始化的话,可以不写__init__方法,因为解释器会自动生成一个__init__方法来执行。
  • 实例化时,先调用了__new__(cls)方法,创建并返回一个类(cls)的新实例对象,传递给构造方法。
  • 封装,就是使用构造方法将属性数据封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容
class Stu(object):
    def __new__(cls, *args, **kwargs):  # __new__方法的第一个参数是类本身,后面的参数是传递给构造方法的参数。
        print('no.1')
        obj = super().__new__(cls)    # 重写需要先调用实现过程,并返回一个类的实例
        return obj
  
    def __init__(self):  # 第一个参数为self的实例方法,实例化一个新对象时,会自动调用这个方法。全名initialize。
        print('no.2')
 
 
s1 = Stu()
# no.1
# no.2

3. 类对象

在python中,一切都是对象,当我们定义了一个类,这个类也是对象,叫做类对象。

  • 类对象是一个类的实例,它是用来创建对象的模板。类对象可以访问类属性和方法,也可以被用来创建实例对象。
  • 对象是类对象的实例,它是由类对象创建出来的。对象可以访问实例属性和方法,也可以访问类属性和方法
  • 类对象也具有id,type,value三大特点。类的类型是“class type”
class Stu():
    def speak(self):
        print('running')
 
 
print(Stu, 'and id is:', id(Stu), 'type is:', type(Stu))
S_copy = Stu
print(S_copy, 'and id is:', id(S_copy), 'type is:', type(S_copy))
# <class '__main__.Stu'> and id is: 2150663355640 type is: <class 'type'>
# <class '__main__.Stu'> and id is: 2150663355640 type is: <class 'type'>

6.2 类的成员

在 Python 中,面向对象编程中的成员包括属性和方法。

  • 属性是指类或对象中的变量,而方法则是类或对象中的函数。在类中定义的属性和方法可以被该类的所有实例对象所共享。
  • 属性和方法可以使用点运算符来访问,语法形式为 对象名.属性名 和 对象名.方法名()。
  • Python 还支持访问控制机制,即通过使用下划线来表示成员的可见性,例如单下划线表示该成员是受保护的,双下划线表示该成员是私有的。

1. 类属性与实例属性

  • 类属性:定义在类中,但不属于任何实例对象的属性。也叫类变量,属于类对象所有,可以被所有该类的实例对象所共享,可以通过类名直接访问和修改。
  • 实例属性:加了self的属性,它隶属于对象而不是类(这些属性是放在实例对象的内存空间里的,而不是类对象的内存空间里),能被不同的对象赋值,对象不同,self指向的内存地址也不同。这个对象的所有方法都可以访问和使用本对象的实例属性。实例属性一般定义在__init__方法里,也可以定义在其他方法里。
class Student():
    num = 10  # 定义了一个属性,没有加self,也没有放在方法里边,他是类属性(类变量),属于Student这个类
 
    def __init__(self, name, age):   # name,和age两个和普通的函数形参变量一样,用来接收参数。方法执行完被清空。
        self.name = name # 加了self,说明这个属性对象可以拿去使用,赋值后放在实例对象的内存空间里。供对象调用
        self.age = age
        print(self.num)  # 当对类变量只做访问不做修改的话,也可以使用self.变量名来访问。  
        
    def showinfo(self):  
        gender = 'male'  # 这个变量没加self,就是一普通局部变量,showinfo方法执行完毕,他就没了
        print(gender)
        print(self.age,self.name) # 调用属性,用self来确定到底是哪一个对象的age属性 
 
# 创建了Student类的两个实例对象stu1和stu2,自动初始化, 需要传入两个属于stu1这个对象的特性属性
stu1 = Student(name='xiaoming', age=12)   # 10

# 类创建的对象也拥有类变量的使用权,但是没有修改权,一旦产生同名变量,则会隐藏类变量
print(stu1.num)   # 10 

# 类属性的修改需要直接基于类,用s1.num会创建一个实例属性。
Student.num = 50 

stu2 = Student('lihua', 18)          # 50
 
# 因为不同的对象都会享有他们类的的方法,属性各自赋值,现在测试一下
stu1.showinfo()
# male
# 12  xiaoming
stu2.showinfo()
# male
# 18  lihua
#果然都能调用showinfo方法,打印了male,但是name和age各是各的。

2.实例方法

Python 严格要求实例方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定概念。

实例方法是属于类对象的,也就是说实例方法包含在类对象的内存空间里。通过对象名和点号来访问。

class Stu:
    def info_age(self, age): # 实例方法,第一个参数是self,可被此类所有对象共享
        self.age = age 
        
    def show_age(self):
        print(self.age)  # 可以访问其他方法里定义的实例属性,因为他和我同属于一个对象
 
s1 = Stu()
Stu.info_age(s1, 20)  
Stu.show_age(s1)
# 常规写成下边两行的形式,但python解释器其实以上面两句代码形式执行。
s1.info_age(18)   # 将类对象s1的年龄修改成了18
s1.show_age()
# 20
# 18

3. 方法装饰器

Python内置了两个装饰器函数,使用它们可以把类中函数转换为专用类方法或静态方法。

  • classmethod:装饰为类方法。对于类方法来说,习惯上使用cls设置第一个形参,当然也可以使用其他名称。
  • staticmethod:装饰为静态方法。无默认实参,如果要在静态方法中访问类的属性,只能通过引用类对象来实现。
def test():  # 普通函数
    print(666)
 
 
class Test():
    def __init__(self):
        self.test()
 
    @classmethod  # 定义类方法
    def test(cls): 
        print(666)
 
    def ceshi(self):
        self.test()  # 这里用self.类方法名也可以调用类方法
 
 
test()
Test.test()
t1 = Test()
# 666
# 666
# 666

静态方法与普通函数没有本质区别,只是放的位置有差异。普通函数定义在模块级别。静态方法本质上就是:普通函数放在类里边了,也没有类方法的cls参数。静态方法通常用于执行与类相关的操作,例如创建和销毁对象、获取类信息等。

def test():  # 普通函数
    print(666)
 
 
class Test():
    @staticmethod   # 类似于普通函数放在类里边
    def show():
        print(666)
 
    def test(self):
        self.show()  # 利用self.静态方法名也能调用
 
 
Test.show()  # 通过类名.静态方法名来访问
t1 = Test()
t1.show()
# 666
# 666

实例方法、类方法和静态方法的区别

  • 实例对象可以调用3种方法,类对象只能调用类方法和静态方法。
  • 类对象调用实例方法时,实例方法变为普通函数,将失去默认的上下文运行环境。实例方法的上下文运行环境是实例对象,而类方法的上下文运行环境是类对象。
  • 访问属性的不同,实例属性只有实例方法可以访问。实例方法也能使用类属性,但是不能修改。静态方法只能通过参数或者类对象间接访问类属性。

3.属性装饰器

静态属性存在一个缺陷:无法对用户的访问进行监控。例如,设置price属性,写入时要求必须输入数字,读取时显示两位小数。

Python内置了property装饰器函数,使用该装饰器可以把一个普通函数转换为函数式属性。这样通过函数的行为对用户的访问进行监控,避免乱操作。

属性的访问包括:读、写、删,对应的装饰器为:@property、@方法名.setter、@方法名.deleter。

在函数的上一行添加@property装饰器,就可以定义函数式属性。在函数式属性中,第一个实参自动被设置为实例对象,一般以self作为形参名,也可以使用其他名称。

当访问函数式属性时,与静态属性的用法相同,使用点语法即可,不需要使用小括号调用属性函数。这种简化的语法形式符合属性的习惯用法。

【示例】设计一个商品报价类,初始化参数为原价和折扣,然后可以读取商品实际价格,也可以修改商品原价,或者删除商品的价格属性。

    class Goods(object):
        def __init__(self, price, discount=1):                   # 初始化函数
            self.orig_price = price                              # 原价
            self.discount = discount                             # 折扣
        @property
        def price(self):                                         # 读取属性函数
            new_price = self.orig_price * self.discount          # 实际价格=原价*折扣
            return new_price
        @price.setter
        def price(self, value):                                  # 写入属性函数
            self.orig_price = value
        @price.deleter
        def price(self):                                         # 删除属性函数
            del self.orig_price
    
    obj = Goods(120, 0.7)                                        # 实例化类
    print( obj.price )                                           # 获取商品价格
    obj.price = 200                                              # 修改商品原价
    del obj.price                                                # 删除商品原价
    print( obj.price )                                           # 不存在,将抛出异常

注意:如果定义只读函数式属性,则可以仅定义@property和@price.deleter装饰器函数。

4.构造属性

属性装饰器用法比较烦琐,使用property()函数构造属性可以快速封装,语法格式如下:

    class property([fget[, fset[, fdel[, doc]]]])

参数说明如下。

  • fget:获取属性值的实例方法。
  • fset:设置属性值的实例方法。
  • fdel:删除属性值的实例方法。
  • doc:属性描述信息。
    class Goods(object):
        def __init__(self, price, discount=1):                        # 初始化函数
            self.orig_price = price                                   # 原价
            self.discount = discount                                  # 折扣
        def get_price(self):                                          # 读取属性
            new_price = self.orig_price * self.discount               # 实际价格=原价×折扣
            return new_price
        def set_price(self, value):                                   # 写入属性
            self.orig_price = value
        def del_price(self):                                          # 删除属性
            del self.orig_price
        # 构造price属性
        price = property(get_price, set_price, del_price, "可读、可写、可删属性:商品价格")
    
    obj = Goods(120, 0.7)                                             # 实例化类
    print( obj.price )                                                # 获取商品价格
    obj.price = 200                                                   # 修改商品原价
    del obj.price                                                     # 删除商品原价
    print( obj.price )                                                # 不存在,将抛出异常

5.一些相关的内置函数(BIF)

  • issubclass(class, classinfo) 方法用于判断参数 class 是否是类型参数 classinfo 的子类。
  • 一个类被认为是其自身的子类。
  • classinfo可以是类对象的元组,只要class是其中任何一个候选类的子类,则返回True
class A:
    pass


class B(A):
    pass


print(issubclass(B, A))  # True
print(issubclass(B, B))  # True
print(issubclass(A, B))  # False
print(issubclass(B, object))  # True
  • isinstance(object, classinfo) 方法用于判断一个对象是否是一个已知的类型,类似type()
  • type()不会认为子类是一种父类类型,不考虑继承关系。
  • isinstance()会认为子类是一种父类类型,考虑继承关系。
  • 如果第一个参数不是对象,则永远返回False
  • 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。

【例子】

a = 2
print(isinstance(a, int))  # True
print(isinstance(a, str))  # False
print(isinstance(a, (str, int, list)))  # True


class A:
    pass


class B(A):
    pass


print(isinstance(A(), A))  # True
print(type(A()) == A)  # True
print(isinstance(B(), A))  # True
print(type(B()) == A)  # False
  • hasattr(object, name)用于判断对象是否包含对应的属性。True False
  • getattr(object, name[, default])用于返回一个对象属性值。 不存在报错。
  • setattr(object, name, value)对应函数 getattr(),用于设置属性值,该属性不一定是存在的。
  • delattr(object, name)用于删除属性。不存在报错。
  • class property([fget[, fset[, fdel[, doc]]]])用于在新式类中返回属性值。
class A(object):
    bar 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值