python面向对象

python进阶语法

说明

补充MOOC上嵩老师的python语言程序设计课程未涉及的语法部分以及一些python相关基础,个人笔记。

一.交互式命令

python的一种使用方式是交互式,即写一行命令执行一行并出结果,就像matlab一样,可以当做一个简单的计算器,进行基本的四则运算和简单内置数学函数运算(如sin,cos,tan等,差不多就像所有编程语言里都带的一样,需要导入math包,math包提供对底层c函数库的访问);另外python可以向matlab一样清除当前的变量,有一些简单的命令:

命令描述
del 变量名删除某个变量
_下划线表示当前计算结果,就像matlab里的ans一样

同样就像matlab一样,脚本方式运行产生的变量也在当前工作空间,脚本运行结束后,在IDLE中仍能使用脚本中定义的变量,而函数中的变量(如果不是全局)就只是函数局部的变量,函数外不可用(这个与其他任何语言一样,很好理解)。

二.面向对象语法

这是我主要想补充的内容:

1.基本
  • 基本概念

    • 面向对象的基本概念与其他任何OOP编程语言类似,不作赘述
    • 类变量与实例变量:类变量就像c++里的静态变量一样,它是属于类的,而不是某个实例对象的;实例变量则是一般实例对象的变量。在python中由于并不需要提前声明变量,所以实例变量都是在函数体里定义的,在类体里(函数外)定义的则都是类变量,为所有实例对象所共有。
  • 类的定义

    python中定义一个类很简单,如:

    class Student:
        def __init__(self,name,id):
            self.name=name
            self.id=id
            Student.studentCount+=1
        def introduce(self):
            print('my name is {}, my student id \
            is {}'.format(self.name,self.id))
        studentCount=0
    
    • 类定义用关键字class,类名称之后加冒号:就和函数开头一样,之后是类体
    • __init__是构造函数,如果不写会给一个默认的无参构造函数
    • 类里面成员函数的第一个参数都是self,但是self并不是一个关键字,它只代表实例化的类对象,可以用其他任何词代替(比如c++里的this),但是惯例是用self表示该实例
    • 类变量定义在类体里函数外(如studentCount),为所有实例共有,使用时用类名.类变量的方法,如构造函数中Student.studentCount;实例变量使用时用实例名.实例变量名的方法,如 self.name
    • 实例变量对类变量的覆盖。如果构造函数中不小心写成了self.studentCount+=1,则是对具体的一个实例里的studentCount递增1,这里其实是对类变量studentCount在具体的一个实例范围下递增1,相当于把类变量实例化了;而如果误写成self.studentCount=1,那就真是新定义了一个实例变量把类变量覆盖掉了。综上,严格按照上一点说明的方法使用类变量与实例变量是一个好习惯,不容易造成无意识的覆盖

    另外需要补充一点的是,构造函数不能像c++一样提供多个版本(不能重载),这其实是所有函数的特性,如果定义两个同名函数,参数个数不一样,后面的函数定义会覆盖之前的;python提供函数“重载”的方法是通过默认参数及可变参数实现的

  • 类的实例化

    s1=Student('Li Hua',14131007)
    print(isinstance(s1,Student))
    
    • 类的实例化。python用类名加括号生成类实例,会自动调用相应的构造函数__init__,如上述代码,生成一个Student类的实例,然后赋值给s1变量(python中对象的赋值是引用赋值,即s1与新生成的对象是同一个)
    • 通过isinstance(变量名,类名)判断变量是否为类的一个实例
  • 类的使用

    s1.introduce()#访问成员函数
    print(s1.name)#访问实例变量
    print(Student.studentCount)#访问类变量
    print('共有{}位学生'.format(s1.studentCount))#通过实例对象访问类变量
    s1.age=18
    print("芳华{}".format(s1.age))
    Student.school="BUAA"
    print("学校为:{}".format(s1.school))
    del s1.age
    del Student.school
    
    • python中成员函数的调用。用法为:实例对象.函数名,需要注意,虽然成员函数定义时第一个参数都是self,但是调用的时候并不需要给定这个参数,它会自动把.成员符之前的实例对象变量名作为第一个参数
    • 类变量与实例变量的使用。通过实例对象.实例变量名访问实例变量,通过类名.类变量访问类变量,这是我认为比较好的方法。当然也可以通过实例对象.类变量名访问类变量,但是建议只读的时候才这么做,因为如果用这种方式更改类变量并不能收效,因为它会把类变量实例化了,或者说局部化了,意思是生成了一个实例变量覆盖了同名类变量
    • 类及其实例对象就像一个口袋,可以直接向里面放原本没有的变量。如直接s1.age=18,相当于添加了一个age变量于s1实例中;类也是一样,可以直接向里面放新的类变量。当然,添加的变量也像一般变量一样,可以用del删除掉
2.继承
class Animal:
    def __init__(self,legs):
        self.legs=legs
    def show(self,end="\n"):
        print("animal with {} legs".format(self.legs),end=end)
class IBark:
    def __init__(self,count):
        self.count=count
    def bark(self):
        print("bark {} times".format(self.count))
    def show(self):
        print("bark...")

class Dog(Animal,IBark):
    def __init__(self,color,count=5):
        Animal.__init__(self,4)
        IBark.__init__(self,count)
        #super(Dog,self).__init__(4)#只会调用Animal的__init__函数
        self.color=color
    def show(self):
        Animal.show(self,",")
        print("a {} dog".format(self.color))
    def bark(self):
        print("a {} dog".format(self.color),end=" ")
        IBark.bark(self)

a1=Animal(3)
a1.show()
d1=Dog("black")
d1.show()#覆盖父类同名方法,调用子类的show()方法
d1.bark()
super(Dog,d1).show()#调用父类被覆盖方法
print(issubclass(Dog,IBark))
  • 继承的基本语法是class 子类名(父类名):然后跟类体,其中父类名可以是多个表示多继承
  • 子类定义与父类同名方法则覆盖父类的方法
  • 子类如果不定义__init__函数则默认调用父类的构造函数;如果是多继承,默认只调用第一个父类的构造函数
  • 子类如果定义__init__函数,则不自动调用父类构造函数,需要手动调用,方法为父类名.__init__(参数列表);也可以用super(子类名,self).__init__(参数列表),但是这显然不适合多继承,因为多继承情况下这种方法只会调用第一个父类构造函数。另外super调用父类被覆盖方法也适用于类外,同样的只会调用多继承中第一个含有该方法父类的此方法
  • 成员方法调用时,先查找子类中有无该方法,如果没有,按顺序逐个查找父类有无该方法
  • 判断两个类是否有继承关系,用issubclass(子类名,父类名)判断
3.多态

多态按照百度百科的解释为:同一操作作用于不同的对象可以有不同的解释,产生不同的执行结果。在c++中多态通过虚函数、抽象类、覆盖和模板实现;在java中通过抽象类、覆盖和接口实现。在python中同理也是通过覆盖(函数重写)实现的,差别不大。因为python中没有类型声明,所以也没有什么向上转型的问题。

4.封装
  • 封装主要是将实现细节对外隐藏,外部只需要知道类有哪些接口,至于具体怎么实现,外部不关心。封装主要体现在权限控制,比如c++中类中public的属性、方法为对外公共接口;private的为私有属性、方法,外部不可访问;protected的为外部不可访问,仅自身及其子类可访问
  • 在python中,变量或方法前加单下划线_的为保护(protected)成员;变量或方法前加双下划线__且尾部不加下划线的为私有(private)成员
  • 在python中对权限设置的也不是那么严格,因为虽然不可以直接用对象名.__私有属性名的方式访问私有属性,但是可以通过对象名._类名__私有属性名(注意先是单下划线后是双下划线)访问私有属性
5.动态

动态语言是一种运行时可以改变自身结构的语言,比如python就是一种动态语言,如上所述,python中的类或实例在运行时可以向其中加入新的属性,原有属性也可以被删除,这是语言的动态性。比如有以下类的定义及其实例:

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def speak(self):
        print("my name is {},I'm {} years old".format(self.name,self.age))
        
p1=Person("Li Dong",23)
p1.speak()
#------------------------------------------------------#
p1.height=175#向实例中添加属性
print(p1.height)
Person.nation="China"#向类中添加属性
print("I'm form {}".format(p1.nation))
print(getattr(p1,'age'))#访问p1中age属性的值
#访问p1中fat_or_not属性的值,如果该属性不存在返回给定的默认值
print(getattr(p1,'fat_or_not',"we don't know"))
delattr(p1,'height')#输出p1实例中的height属性
print(hasattr(p1,'height'))#判断height属性在实例p1中是否存在

#添加类方法,不需要导入库
@classmethod
def print_msg2(cls):
    print("added method2")
Person.print_msg2=print_msg2
Person.print_msg2()#调用增添的方法2
#添加实例方法(要导入types库)
import types
def print_msg1(self):
    print("added method1")
p1.print_msg1=types.MethodType(print_msg1,p1)
p1.print_msg1()#调用增添的方法1
del Person.print_msg2
del p1.print_msg1
  • 增删访问属性。可以直接按照常规的对象名.实例变量名访问属性,也可以用getattr(obj,name[,default])方法访问属性;可以直接通过对象名.实例变量名=变量值来设置属性值(如果不存在添加),也可以通过setattr(obj,name,value)来设置属性;可以通过del 对象名.实例变量名来删除属性,也可通过delattr(obj,name)来删除属性;通过hasattr(obj,name)来判断属性是否存在。注意:上述的属性名称name都是用字符串形式指定
  • 如果想在类定义的时候限制有哪些属性,可以定义一个类变量__slots__=一个由所有属性构成的元组,这样之后就不能再向该类或者他的实例中添加属性了,但是删除属性仍然是可以的
  • 增删方法。添加实例方法和类方法如上代码,其中添加类方法的cls参数同样只是一个名称不是关键字,代表当前类,可以通过它使用类变量及其他类方法;另外可以增添静态方法,只要把@classmethod改成@staticmethod就可,静态方法不需要第一个参数是self或者cls。删除方法直接del 实例对象.实例方法名del 类名.类方法名
  • 另外要知道,类的归类,实例的归实例,访问实例的变量、方法都用实例名加成员运算符;访问类的变量、方法都用类名加成员运算符。尽管实例也可访问类的变量、方法,尽量不要这么做
6.内置属性
  • __dict__:类的属性,包含类的所有数据属性(类变量和类方法)的一个字典;如果用对象.__dict__则是返回对象的属性、方法字典,不包含类变量、类方法
  • __doc__:类的文档字符串,在类名冒号之后第二行的字符串为类的说明文档,使用__doc__属性返回的即是这个字符串
  • __name__:类名
  • __module__:类定义所在的模块,一般没声明则为__main__模块。关于python模块的自定义回头再说,先参考python自定义模块
  • __bases__:类的所有父类构成的元组
7.下划线特殊命名

仅前面加单、双下划线的是保护、私有成员,这个前面已经说明过了;

前后均加双下划线的是:

  • 类的内置属性——如6中所述

  • 基础重载方法——比如__init__函数、__del__函数等

    方法描述调用
    __init__(self[,args])构造函数obj=className(args)
    __del__(self)析构函数del obj
    __repr__(self)转化为供解释器读取的形式repr(obj)
    __str__(self)转化为人阅读的形式(转化为字符串)str(obj)
  • 运算符重载方法

    如:

    class Complex:
        def __init__(self,real,imag):
            self.real=real
            self.imag=imag
        def show(self,end="\n"):
            flag="+" if self.imag>=0 else "-"
            print("{}{}{}i".format(self.real,flag,abs(self.imag)))
        def __add__(self,other):
            return Complex(self.real+other.real,self.imag+other.imag)
        
    c1=Complex(1,2)
    c2=Complex(2,-3)
    c3=c1+c2
    c1.show()
    c2.show()
    c3.show()
    

    __add__函数重载了+运算符。python中可供重载的运算符有众多算术运算符、比较运算符等,具体参看python运算符重载

三.其他

1.迭代器

迭代器是用来遍历集合元素的。用迭代器遍历的方法如下:

ls=range(1,11)
it=iter(ls)
while True:
    try:
        print(next(it))
    except StopIteration:
        print('over')
        break

迭代器遍历是通过抛出异常结束的。实际上,一个类只要实现了__iter__函数和__next__函数就可以生成迭代器进行迭代遍历,比如:

class Group:
    def __init__(self,start,stop,step=1):
        self.ls=range(start,stop,step)
    def __iter__(self,count=10):
        self.index=0
        self.count=min(count,len(self.ls))
        return self
    def __next__(self):
        if self.index<self.count:
            x=self.ls[self.index]
            self.index+=1
            return x
        else:
            raise StopIteration

s1=Group(1,100)	#生成1到100的"群组"
it=iter(s1)		#生成前十个元素的迭代器	#调用了__iter__函数
while True:
    try:
        print(next(it))
    except StopIteration:
        break
2.列表推导式

列表推导式用于快速由一个列表的元素生成另一个列表,原先我们只能遍历操作,比如:

#生成1-10的平方列表
ls=[]
for i in range(1,11):
    ls.append(i**2)
print(ls)

但是使用列表推导式可以直接在ls定义的时候赋值,而不必用一个遍历循环:

ls=[i**2 for i in range(1,11)]

另外,range(1,11)可以换成其他组合数据类型,i**2可以换成其他表达式或者函数:

def aCmplxFunc(x):
    return 3*x**2+2*x-4
lt=[1,3,6,4,8,2,9]
ls=[aCmplxFunc(i) for i in lt]
print(ls)

参考链接:

菜鸟教程python3面向对象

python中向类中动态添加新特性及删除属性方法

多态

列表推导式

python基础知识-列表推导式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python面向对象编程是一种编程范式,它将程序组织成对象的集合,每个对象都有自己的属性和方法。在Python中,可以通过定义类来创建对象,并通过实例化类来创建具体的对象。引用[1]中的代码示例展示了一个Animal类,其中包含了初始化方法和一个__str__方法来返回对象的描述信息。通过这个类,可以创建Animal对象,并通过print函数输出对象。引用中的代码示例展示了如何使用@property装饰器来定义类的属性和属性的访问方法。通过这种方式,可以在访问属性时像访问普通属性一样使用点号,而不需要使用方法调用的方式。引用中的代码示例展示了多态在Python中的应用。多态是面向对象编程的重要概念,它允许不同的对象以相同的方式对外部访问,但具体的实现可能不同。在这个示例中,father、son和daughter类都继承了father类,并重写了tell方法。通过调用不同的对象的tell方法,可以看到不同的输出结果。总之,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/Thewei666/article/details/126652501)[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、付费专栏及课程。

余额充值