10.5 return返回值
函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。
函数返回的值被称为返回值。
在函数中,可使用return语句将值返回到调用函数的代码行。
返回值让你能够将程序的大部分繁重工作移到函数中完成,从而简化主程序。
例1: 返回简单值
def get_formatted_name(first_name, last_name): """返回整洁的姓名""" full_name = first_name + " " + last_name return full_name.title() musician = get_formatted_name('z', 'db') print(musician)
Z Db
(1)如果函数没有返回值【函数执行完毕之后,不需要给调用处提供数据】,return可以省略不写
(2)函数的返回值,如果是1个,直接返回类型
(3)函数的返回值,如果是多个,返回的结果为元组
函数在定义时,是否需要返回值,视情况而定
def fun1(): print('hello') # return fun1() def fun2(): return 'hello' res = fun2() print(res) def fun3(): return 'hello', 'world' print(fun3())
hello hello ('hello', 'world')
例2: 返回字典
def your_name(first_name, last_name): """返回一个字典,其中包含有关一个人的信息""" person = {'姓': first_name, '名': last_name} return person name = your_name('z', 'db') print(name)
{'姓': 'z', '名': 'db'}
例3: 字典添加元素
def your_name(first_name, last_name, age=' '): """返回一个字典,其中包含有关一个人的信息""" person = {'姓': first_name, '名': last_name} if age: # 有age就赋值,没有不赋值 person['年龄'] = age # 将输入的age赋值给字典键age对应的值 return person name = your_name('z', 'db', age=22) print(name)
{'姓': 'z', '名': 'db', '年龄': 22}
例4:结合使用函数和while循环
版本一:无线循环,不能停止
def your_name(first_name, last_name): """返回整洁的姓名""" full_name = first_name + " " + last_name return full_name.title() active = True while active: print("请告诉我你的名字:") f_name = input("First name:") # 输入的First anme 赋值给f_name l_name = input("Last name:") # 输入的Last name 赋值给l_name name = your_name(f_name, l_name) # 调用定义的函数 print("你好, " + name + "!") a = input("是否继续,输入quit可退出:") if a == 'quit': active = False
请告诉我你的名字: First name:hu Last name:zhuzhu 你好, Hu Zhuzhu! 是否继续,输入quit可退出:hu 请告诉我你的名字: First name:hu Last name:zhuzhu 你好, Hu Zhuzhu! 是否继续,输入quit可退出:quit
函数作为返回值
例1: 实现一个可变参数的求和。
通常情况下,求和的函数是这样定义的:
def calc_sum(*args): ax = 0 for n in args: ax = ax + n return ax
但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?
可以不返回求和的结果,而是返回求和的函数:
def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum
当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:
>>> f = lazy_sum(1, 3, 5, 7, 9) >>> f <function lazy_sum.<locals>.sum at 0x101c6ed90>
调用函数f时,才真正计算求和的结果:
>>> f() 25
10.6 导入模块,函数的几种方法
首先,将函数存储在模块中
- 1、使用函数可以将代码块与主程序分离
- 2、通过将函数存储在独立的文件中,可隐藏程序代码的细节,将重点放在程序的高层逻辑上。
1. import 模块名:导入整个模块
1.先创建模块,模块是扩展名为 .py的文件
pizza.py
def make_pizza(size, *toppings): """概述要制作的披萨""" print("\nMaking a " + str(size) + "-inch pizza with the following toppings:") for topping in toppings: print("- " + topping)
2.调用
import pizza pizza.make_pizza(16, 'pepperoni') pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
3.输出
Making a 16-inch pizza with the following toppings: - pepperoni Making a 12-inch pizza with the following toppings: - mushrooms - green peppers - extra cheese
2. from 模块 import 函数:导入模块中特定的函数
正常调用模块使用函数
module_name.function_name()
你还可以导入模块中的特定函数
from module_name import function_name
通过用逗号分隔函数名,可根据需要从模块中导入任意数量的函数
form module_name import function_0, function_1, function_2
对于前面的making_pizza.py示例,如果只想要导入要使用的函数,代码将类似于下面这样:
from pizza import make_pizza make_pizza(16, 'pepperoni') make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
3. 用as给函数指定别名
格式:form 模块 import 函数名 as 别名
如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名
from pizza import make_pizza as mp mp(16, 'pepperoni') mp(12, 'mushrooms', 'green peppers', 'extra cheese')
4. 用as给模块指定别名
格式:import 模块 as 模块别名
import pizza as p p.make_pizza(16, 'pepperoni') p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
5. (*)导入模块中所有函数
使用星号(*) 导入模块中所有函数
from pizza import * make_pizza(16, 'pepperoni') make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
import语句中的星号让python将模块pizza中的每个函数都复制到这个程序文件中
10.7 导入包
包是一个分层次的目录结构,它将一组功能相近的模块组织在一下
- 作用:
1、代码规范
2、避免模块名称冲突
包和目录的区别:
- 1、包含__init __.py文件的目录称为包
- 2、目录里通常不包含__init __.py文件
创建包:
1、创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字
2、在文件夹中创建一个__init__.py的模块文件,内容可以为空
导入包模块
import 包名.模块名
起别名:
import 包名 as 别名
from 包名 import 模块名 from 包名.模块名 import 函数名/变量名
例
>>> import sys # 这里直接导入包 >>> sys.path.append('C:\\Users\\zdb\\Desktop') >>> import M1.Temperature # 导入包里面的模块 >>> M1.Temperature.c2f(32) # 使用包.模块.函数 89.6
10.8 if __name __ == ‘__main __’
以主程序形式运行
def c2f(cel): fah = cel * 1.8 +32 return fah def f2c(fah): cel = (fah - 32)/1.8 return cel def test(): #多了这个 print('测试:0摄氏度 = %.2f华氏度' % c2f(0)) print('测试:0华氏度 = %.2f摄氏度' % f2c(0)) if __name__ == '__main__': #多了这个 test()
第十一章 类class
类命名首字母大写
11.1 类对象、类属性、实例方法
1. 类对象class
面向对象最重要的概念就是类(Class)和实例(Instance)
类是属性和方法的封装
2. 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享
# 类名有一个或多个单词组成,单词首字母大写,其余小写 class Student(): # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性
3. 实例方法
# 类名有一个或多个单词组成,单词首字母大写,其余小写 class Student(): # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性 # 初试化方法 def __init__(self, name, age): # self称为实例属性,这里进行了一个赋值操作,将局部变量name的值赋值给实例属性 self.name = name self.age = age # 实例方法 def eat(self): # 类里面的函数称为方法, print('学生正在吃饭...')
11.2 静态方法:@staticmethod
静态方法:使用 @staticmethod 修饰的方法,使用类名直接访问的方法
# 类名有一个或多个单词组成,单词首字母大写,其余小写 class Student(): # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性 # 初试化方法 def __init__(self, name, age): # self称为实例属性,这里进行了一个赋值操作,将局部变量name的值赋值给实例属性 self.name = name self.age = age # 实例方法 def eat(self): # 类里面的函数称为方法, print('学生正在吃饭...') # 静态方法 @staticmethod def method(): # 这里不能写self print('我使用了statticmethod进行修饰,所以我是静态方法')
11.3 类方法:@classmethod
类方法:使用 @classmethod 修饰的方法。使用类名直接访问的方法
# 类名有一个或多个单词组成,单词首字母大写,其余小写 class Student: # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性 # 初试化方法 def __init__(self, name, age): # self称为实例属性,这里进行了一个赋值操作,将局部变量name的值赋值给实例属性 self.name = name self.age = age # 实例方法 def eat(self): # 类里面的函数称为方法, print('学生正在吃饭...') # 静态方法 @staticmethod def method(): # 这里不能写self print('我使用了statticmethod进行修饰,所以我是静态方法') # 类方法 @classmethod def cm(cls): # 这里传入cls print('我是类方法,因为我使用了classmethod进行修饰')
11.4 类的实例化 (实例对象)
根据类来创建对象被称为实例化
语法:实例名 = 类名()
stu = Student()
有了实例,就可以调用类中的内容。
这里接着最上面的代码继续
# 创建Student类的对象 stu1 = Student('张三', 20) stu1.eat() # 对象名.方法名() print(stu1.name) print(stu1.age) print('-----------------') # 类名.方法名(对象) Student.eat(stu1) # 这个也可以
学生正在吃饭... 张三 20 ----------------- 学生正在吃饭...
完整代码如下:
# 类名有一个或多个单词组成,单词首字母大写,其余小写 class Student(): # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性 # 初试化方法 def __init__(self, name, age): # self称为实例属性,这里进行了一个赋值操作,将局部变量name的值赋值给实例属性 self.name = name self.age = age # 实例方法 def eat(self): # 类里面的函数称为方法, print('学生正在吃饭...') # 静态方法 @staticmethod def method(): # 这里不能写self print('我使用了statticmethod进行修饰,所以我是静态方法') # 类方法 @classmethod def cm(cls): # 这里传入cls print('我是类方法,因为我使用了classmethod进行修饰') # 类属性,类方法,静态方法 # 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享 # 类方法:使用@classmethod修饰的方法。使用类名直接访问的方法 # 静态方法:使用@staticmethod修饰的主法,使用类名直接访问的方法 print(Student.native_pace) # 访问类属性 # Student.cm() # 调用类方法 # Student.sm() # 调用静态方法 # 创建Student类的对象 stu1 = Student('张三', 20) stu2 = Student('李四', 30) print(stu1.native_pace) print(stu2.native_pace) Student.native_pace = '天津' print(stu1.native_pace) print(stu2.native_pace) print('---------------类方法的使用方式--------------') Student.cm() # cls不需要传入 print('---------------静态方法的使用方式--------------') Student.method()
动态绑定属性
class Student(): # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性 # 初试化方法 def __init__(self, name, age): # self称为实例属性,这里进行了一个赋值操作,将局部变量name的值赋值给实例属性 self.name = name self.age = age # 创建Student类的对象 stu1 = Student('张三', 20) stu2 = Student('李四', 30) stu2.gender = '女' # stu2多了一个属性,而stu1没有 print(stu1.name, stu1.age) print(stu2.name, stu2.age, stu2.gender)
张三 20 李四 30 女
动态绑定方法
class Student(): # Student为类的名称, native_pace = '吉林' # 直接写在类里面的变量, 称为类属性 # 初试化方法 def __init__(self, name, age): # self称为实例属性,这里进行了一个赋值操作,将局部变量name的值赋值给实例属性 self.name = name self.age = age # 实例方法 def eat(self): # 类里面的函数称为方法, print('学生正在吃饭...') def show(): print('定义在类之外的,称函数') # 创建Student类的对象 stu1 = Student('张三', 20) stu2 = Student('李四', 30) stu1.show = show stu1.show()
定义在类之外的,称函数
11.5 面向对象的三大特征:封装,继承,多态
1.封装:提高程序的安全性
- 1、将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度
- 2、在python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个“_”
将一类事物的属性和行为抽象成一个类,使其属性私有化,行为公开化, 提高了数据的隐秘性的同时,使代码模块化。这样做使得代码的复用性更高。 意义: 1. 将属性和方法放到一起做为一个整体,然后通过实例化对象来处理; 2. 隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了; 3. 对类的属性和方法增加 访问权限控制。
2.继承:提高代码的复用性
语法:
class 子类类名(父类1,父类2...): pass
- 1、如果一个类没有继承任何类,则默认继承object
- 2、python支持多继承
- 3、在定义子类时,必须在其构造函数中调用父类的构造函数
- 让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
创建子类的实例时,python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法 __ init__() 需要父类施以援手。
super()是一个特殊函数,帮助python将父类和子类关联起来。 这行代码让python调用ElectricCar的父类的方法__init__(),让ElectricCar实例包含父类的所有属性。
class Person(object): # 也可以不写object def __init__(self, name, age): self.name = name self.age = age def info(self): print('姓名:{0},年龄:{1}'.format(self.name, self.age)) # 定义子类 class Student(Person): def __init__(self, name, age, score): super().__init__(name, age) # 调用父类的init方法,继承 self.score = score # 子类自己的属性 class Teacher(Person): def __init__(self, name, age, teacher_of_year): super().__init__(name, age) self.teacher_of_year = teacher_of_year # 测试 stu = Student('Jack', 20, '1001') stu.info() teacher = Teacher('李四', 34, 20) teacher.info()
姓名:Jack,年龄:20 姓名:李四,年龄:34
多继承
class A(object): pass class B(object): pass class C(A, B): # 继承A和B pass
把类A的实例用作类B的属性
当添加类的细节越来越多时,可将类的一部分作为一个独立的类提取出来,将一个大类拆分成若干个小类。
例1
"""组合 """ class Turtle: # 乌龟类 def __init__(self, x): self.num = x class Fish: # 鱼类 def __init__(self, y): self.num = y class Pool: # 水池类 def __init__(self, x, y): # x只乌龟,y个鱼 self.turtle = Turtle(x) # 乌龟 self.fish = Fish(y) # 鱼 def print_num(self): print('水池里总共有乌龟 %d 只,小鱼 %d 条!' % (self.turtle.num, self.fish.num)) pool = Pool(1, 10) # 乌龟1个,鱼10个 pool.print_num() # 输出
水池里总共有乌龟 1 只,小鱼 10 条!
重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
例1
class Animal(object): def run(self): print('Animal is running...') class Dog(Animal): def run(self): print('Dog is running...') def eat(self): print('Eating meat...') animal = Animal() animal.run() dog = Dog() dog.run()
Animal is running... Dog is running...
例
class Person(object): def __init__(self, name, age): self.name = name self.age = age def info(self): print('姓名:{0},年龄{1}'.format(self.name, self.age)) # 定义子类 class Student(Person): def __init__(self, name, age, score): super().__init__(name, age) self.score = score def info(self): super().info() print('学号:{0}'.format(self.score)) class Teacher(Person): def __init__(self, name, age, teacher_of_year): super().__init__(name, age) self.teacher_of_year = teacher_of_year def info(self): super().info() print('教龄', self.teacher_of_year) # 测试 stu = Student('张三', 20, '1001') stu.info() # 继承父类输出的姓名和年龄,子类自己多了学号 print('-------') teacher = Teacher('李四', 34, 10) teacher.info()
姓名:张三,年龄20 学号:1001 ------- 姓名:李四,年龄34 教龄 10
# object类 # object类是所有类的父类,因此所有类都有object类的属性和方法 # 内置函数dir()可以查看指定对象所有属性 # object有一个__str__()方法,用于返回一个对于“对象的描述”, # 对应于内置函数str()经常用于print()方法,帮我们查看对象的信息, # 所以我们经常会对__str__()进行重写 class Person(object): def __init__(self, name, age): self.name = name self.age = age def info(self): print('姓名:{0},年龄:{1}'.format(self.name, self.age)) def __str__(self): return '姓名:{0},年龄:{1}'.format(self.name, self.age) o = object() p = Person('Jack', 20) print(dir(o)) print(dir(p)) print(p)
例
class Student: pass stu = Student() print(dir(stu)) print(stu)
这里print(str)输出的是内存地址
['__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__'] <__main__.Student object at 0x00000246F49EAEC8>
def __str __(self)
class Student: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return '我的名字是{0},今年{1}岁了'.format(self.name, self.age) stu = Student('张三', 20) print(dir(stu)) print(stu) # 默认调用__str__()这样的方法 print(type(stu))
['__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__', 'age', 'name'] 我的名字是张三,今年20岁了 <class '__main__.Student'>
修改类的方法
class C: def x(self): print('X.man!') c = C() c.x() c.x = 1 # 修改方法 print(c.x)
X.man! 1
修改属性的值
1、直接修改属性的值
class Car(): --snip-- #与上面相同 my_new_car = Car('audi', 'a4', 2016) #创建实例 print(my_new_car.get_descriptive_name()) #调用属性 my_new_car.odometer_reading = 23 my_new_car.read_odometer()
2016 Audi A4 This car has 23 miles on it.
2、通过方法修改属性的值
如果有替你更新属性的方法,将大有裨益。这样,你就无需直接访问属性,而可将值传递给一个方法,由它在内部进行更新。
class Car(): """一次模拟汽车的简单尝试""" def __init__(self, make, model, year): """初始化描述汽车的属性""" self.make = make self.model = model self.year = year self.odometer_reading = 0 #初始化 def get_descriptive_name(self): """返回整洁的描述性信息""" long_name = str(self.year) + ' ' + self.make + ' ' + self.model return long_name.title() def read_odometer(self): """打印一条指出汽车里程的消息""" print("This car has " + str(self.odometer_reading) + " miles on it.") def update_odometer(self, mileage): #定义这个函数,用这个更新read_odometer函数 """将里程表读数设置为指定的值""" self.odometer_reading = mileage my_new_car = Car('audi', 'a4', 2016) #创建实例 print(my_new_car.get_descriptive_name()) #调用属性 my_new_car.update_odometer(23) #这里改了 my_new_car.read_odometer()
3、通过方法对属性的值进行递增
class Car(): """一次模拟汽车的简单尝试""" def __init__(self, make, model, year): """初始化描述汽车的属性""" self.make = make self.model = model self.year = year self.odometer_reading = 0 #初始化 def get_descriptive_name(self): """返回整洁的描述性信息""" long_name = str(self.year) + ' ' + self.make + ' ' + self.model return long_name.title() def read_odometer(self): """打印一条指出汽车里程的消息""" print("This car has " + str(self.odometer_reading) + " miles on it.") def update_odometer(self, mileage): #定义这个函数,用这个更新read_odometer函数 """ 将里程表读数设置为指定的值 禁止这里程表读数往回调 """ if mileage >= self.odometer_reading: #禁止调的比原来小 self.odometer_reading = mileage else: print("You can't roll back an odometer!") def increment_odometer(self, miles): """将里程表读数增加指定的量""" self.odometer_reading += miles my_new_car = Car('audi', 'a4', 2016) #创建实例 print(my_new_car.get_descriptive_name()) #调用属性 #2016 Audi A4 my_new_car.update_odometer(235000) my_new_car.read_odometer() my_new_car.increment_odometer(100) my_new_car.read_odometer()
2016 Audi A4 This car has 235000 miles on it. This car has 235100 miles on it.
多态:提高程序的可扩展性和可维护性
- 简单地说,多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法
class Animal(object): def eat(self): print('动物要吃东西') class Dog(Animal): def eat(self): print('狗吃肉') class Cat(Animal): def eat(self): print("猫吃鱼") class Person(object): def eat(self): print('人吃五谷杂粮') def fun(animal): animal.eat() fun(Dog()) fun(Cat()) fun(Animal()) print('--------------') fun(Person())
狗吃肉 猫吃鱼 动物要吃东西 -------------- 人吃五谷杂粮
- 问: self是什么?
面向对象编程
python中的self相当于C++里面的this指针
- 问:什么是绑定?
python严格要求方法需要有实例才能被调用,这种限制其实就是python所谓的绑定概念
11.6 私有变量(private)限制访问
外部访问属性、修改属性
class Student(object): def __init__(self, name, score): self.name = name self.score = score bart = Student('Bart Simpson', 59) print(bart.score) bart.score = 99 print(bart.score)
59 99
private:私有变量
- 如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:
class Student(object): def __init__(self, name, score): self.__name = name self.__score = score def print_score(self): print('%s: %s' % (self.__name, self.__score))
错误实例:
class Person: __name = 'zdb' # 私有变量 p = Person() print(p.__name)
AttributeError: 'Person' object has no attribute '__name'
访问私有变量方法
- 但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法:
- 如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:
你也许会问,原先那种直接通过bart.score = 99也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数:
class Student: def __init__(self, name, age): self.name = name self.__age = age # 不希望在类的外部被使用,不是不能,是不希望 def show(self): print(self.name, self.__age) stu = Student('张三', 20) print(stu.name) # print(stu.__name) ## 这个不能 # print(dir(stu)) # 完全靠自觉性不访问 print(stu._Student__age) # 在类的外部可以通过_Student__age进行访问
例:
class Student(object): def __init__(self, name, score): self.__name = name self.__score = score def print_score(self): print('%s: %s' % (self.__name, self.__score)) def get_name(self): return self.__name def get_score(self): return self.__score def set_score(self, score): if 0 <= score <= 100: self.__score = score else: raise ValueError('bad score') def set_score(self, score): self.__score = score bart = Student('Bart Simpson', 59) print(bart._Student__name) print(bart.get_name()) bart.print_score() print(bart.get_score())
Bart Simpson Bart Simpson Bart Simpson: 59 59
例2
class Person: __name = 'zdb' def getName(self): # 设置方法 return self.__name # 返回私有变量 p = Person() print(p.getName())
zdb
11.7 特殊的属性和方法
特殊属性
名称 | 描述 |
__dict __ | 获得类对象或实例对象所绑定的所有属性和方法的字典 |
class A: pass class B: pass class C(A, B): def __init__(self, name, age): self.name = name self.age = age # 创建C类的对象 x = C('Jack', 20) # x是C类型的一个实例对象 print(x.__dict__) print(C.__dict__) # 能看到属性和方法的字典 print('-------------------') print(x.__class__) # 输出对象所属于的类 print(C.__bases__) # 输出C类的父类类型的元组 print(C.__base__) # 谁写在继承括号的最前面就输出谁,类的基类 print(C.__mro__) # 类的层次结构 print(A.__subclasses__()) # A的子类的列表
{'name': 'Jack', 'age': 20} {'__module__': '__main__', '__init__': <function C.__init__ at 0x000001DEB40B7678>, '__doc__': None} ------------------- <class '__main__.C'> (<class '__main__.A'>, <class '__main__.B'>) <class '__main__.A'> (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) [<class '__main__.C'>]
特殊方法
名称 | 描述 |
__len __() | 通过重写__len __()方法,让内置函数len()的参数可以是自定义类型 |
__add __() | 通过重写__add __()方法,可使用自定义对象具有“+”功能 |
__new __() | 用于创建对象 |
__init __() | 对创建的对象进行初始化 |
a = 20 b = 100 c = a + b print(c) d = a.__add__(b) # 实现一样的加法功能 print(d) class Student: def __init__(self, name): self.name = name def __add__(self, other): return self.name + other.name def __len__(self): return len(self.name) stu1 = Student('Jack') stu2 = Student('李四') s = stu1 + stu2 # 有__add__方法后才能相加,没有会报错 print(s) s = stu1.__add__(stu2) # 这种方法也可以实现相加 print(s) print('-----------------------') lst = [11, 22, 33, 44] print(len(lst)) print(lst.__len__()) # 这样也可以 print(len(stu1))
120 120 Jack李四 Jack李四 ----------------------- 4 4 4
例:这个一点都看不懂
class Person(object): def __new__(cls, *args, **kwargs): print("__new__被调用执行了,cls的ID值为{0}".format(id(cls))) obj = super().__new__(cls) print('创建的对象的ID为:{0}'.format(id(obj))) return obj def __init__(self, name, age): print('__init__被调用了,self的ID值为{0}'.format(id(self))) self.name = name self.age = age print('object这个类对象的ID为:{0}'.format(id(object))) print('Person这个类对象的ID为{0}'.format(id(Person))) # 创建Person类的实例对象 p1 = Person('张三', 20) print('p1这个Person类的实例对象的ID:{0}'.format(id(p1)))
object这个类对象的ID为:140711006337840 Person这个类对象的ID为2219114295720 __new__被调用执行了,cls的ID值为2219114295720 创建的对象的ID为:2219148478536 __init__被调用了,self的ID值为2219148478536 p1这个Person类的实例对象的ID:2219148478536