Python面向对象编程

1、类的定义

Python中类的定义与对象的初始化如下,python中所有类的父类是object,需要继承。

由于Python是动态语言,因此可以直接为对象添加属性并赋值而不必在类定义中声明

class Person(object):    # 定义一个Person类
    pass
p = Person()    # 初始化一个Person对象
p.name="xiaoming"    # 对象属性赋值

 Python的类初始化方法为__init__(),其第一个参数为self代之对象自身,其后为各个参数,初始化就是将传入的参数赋值给对象的属性。**kw代表任意数量的属性,通过key=attribute的形式传入,之后通过setattr()方法将每个属性赋值给对象。

直接在class中定义的变量称为类属性,在__init__()中定义的为对象属性,类属性供所有对象共享,对象只能访问却无权修改。当通过对象给类属性赋值时,会为对象新建一个同名的对象属性,而不是修改类属性。无论在类的内部还是外部,都通过类名对类属性进行访问。

__开头的变量无法被外部访问,类似于私有变量。这时就需要对象的实例方法从类的内部访问私有变量并做出相应的操作,这样在类的内部定义的方法叫做实例方法,实例方法的第一个参数默认为self代表对象自己。

相应地类方法只能访问类属性,其定义方式是在之前添加标记@classmethod:,其第一个参数cls代表类本身

class Person(object):
    count = 0    # 类属性
    @classmethod:
    def get_count(cls):    # 类方法
        return cls.count
    def __init__(self,name,gender,birth,**kw):
        Person.count+=1    # 访问类属性
        self.name = name
        self.__gender = gender
        self.birth = birth
        for k, v in kw.iteritems():    # 遍历之后的键值对,设置属性
            setattr(self, k, v)
    def get_name(self):    # 定义实例方法
        return self.__name

xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
xiaoming.count==9    # 为对象创建属性,不会修改Person.count

print(xiaoming.job)    # 显示Student
print(xiaoming.__gender)   # 无法访问,抛出异常AttributeError
print(xiaoming.get_name())    # 通过实例方法访问内部变量

2、类的继承

 Python中类的继承方式如下。值得注意的是在子类Teacher中需要通过super(子类名,self)调用父类的初始化函数来完成对父类中参数的初始化。也可以直接通过父类名称调用父类的方法

通过type()方法输出变量的类型,isinstance()可以判断变量是否是某个类型,dir()方法返回变量的所有属性和方法列表。输出对象t的属性结果如下,其中带__的为默认属性,其余为自定义的属性

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'course', 'gender', 'name']

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Teacher(Person):    # 继承父类Person
    def __init__(self, name, gender, course):
        super(Teacher,self).__init__(name,gender)    # 调用父类的初始化函数
        self.course= course    # 完成子类变量的初始化

t = Teacher('Alice', 'Female', 'English')

print(isinstance(t,Person))    # 结果为True,子类也是父类的类型
print(dir(t))    # 显示对象的所有属性

和其他面向对象的语言一样,Python具有多态的特性,例如父类和不同的子类都定义了相同的方法,当不同的子类调用该方法时会调用自己定义的方法,从而实现相同的方法具有不同的操作。但python是动态语言,和静态语言C++、Java不同的是在调用实例方法时,python不检查类型,只要方法存在,参数正确,就可以调用。例如原本json的load方法中定义了read()方法用于实现对文件的读取,当我们自定义一个类其中包含read()方法时,便可动态调用Student重写的read()方法

import json

class Student(object):
    def read(self):
        return r'["Tim", "Bob", "Alice"]'

s = Student()
print(json.load(s))        # 输出:['Tim', 'Bob', 'Alice']

一个子类可以同时继承两个以上的父类,这个特性叫做多继承,当有多个父类时,在调用构造方法时需要指明父类

class A(object):
    def __init__(self, a):
        self.a = a

class B(object):
    def __init__(self, b):
        self.b = b

class C(A, B):
    def __init__(self, a, b, c):
        A.__init__(self, a)        # 调用构造方法时指明父类A
        B.__init__(self, b)
        self.c = c

c = C(1, 2, 3)
print(c.a)      # 输出1

3、类的特殊方法

Python的特殊方法是指定义在类中,以__开头和结尾,由某些函数或操作符隐式触发调用的方法。例如当我们使用print(p)打印一个Person对象p时,就会调用Person的__str__()方法将p转化为字符串共print输出,输出结果为:<__main__.Person object at 0x000001787CC7C0D0>

当我们重新自定义这些特殊方法后,当触发调用时就会按我们定义的函数执行。例如重新定义__str__(),当print()时就会显示My name is Bob

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def __str__(self):    # 重新定义类特殊方法
        return "My name is " + self.name

p = Person('Bob', 'male')
print(p)    # 输出结果为:My name is Bob

__cmp__()方法用于实现类的比较,在排序时会自动调用。例如在Student类中重新定义该方法,按分数高低对学生进行排序,其有两个参数,第一个自己self,第二个是比较的对象s,如果self应该在s之前,则返回-1

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __cmp__(self, s):    # 重写__cmp__方法
        if self.score>s.score:
            return -1    # self在s之前
        elif self.score<s.score:
            return 1
        else:
            return 0

L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
Ls = sorted(L)    # 使用sorted对Student类进行排序

__len__()方法用于返回长度,当len()调用类时会触发

__add____sub____mul____div__分别对应类的加减乘除运算,当类遇到运算符+-*/时会调用该方法,例如实现一个分数类Rational的加法:1/2+1/4,通分相加得6/8,最后求最大公约数后约分得到3/4

__int__、__float__方法在int()、float()调用类时触发,可以重新该方法返回一个int或float结果

def gcd(a, b):    # 求最大公约数
    if b == 0:
        return a
    return gcd(b, a % b)
    
class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

    def __add__(self, r):    # 重写加法运算
        return Rational(self.p * r.q + self.q * r.p, self.q * r.q)

    def __str__(self):
        g = gcd(self.p, self.q)    # 将分数约分后输出
        return '%s/%s' % (self.p / g, self.q / g)

    def __float__(self):    # 将分数转化为float小数返回
        return float(self.p)/float(self.q)

r1 = Rational(1, 2)
r2 = Rational(1, 4)
print(r1 + r2)    # 两个类相加
print(float(r1))    # 输出小数形式

类属性的装饰器@property用于将类方法转化为属性,这样就可以像访问属性一样调用方法。例如Student类的__score属性对外是不可见的,通过定义返回方法score使得对象s可以通过s.score得到分数值。

@property.setter方法用于对属性设置方法进行装饰,使得可以像给属性赋值一样调用类方法。例如当使用s.score=99时会调用设置方法score(self,score),将值传递给__score,并且可以对传入值的合法性进行检验。

__slots__()用于定义类中可以使用的属性,父类定义过的子类中无需重复定义。当添加新的属性并赋值时,运行会抛出异常AttributeError

__call__()将一个类实例变成一个可调用对象,例如一个Student对象s,像函数调用一样使用对象:s('Alice')

class Student(object):
    __slots__ = ('name','__score')    # 本类只允许使用name、score两个属性

    def __init__(self, name, score):
        self.name = name
        self.__score = score

    @property                # 定义属性返回方法
    def score(self):
        return self.__score

    @score.setter            # 定义属性设置方法
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
    
    def __call__(self, friend):
        print('My friend is %s...' % friend)


s = Student('Bob', 59)
s.score = 60    # 调用属性设置方法
print(s.score)    # 调用属性返回方法
s.grade='A'    # 抛出异常,无法添加其他属性
s('Alice')    # 输出My friend is Alice...

__getattribute__(self,attr)、__setattr__(self,attr)、__delattr__(self,attr)分别用于获取、设置、删除属性时触发的方法,在使用时应注意避免递归调用引起的无限循环,例如在get方法中再调用get类似的方法导致无限循环。

4、模块管理

为了方便分类管理python中的类和方法,需要将代码放在不同的文件中,每个文件构成了一个独立的模块,不同模块之间相同的变量名不会引起命名冲突。但是如果在文件a.py中希望使用文件b.py中的函数func1,则可以通过import在a中导入模块b,并通过b.func1()调用该方法。或者通过from直接引入模块中的函数。在引入时为了防止命名冲突,可以通过as为引入的函数起个别名

# 文件a.py中
import b
print(b.func1())

# 直接引入函数
from b import func1
print(func1())

# 使用别名
from b import func1 as f1
print(f1())

有时将相同类别的模块放在一个文件夹内,就形成了一个包,python要求一个包文件夹内必须有一个__init__.py文件才会识别为一个包,即使它是一个空文件。这时如果一个p1包内的a.py想访问p2包内的b.py中的函数func2,则操作如下

# p1/a.py文件内
import p2.b

print (p2.b.func2())

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python对象程序设计是一种编程范式,它将程序看作是一系列对象的集合,每个对象都有自己的属性和方法。在Python中,可以使用抽象基类(Abstract Base Class,ABC)来实现抽象类,抽象类是不能被实例化的类,只能被其它类继承和实现。 在Python中,定义一个类可以使用class关键字,可以在类中定义构造方法(__init__)和其他方法。构造方法用于初始化对象的属性,其他方法用于描述对象的行为。 例如,定义一个Car(汽车)类,可以使用构造方法来初始化汽车的名称,然后定义一个getName方法来获取汽车的名称。可以通过创建Car类的对象来使用这些方法。 另外,在Python中可以定义父类和子类,子类可以继承父类的属性和方法,并且可以重写父类的方法。可以使用super关键字来调用父类的方法。 例如,定义一个People(人)类,其中包括构造方法和公有方法speak,然后定义一个Student(学生)类,继承自People类,并且重写了speak方法。可以创建Student类的对象,并调用其自己定义的speak方法和父类的speak方法。 总之,Python面向对象程序设计提供了丰富的语法和特性,可以利用类、对象、继承和重写等概念来构建复杂的程序。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【python面向对象程序设计(基础篇)](https://blog.csdn.net/m0_67388084/article/details/128057443)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值