赞
踩
面向对象是Python最重要的特性,在Python中一切数据类型都是面向对象的。
面向对象的编程思想:按照真实世界客观事物的自然规律进行分析,客观世界中存在什么样的实体,构建的软件系统就存在什么样的实体。
例如:在学校里,有学生实体,学生是抽象的描述,称为“类”;而张同学、李同学等具体的学生个体称为“对象”,也称为“实例”;学生有学号、姓名、班级等属性,还有吃饭、走路等操作。
封装性:使外部访问者不能随意存取对象的内部数据,隐藏了对象的内部细节,只保留有限的对外接口。外部访问者不用关心对象的内部细节,操作对象变得简单。
继承性: 特殊类继承一般类,拥有一般类的全部数据和操作。一般类称为“父类”或“超类”,特殊类称为“子类”或“派生类”。
多态性:在父类中成员被子类继承后,可以具有不同的状态或表现行为。
Python中的数据类型都是类,类是组成Python程序的基本要素,它封装了一个类对象的数据和操作。
Python语言中一个类的实现包括类定义和类体。语法格式如下:
- class 类名[(父类)]:
- 类体
输入下面代码
- class Animal(): # 创建Animal类
- pass
- class Books(): # #创建Books类
- pass
-
- # 分别创建对应的类对象
- a = Animal()
- b = Books()
-
- print(id(Animal))
- print(type(Animal))
- print(type(a))
- print(type(b))
代码运行结果
- 1939387281408
- <class 'type'>
- <class '__main__.Animal'>
- <class '__main__.Books'>
-
- Process finished with exit code 0
注意:object类是所有类的根类,在Python中任何一个类都直接或间接的继承object;代码的pass语句表示什么操作都不执行,用来维持程序结构的完整。
一个对象的生命周期包括创建、使用和销毁。类实例化可生成对象,所以对象也称为“实例”。
创建对象就是在类对象的后面加上一对小括号,表示调用类对象的构造方法,这就创建了一个对象,示例代码如下
- class Animal:
- pass
- '''
- Animal()表达式创建了一个对象,并把创建的对象通过“=”赋给animal变量
- animal是指向对象的一个引用。通过animal可以使用刚刚创建的对象
- '''
- animal = Animal()
- # print函数实际上是调用了对象的__str__()方法(__str__()是object类的一个方法,
- # 用于返回有关该对象的描述信息)输出字符串信息
- print(animal)
代码运行结果
<__main__.Animal object at 0x000001A74F1F1970>
Python会实现自动的垃圾回收:当对象没有被引用时(引用计数为0),由垃圾回收器调用__del__()(析构函数),__del__()被称为“析构方法”,用于实现对象被销毁时所需的操作。比如:释放对象占用的资源(例如:打开的文档资源、网络连接等)。我们也可以通过del语句删除对象,系统会自动调用__del__()方法,一般不需要自定义析构方法。
示例代码如下
- class Person:
- def __del__(self):
- print("销毁对象:{0}".format(self))
- p1 = Person()
- p2 = Person()
- del p2
- '''
- 当 p2 的引用被 del 语句删除时
- p2 的 __del__ 方法会被调用
- 但是,p1 的 __del__ 方法可能在程序结束前不会被调用
- 因为它的引用仍然存在于变量 p1 中
- '''
- print("程序结束")
代码运行结果
- 销毁对象:<__main__.Person object at 0x000001B649C01AF0>
- 程序结束
- 销毁对象:<__main__.Person object at 0x000001B649C01AC0>
“实例变量”就是某个实例(或对象)个体特有的数据。
示例代码如下
- class Animal(object):
- def __init__(self,name,age,weight,gender):
- self.name = name # 定义姓名实例变量
- self.age= age # 定义年龄实例变量
- self.weight = weight # 定义体重实例变量
- self.gender =gender # 定义性别实例变量
- animal = Animal('Tom',18,66,1)
- animal1 = Animal('Mary',18,50,0)
-
- print("姓名:{0},年龄:{1},体重:{2}".format(animal.name,animal.age,animal.weight))
- print("男性" if animal.gender==1 else '女性')
- print("姓名:{0},年龄:{1},体重:{2}".format(animal1.name,animal1.age,animal1.weight))
- print("男性" if animal1.gender==1 else '女性')
代码运行结果
- 姓名:Tom,年龄:18,体重:66
- 男性
- 姓名:Mary,年龄:18,体重:50
- 女性
“类变量”是所有实例(或对象)共有的变量,需要在方法外定义,访问实例变量通过“实例名.实例变量名”的形式,而访问类变量“类名.类变量名”的形式访问。
示例代码如下
- class Account:
- interest_rate = 0.068 # 类变量
- # 重写构造方法
- def __init__(self,owner,amount):
- self.owner = owner
- self.amount = amount
- account = Account('Tony',1_800_000.0)
- # 查看实例变量
- print('account实例所有变量:{0}'.format(account.__dict__))
- # 为account.interest_rate变量赋值,此时无论类中是否有同名变量都会创建一个新的实例变量
- account.interest_rate = 0.01
- account.interest_rate2 = 0.01
- print('账户名:{0}'.format(account.owner))
- print('账号金额:{0}'.format(account.amount))
- print('利率:{0}'.format(Account.interest_rate))
- # 查看实例变量
- print('account实例所有变量:{0}'.format(account.__dict__))
代码运行结果
- account实例所有变量:{'owner': 'Tony', 'amount': 1800000.0}
- 账户名:Tony
- 账号金额:1800000.0
- 利率:0.068
- account实例所有变量:{'owner': 'Tony', 'amount': 1800000.0, 'interest_rate': 0.01, 'interest_rate2': 0.01}
注意:不要通过实例存取类变量数据。当通过实例读取变量时,Python解释器会先在实例中找这个变量,如果没有再到类中去找;当通过实例为变量赋值时,无论类中是否有该同名变量,Python解释器都会创建一个同名实例变量。
__init_()方法是构造方法,用来创建和初始化实例变量,定义时它的第一个参数应该是self,其后的参数才是用来初始化实例变量的;其中参数可以有默认值。调用构造方法时不需要传入self。如果未定义构造方法,则会自动调用默认的构造方法;一旦定义了构造方法,则不会调用默认的构造方法。
输入下面代码
- class Animal(object):
- # 构造方法
- def __init__(self,name='mark',age=20,weight=120,gender=120):
- self.name = name # 定义姓名实例变量
- self.age= age # 定义年龄实例变量
- self.weight = weight # 定义体重实例变量
- self.gender =gender # 定义性别实例变量
- animal0 = Animal() # 此时没有传入参数,参数为默认值
- animal = Animal('Tom',18,66,1)
- animal1 = Animal('Mary',18,50,0)
-
- print("姓名:{0},年龄:{1},体重:{2}".format(animal0.name,animal0.age,animal0.weight))
- print("姓名:{0},年龄:{1},体重:{2}".format(animal.name,animal.age,animal.weight))
- print("姓名:{0},年龄:{1},体重:{2}".format(animal1.name,animal1.age,animal1.weight))
代码运行结果
- 姓名:mark,年龄:20,体重:120
- 姓名:Tom,年龄:18,体重:66
- 姓名:Mary,年龄:18,体重:50
实例方法与实例变量一样都是某个实例个体特有的。定义实例方法时它的第一个参数应该是self,这个过程是将当前实例与该方法绑定起来,使该方法成为实例方法。
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.weight = weight
-
- def eat(self):
- self.weight += 0.05
- print("eat...")
-
- def run(self):
- self.weight -= 0.01
- print("run...")
- a1 = Animal(2,0,10.0)
- print('a1体重:{0:0.2f}'.format(a1.weight))
- a1.eat()
- print('a1体重:{0:0.2f}'.format(a1.weight))
- a1.run()
- print('a1体重:{0:0.2f}'.format(a1.weight))
代码运行结果
- a1体重:10.00
- eat...
- a1体重:10.05
- run...
- a1体重:10.04
类方法不需要与实例绑定,但需要与类绑定,定义时它的第一个参数是类的type实例。type是描述Python数据类型的类,Python中所有数据类型都是type的一个实例。类方法可以访问类变量和其他类方法,但不能访问其他实例方法和实例变量。
定义类方法:方法第一个参数cls是type类型的一个实例;方法使用装饰器@classmethod声明该方法是类方法。该方法不能调用实例属性,也不能调用实例方法。
示例代码如下
- class Account:
- interest_rate = 0.0668 # 类变量
- # 重写构造方法
- def __init__(self,owner,amount):
- self.owner = owner
- self.amount = amount
-
- # 类方法
- @classmethod
- def interest_by(cls,amt):
- return cls.interest_rate * amt
-
- interest = Account.interest_by(12_000.0)
- print('计算利息:{0:.4f}'.format(interest))
代码运行结果
计算利息:801.6000
如果定义的方法既不想与实例绑定,也不想与类绑定,只是想把类作为它的命名空间,那么可以定义静态方法。定义时使用@staticmethod装饰器,声明方法是静态方法,方法参数不指定self 和 cls。该方法不能调用实例属性,也不能调用实例方法。
示例代码如下
- class Account:
- interest_rate = 0.0668 # 类变量
- # 重写构造方法
- def __init__(self,owner,amount):
- self.owner = owner
- self.amount = amount
-
- # 类方法
- @classmethod
- def interest_by(cls,amt):
- return cls.interest_rate * amt
-
- @staticmethod
- def interst_with(amt):
- return Account.interest_by(amt)
- interest1 = Account.interest_by(12_000.0)
- print('计算利息:{0:.4f}'.format(interest1))
- interest2 = Account.interest_by(12_000.0)
- print('计算利息:{0:.4f}'.format(interest2))
代码运行结果
- 计算利息:801.6000
- 计算利息:801.6000
示例代码如下
- class Person():
- def __init__(self,name,age):
- self.name = name
- self.age = age
- def show(self):
- print(f'我的名字是{self.name},我的年龄是{self.age}')
-
- person1 = Person('张三',18)
- person2 = Person('李四',19)
-
- # 为person2动态绑定属性
- person2.gender = 'male'
- # 为person2动态绑定方法
- def method():
- print('这是用于动态绑定的方法')
- person2.fun = method
- # 输出绑定的属性
- print(person2.gender) # person1并没有gender属性
- person2.fun() # person1并没有fun()方法
代码运行结果
- male
- 这是用于动态绑定的方法
-
- Process finished with exit code 0
默认情况下,Python中的变量是公有的,可以在类的外部访问他们。如果想让他们成为私有变量,可以在变量前加上双下划线“__”,双下划线开头表示private私有的成员,这类成员只允许定义该属性或方法的类本身进行访问。如果以单下划线开头的属性或方法表示protected受保护的成员,这类成员被视为仅供内部使用,允许类本身和子类进行访问,但实际上它可以被外部代码访问。而首尾双下划线一般表示特殊的方法。
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__wight = weight
-
- def eat(self):
- self.__wight += 0.05
- print("eat...")
-
- def run(self):
- self.__wight -= 0.01
- print("run...")
-
- a1 = Animal(2,0,10.0) # 该段代码发生错误,因为weight是私有变量,无法在类的外部访问
- print('a1体重:{0:0.2f}'.format(a1.weight))
- a1.eat()
- a1.run()
代码运行结果
Python语言并不像Java,私有变量只是形式上私有,并非严格意义上的私有;如果想要访问私有变量,可以通过 对象名._类名__变量名 来访问,但是一般不推荐这么做,因为这违反了封装的原则,使代码的维护变得困难(可见Python的封装性靠的是程序员的自律,而非强制性的语法)。
输入下面代码
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__weight = weight #定义私有变量
-
- def eat(self):
- self.__weight += 0.05
- print("eat...")
-
- def run(self):
- self.__weight -= 0.01
- print("run...")
-
- a1 = Animal(2,0,10.0)
- print('a1体重:{0:0.2f}'.format(a1._Animal__weight))
- a1.eat()
- a1.run()
- # 通过内置函数dir打印对象的属性和方法
- print(dir(a1))
代码运行结果
- a1体重:10.00
- eat...
- run...
- ['_Animal__weight', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'eat', 'run', 'sex']
推荐的做法是定义一个公共方法来访问
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__weight = weight #定义私有变量
-
- def eat(self):
- self.__weight += 0.05
- print("eat...")
-
- def run(self):
- self.__weight -= 0.01
- print("run...")
-
- def get_weight(self): # 添加一个公共方法来获取私有变量的值
- return self.__weight
-
- a1 = Animal(2,0,10.0)
- print('a1体重:{0:0.2f}'.format(a1.get_weight()))
- a1.eat()
- a1.run()
- print('a1体重:{0:0.2f}'.format(a1.get_weight()))
代码运行结果
- a1体重:10.00
- eat...
- run...
- a1体重:10.04
私有方法与私有变量是类似的,只要在方法前加上双下划线“__”就是私有方法,在类外面强制使用也是“对象名._变量名__方法名”(不推荐)。
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__weight = weight #定义私有变量
-
- def eat(self):
- self.__weight += 0.05
- print("eat...")
-
- def __run(self):
- self.__weight -= 0.01
- print("run...")
-
- def get_weight(self): # 添加一个公共方法来获取私有变量的值
- return self.__weight
-
- a1 = Animal(2,0,10.0)
- print('a1体重:{0:0.2f}'.format(a1.get_weight()))
- a1.eat()
- a1._Animal__run() #强制访问,不推荐这样做
- print('a1体重:{0:0.2f}'.format(a1.get_weight()))
代码运行结果
- a1体重:10.00
- eat...
- run...
- a1体重:10.04
在实际的面向对象设计中,一个类是不应该有公有的实例成员变量的,这些实例成员变量被设计为私有的,然后通过共有的 setter 和 getter 访问器访问。(访问器形式的封装需要一个私有变量,需要提供 setter 和 getter 访问器,只读变量不用提供 setter 访问器)
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__weight = weight #定义私有变量
-
- def eat(self):
- self.__weight += 0.05
- print("eat...")
-
- def __run(self):
- self.__weight -= 0.01
- print("run...")
-
- def get_weight(self): # 添加一个公共方法来获取私有变量的值
- return self.__weight
-
- def set_weight(self,weight): # 添加一个set方法来访问
- self.__weight = weight
-
- a1 = Animal(2,0,10.0) # 该段代码发生错误,因为weight是私有变量,无法在类的外部访问
- print('a1体重:{0:0.2f}'.format(a1.get_weight()))
- a1.set_weight(20.00)
- print('a1体重:{0}'.format(a1.get_weight()))
代码运行结果
- a1体重:10.00
- a1体重:20.0
访问器形式的封装在编写代码时比较麻烦,Python提供了属性(poperty),定义属性可以使用@property(将一个方法转换成属性去使用,即定义形式是方法,使用时可以将该方法当成属性来用,也就是不需要加括号)和 @属性名.setter装饰器(通过@property设置之后就只能访问不能修改,如果想要修改可以再定义@属性名.setter方法)。
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__weight = weight #定义私有变量
- @property
- def weight(self): # 添加一个公共方法来获取私有变量的值
- return self.__weight
-
- @weight.setter
- def weight(self,weight): # 添加一个set方法来访问
- self.__weight = weight
-
- a1 = Animal(2,0,10.0) # 该段代码发生错误,因为weight是私有变量,无法在类的外部访问
- print('a1体重:{0:0.2f}'.format(a1.weight))
- a1.weight = 20.0
- print('a1体重:{0}'.format(a1.weight))
代码运行结果
- a1体重:10.00
- a1体重:20.0
示例代码二:加深对装饰器的理解
示例代码如下
- class Person():
- def __init__(self,name,age):
- self.name = name
- self.__age = age
- @property
- def age(self):
- return self.__age
-
- @age.setter
- def age(self,value):
- if value<0 or value>150:
- print('年龄不在有效范围,已将年龄设置为默认18')
- self.__age = 18
- else:
- self.__age = value
-
- person = Person('张三',18)
- print(person.name,person.age)
- person.age = 190
- print(person.age)
代码运行结果
- 张三 18
- 年龄不在有效范围,已将年龄设置为默认18
- 18
-
- Process finished with exit code 0
多态性的前提是继承性,子类继承父类时只是继承父类中公有的成员变量和方法,不能继承私有的成员变量和方法。
示例代码如下
- class Person:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.__weight = weight #定义私有变量
-
- class Student(Person): # Student继承了Person类
- def __init__(self,name,age,school):
- super().__init__(name,age)
- # 定义子类的构造方法时先要调用父类的构造方法,初始化父类实例变量
- self.school = school
如果子类方法名与父类方法名相同,而且参数列表也相同,只是方法体不同,那么子类重写了父类的构造方法;此时在用子类对象调用该方法时,会执行子类的该方法,而不是父类的。
示例代码如下
- class Animal:
- def __init__(self,age,sex=1,weight=0.0):
- self.age = age
- self.sex = sex
- self.weight = weight #定义私有变量
- def eat(self):
- self.weight += 0.1
- print("动物吃...")
-
-
- class Dog(Animal):
- def eat(self):
- self.weight += 0.1
- print("狗狗吃...")
-
- a1 = Dog(2,0,10.0)
- a1.eat()
代码运行结果
狗狗吃...
多继承就是一个子类继承多个父类,在Java中只能单继承,因为多继承会发生方法冲突。Python支持多继承,当子类实例调用一个方法时,先从子类中查找,如果没有则查找父类,查找父类的顺序是按照子类声明的父类列表从左到右查找,若没有则查找父类的父类。
示例代码如下
- class ParentClass1:
- def run(self):
- print('ParentClass1 run...')
-
- class ParentClass2:
- def run(self):
- print('ParentClass2 run...')
-
- class SubClass1(ParentClass1,ParentClass2):
- pass
-
- class SubClass2(ParentClass2,ParentClass1):
- pass
-
- class SubClass3(ParentClass1,ParentClass2):
- def run(self):
- print('SubClass3 run...')
-
- sub1 = SubClass1()
- sub1.run()
- sub2 = SubClass2()
- sub2.run()
- sub3 = SubClass3()
- sub3.run()
代码运行结果
- ParentClass1 run...
- ParentClass2 run...
- SubClass3 run...
示例二:加深对多继承的理解
示例代码如下
- # 在多继承时需要调用多个父类的方法进行初始化时,此处定义了A、B两个父类
- class FatherA():
- def __init__(self,name):
- self.name = name
- def showA(self):
- print('我是FatherA中的方法')
- class FatherB():
- def __init__(self,age):
- self.age = age
- def showB(self):
- print('我是FatherB中的方法')
- class Son(FatherA,FatherB):
- def __init__(self,name,age,gender):
- # 此时不能再用super()来调用,因为无法区分哪个父类,因此需要直接指明调用哪个父类
- FatherA.__init__(self,name)
- FatherB.__init__(self,age)
- self.gender = gender
-
- son = Son('CSDN@邂逅自己',18,'female')
- son.showA()
- son.showB()
代码运行结果
- 我是FatherA中的方法
- 我是FatherB中的方法
-
- Process finished with exit code 0
发生多态有两个前提条件:
示例代码如下
- class Figure:
- def draw(self):
- print("Figure draw...")
-
- class Ellipse(Figure):
- def draw(self):
- print("Ellipse draw...")
-
- class Triangle(Figure):
- def draw(self):
- print("Triangle draw...")
-
- f2 = Ellipse()
- f2.draw()
- f3 = Triangle()
- f3.draw()
代码运行结果
- Ellipse draw...
- Triangle draw...
案例二:加深对多态的理解
示例代码如下
- # 多态可以在程序运行过程中动态决定调用哪个方法
- # 该代码说明了在Python中要实现多态不需要对象之间有继承关系、也不关心对象的数据类型
- # 需要有同名方法,即便在一开始不知道数据类型
- class Person():
- def show(self):
- print('我是Person的show方法')
- class Dog():
- def show(self):
- print('我是Dog的show方法')
- class Cat():
- def show(self):
- print('我是Cat的show方法')
- def fun(obj):
- obj.show()
- person = Person()
- dog = Dog()
- cat = Cat()
-
- fun(person)
- fun(dog)
- fun(cat)
代码运行结果
- 我是Person的show方法
- 我是Dog的show方法
- 我是Cat的show方法
-
- Process finished with exit code 0
与Java语言相比,多态性对于动态语言Python而言意义不大。但是无论多态性对Python的多大,Python作为面向对象的语言多态性是存在的。
函数 | 描述 |
---|---|
isinstance(object,classinfo) | 可以检查 object 实例是否由 classinfo 类或 infoclass 子类所创建的实例 |
issubclass(class,classinfo) | 可以检查 class 是否是 classinfo 的子类 |
示例代码如下
- class Figure:
- def draw(self):
- print("Figure draw...")
-
- class Ellipse(Figure):
- def draw(self):
- print("Ellipse draw...")
-
- class Triangle(Figure):
- def draw(self):
- print("Triangle draw...")
- f1 = Figure()
- f2 = Ellipse()
- f3 = Triangle()
- print(isinstance(f2,Figure)) # True
- print(isinstance(f3,Figure)) # True
- print(isinstance(f1,Figure)) # True
- print(isinstance(f1,object)) # True,因为任何类都是 object 类的子类
- print(issubclass(Figure,object)) # True
- print(issubclass(Ellipse,Triangle))# False
代码运行结果
- True
- True
- True
- True
- True
- False
不关注变量的类型,而是关注变量具有的方法。鸭子类型像多态一样工作,但是没有继承,只要像“鸭子”一样的行为(方法)就可以了。(用“鸭子类型”代替多态性设计能够充分发挥Python动态语言特点,但是对程序员要求也非常高)
示例代码如下
- class Animal(object):
- def run(self):
- print("Animal run...")
-
- class Dog(Animal):
- def run(self):
- print("Dog run...")
-
- class Car:
- def run(self):
- print("Car run...")
-
- def go(animal):
- if not isinstance(animal, (Animal, Car)): # 检查 animal 是否为 Animal 或 Car 的实例
- return # 如果不是,则作为递归的基案结束递归
- animal.run() # 调用 run 方法
-
- # 创建实例
- animal_instance = Animal()
- dog_instance = Dog()
- car_instance = Car()
-
- # 使用实例调用 go 函数
- go(animal_instance)
- go(dog_instance)
- go(car_instance)
- #添加了一个类型检查来确保只有 Animal 或 Car 的实例才会调用 run 方法。如果传入的不是这些类的实例,#go 函数将直接返回,避免递归调用。
代码运行结果
- Animal run...
- Dog run...
- Car run...
Python所有类都直接或间接的继承 object 类,因此所有类拥有object类的属性和方法;object类有很多方法。
方法 | 描述 |
---|---|
__str__() | 默认返回对象的类名,以及内存地址等信息;可以重写该方法,输出描述信息 |
__eq__() | 重写该方法指定相等的规则(即指定比较的是哪些实例变量相等) |
__new__() | 由系统调用,用于创建对象 |
__init__() | 创建对象时手动调用,用于初始化对象属性值 |
示例代码1如下
- class Person:
- def __init__(self,name,age):
- self.name = name
- self.age = age
-
- def __str__(self): # 重写str方法,返回什么样的字符串可以自己指定
- template = 'Person[name={0},age={1}]'
- s = template.format(self.name,self.age)
- return s
- Person = Person('Tony',18)
- print(Person)
代码运行结果
Person[name=Tony,age=18]
示例代码2如下
- class Person:
- def __init__(self,name,age):
- self.name = name
- self.age = age
-
- def __str__(self): # 重写str方法,返回什么样的字符串可以自己指定
- template = 'Person[name={0},age={1}]'
- s = template.format(self.name,self.age)
- return s
-
- def __eq__(self,other): # 重写eq方法,指定只有姓名和年龄都相等时才是True
- if self.name == other.name and self.age == other.age:
- return True
- else:
- return False
-
- p1 = Person('Tony',18)
- p2 = Person('Tony',18)
- p3 = Person('Mary',18)
- print(p1 == p2)
- print(p1 == p3)
代码运行结果
- True
- False
示例代码3如下
- class Person():
- def __init__(self,name,age):
- self.name = name
- self.age = age
- def __str__(self):
- return '我是重写str方法后输出的内容'
- person = Person('CSDN@邂逅自己',18)
- # 若不重写str方法
- # 则输出对象时是输出内存地址<__main__.Person object at 0x000002516EDB5D90>
- # 重写str方法后
- # 则输出对应的内容,如果有的话
- print(person)
代码运行结果
- 我是重写str方法后输出的内容
-
- Process finished with exit code 0
实际上,在Python中使用运算符时也是通过调用特殊方法来实现的
运算符 | 特舒方法 | 描述 |
---|---|---|
+ | _add_() | 执行加法运算 |
- | _sub_() | 执行减法运算 |
<,<=,== | _It_(),_le_(),_eq_() | 执行比较运算 |
>,>=,!= | _gt_(),_ge_(),_ne_() | 执行比较运算 |
*, / | _mul_(),_truediv_() | 执行乘法运算,非整数运算 |
%,// | _mod_(),_floordiv_() | 执行取余运算,整除算法 |
** | _pow_() | 执行幂运算 |
特殊属性 | 说明 |
---|---|
obj.__dict__ | 对象的属性字典,使用语法:对象名.__dict__ |
obj.__class__ | 对象所属的类,使用语法:对象名.__class__ |
class.__bases__ | 类的父类元组,使用语法:类名.__bases__ |
class.__base__ | 类的父类,使用语法:类名.__base__ |
class.__mro__ | 类的层次结构,使用语法:类名.__mro__ |
class._subclasses | 类的子类列表 |
示例代码如下
- class FatherA():
- pass
- class FatherB():
- pass
- class son(FatherA,FatherB):
- def __init__(self,name,age):
- self.name = name
- self.age = age
-
- a = FatherA()
- b = FatherB()
- c = son('张三',18)
- print('-'*20,'__dict__','-'*20) # 输出对象的属性字典
- print(a.__dict__)
- print(b.__dict__)
- print(c.__dict__)
- print('-'*20,'__class__','-'*20) # 输出对象所属的类
- print(a.__class__)
- print(b.__class__)
- print(c.__class__)
- print('-'*20,'__bases__','-'*20) # 输出父类元组
- print(FatherA.__bases__)
- print(FatherB.__bases__)
- print(son.__bases__)
- print('-'*20,'__base__','-'*20) # 输出所属的父类
- print(FatherA.__base__)
- print(FatherB.__base__)
- print(son.__base__) # 如果继承了多个父类,结果只显示第一个父类,要想知道所有的父类需要用__bases__
- print('-'*20,'__mro__','-'*20) # 输出类的层次结构
- print(FatherA.__mro__)
- print(FatherB.__mro__)
- print(son.__mro__)
- # 输出结果解析,以 (<class '__main__.son'>, <class '__main__.FatherA'>, <class '__main__.FatherB'>, <class 'object'>)
- # 为例,其中,为分隔符 ,前面表示son类,中间的内容表示son类继承了FatherA和FatherB,最后内容白叟son类又间接继承了object类
- print('-'*20,'__subclasses__','-'*20) # 输出类的子类列表
- print(FatherA.__subclasses__())
- print(FatherB.__subclasses__())
- print(son.__subclasses__())
代码运行结果
- -------------------- __dict__ --------------------
- {}
- {}
- {'name': '张三', 'age': 18}
- -------------------- __class__ --------------------
- <class '__main__.FatherA'>
- <class '__main__.FatherB'>
- <class '__main__.son'>
- -------------------- __bases__ --------------------
- (<class 'object'>,)
- (<class 'object'>,)
- (<class '__main__.FatherA'>, <class '__main__.FatherB'>)
- -------------------- __base__ --------------------
- <class 'object'>
- <class 'object'>
- <class '__main__.FatherA'>
- -------------------- __mro__ --------------------
- (<class '__main__.FatherA'>, <class 'object'>)
- (<class '__main__.FatherB'>, <class 'object'>)
- (<class '__main__.son'>, <class '__main__.FatherA'>, <class '__main__.FatherB'>, <class 'object'>)
- -------------------- __subclasses__ --------------------
- [<class '__main__.son'>]
- [<class '__main__.son'>]
- []
-
- Process finished with exit code 0
类的浅拷贝与深拷贝
示例代码如下
- class CPU():
- pass
- class Disk():
- pass
- class computer():
- def __init__(self,cpu,disk):
- self.cpu = cpu
- self.disk = disk
- cpu = CPU()
- disk = Disk()
- computer = computer(cpu,disk)
- # 变量赋值
- computer1 = computer
- print(computer,'子对象的内存地址',computer.cpu,computer.disk)
- print(computer1,'子对象的内存地址',computer1.cpu,computer1.disk)
- # 类对象的拷贝
- print('-'*20,'类对象的浅拷贝','-'*20)
- import copy
- computer2 = copy.copy(computer) # computer2是新产生的子对象,但是cpu和disk不变
- print(computer2,'computer2子对象的内存地址',computer2.cpu,computer2.disk)
- # 类对象的深拷贝
- print('-'*20,'类对象的深拷贝','-'*20)
- computer3 = copy.deepcopy(computer) # computer2、cpu和disk都是新产生的子对象
- print(computer3,'computer3子对象的内存地址',computer3.cpu,computer3.disk)
代码运行结果
- <__main__.computer object at 0x0000025DDC896840> 子对象的内存地址 <__main__.CPU object at 0x0000025DDC8968A0> <__main__.Disk object at 0x0000025DDC896810>
- <__main__.computer object at 0x0000025DDC896840> 子对象的内存地址 <__main__.CPU object at 0x0000025DDC8968A0> <__main__.Disk object at 0x0000025DDC896810>
- -------------------- 类对象的浅拷贝 --------------------
- <__main__.computer object at 0x0000025DDC896990> computer2子对象的内存地址 <__main__.CPU object at 0x0000025DDC8968A0> <__main__.Disk object at 0x0000025DDC896810>
- -------------------- 类对象的深拷贝 --------------------
- <__main__.computer object at 0x0000025DDC8CEAE0> computer3子对象的内存地址 <__main__.CPU object at 0x0000025DDC8CEBA0> <__main__.Disk object at 0x0000025DDC8CEC00>
-
- Process finished with exit code 0
参考书籍:《python从小白到大牛》(第2版)关东升 编著
文章创作不易,本文18000+字,为了大家能理解,写的很详细,这也让我花了很多时间。最后,如果觉得本文对大家有帮助的话,还请给我点个赞和关注,谢谢大家!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。