太原网站公司哪家好,黄梅那里有做网站的,网站推广服务合同模板,优质做网站哪家正规3.5 Python类和对象 目录 1. 面向对象的基本概念
2. 类和对象的关系
3. 类的声明
4. 对象的创建和使用
5. 类对象属性
6. 类对象方法
7. 面向对象的三个基本特征
8. 综合案例#xff1a;汉诺塔图形化移动 1.1 面向对象的基本概念
1.1.1 对象#xff08;object#x… 3.5 Python类和对象 目录
1. 面向对象的基本概念
2. 类和对象的关系
3. 类的声明
4. 对象的创建和使用
5. 类对象属性
6. 类对象方法
7. 面向对象的三个基本特征
8. 综合案例汉诺塔图形化移动 1.1 面向对象的基本概念
1.1.1 对象object概念引入
在现实生活中随处可见的事物就是对象对象是事物存在的实体。
小狗就是真实世界的一个对象应该如何描述这个对象呢可以从以下两个方面来讨论
1静态特征比如四条腿、一条尾巴、两只耳朵、黑色…
2动态特征比如它跑得很快、喜欢睡懒觉、吃东西时会流口水、见认识的人会摇尾巴见了陌生人会“汪汪”大叫…
从静态特征和动态特征两方面就可以简单地将小狗这个对象来描述清楚。如果把人作为一个对象你会从哪些方面来描述呢
长相高矮胖瘦、爱好运动、书法
1.1.2 对象的定义
对象object从概念层面讲就是某种事物的抽象。抽象原则包括两个方面数据抽象定义对象的属性过程抽象定义对象的操作。
面向对象的程序设计强调把数据属性和操作服务结合为一个不可分的系统单位即对象对象的外部只需要知道它做什么而不需要知道它如何做。
从规格层面讲对象是一系列可以被其他对象使用的公共接口对象交互。从语言实现层面来看对象封装了数据和代码数据和程序。
Python中的对象也是如此对象的静态特征称为“属性”对象的动态特征称为方法。
概括起来讲对象 属性 方法
特性的描述称为属性在代码层面来看其实就是变量。
方法实际就是函数通过调用这些函数来完成操作。
1.1.3 面向对象编程
面向过程procedure-oriented通过把解决问题的步骤写出来让程序一步一步去执行直到解决问题是一种以事件为中心的编程。
面向对象Object-Oriented一种以事物为中心的编程思想。
面向对象编程是较“高层”的编程架构。
1.2 类和对象的关系
类是抽象的、宏观的是一种描述。而对象是具体的、个性的。
类是数据结构类定义数据类型的数据属性和行为方法。
对象是类的具体实体也可称为类的实例Instance。
类与对象的关系类似于车型设计和具体车辆之间的关系。车型设计类描述了该车型所应该具备的属性和性能但车型设计并不是具体的车不能发动和驾驶。具体的一辆车车类的实例具备该车型设计所描述的属性和功能可以发动和驾驶。
1.3 类的声明
类的声明定义Python中使用class关键字来定义类其中属性也称成员变量方法也称成员函数。格式如下
class 类名类体属性、方法类名为有效的标识符命名规则一般为多个单词组成的名称每个单词除第一个字母大写外其余的字母均小写Python中的类名约定以大写字母开头类体由缩进的语句块构成。
定义在类体内的元素都是类的成员。类的主要成员包括两种类型即描述状态的数据成员属性和描述操作的函数成员方法。
# Dog类声明示例
class Dog:leg4; tail1; ear2 ; weight5 #属性def run(self): #方法1print(小狗正在飞快地跑) def sleep(self): #方法2print(小狗正在睡觉)def eat(self): #方法3print(食物真好吃)dDog()
print(d.leg)
d.run()
d.sleep()
d.eat()输出结果
4
小狗正在飞快地跑
小狗正在睡觉
食物真好吃1.4 对象的创建和使用
类是抽象的要使用类定义的功能就必须实例化类即创建类的对象。创建对象后可以使用“. ”运算符来调用其成员。实例出来的对象具有与类相同的属性和方法。 注意创建类的对象、创建类的实例、实例化类等说法是等价的都说明以类为模板生成了一个新的对象。
对象的创建格式anObject 类名(参数列表)
对象的调用格式anObject.对象函数 或 anObject.对象属性
# 类对象的创建和调用示例
mydogDog() #创建名为mydog的对象
w1mydog.weight #访问mydog对象中weight属性
print(我的小狗重:{}kg.format(w1)) #输出我的小狗重:5kg
mydog.run() #输出我正在飞快地跑
mydog.sleep() #输出我正在睡觉输出结果
我的小狗重:5kg
小狗正在飞快地跑
小狗正在睡觉1.5 类对象属性
类的数据成员是在类中定义的成员变量用来存储描述类的特征的值称为属性。属性可以被该类中定义的方法访问也可以通过类或类的实例进行访问。在函数体或代码块中定义的局部变量则只能在其定义的范围内进行访问。
属性实际上是在类中的变量。Python变量不需要声明可直接使用。建议在类定义开始位置初始化类属性或者在构造函数__init__中初始化对象属性。
1.5.1 对象属性
在类中定义的属性最好是通用的属性。
前面的Dog类中定义的weight5其实是个不很恰当的示范它应该定义在对象的方法中在__init__ 方法中定义才为恰当。
通过self.变量名定义的属性称为对象属性实例属性也称为对象变量。类的每个实例都包含该类的对象变量单独副本对象变量属于特定的实例。
对象变量在类的内部通过self访问在外部通过对象实例访问。
注Python中的self等价于C中的this指针和Java、C#中的this关键字。
1.5.2 类属性
Python允许声明属于类本身的变量即类属性也称为类变量、静态属性。类属性属于整个类不是特定实例的一部分而是所有实例共享一个副本。
类属性一般在类体中通过如下形式初始化
类变量名 初始值然后在其类定义的方法中或外部代码中通过类名访问
类名.类变量名 值 #写入
类名.类变量名 #读取# 类属性示例c16_01_Person.py
class Person:count 0def __init__(self, name, age):self.name nameself.age agePerson.count 1def __del__(self):Person.count - 1def say_hi(self):print(您好我叫{}.format(self.name))def getcount():print(计数{}.format(Person.count))
print(现有人数{}.format(Person.count))
p31 Person(张三, 25)
p31.say_hi()
Person.getcount()
p32 Person(李四, 28)
p32.say_hi()
Person.getcount()
del p31
Person.getcount()
del p32
Person.getcount()现有人数0
您好我叫张三
计数1
您好我叫李四
计数2
计数1
计数01.5.3 对象属性和类属性的区别
类属性通过“类名.属性名”的方式访问对象属性通过“对象名.属性名”的方式访问。如果类属性通过“对象名.属性名”来访问则转化为该对象实例的对象属性。
# 类属性和对象属性示例
class A:nameaaaa A()
b A()A.name AAA
print(a.name , b.name) #输出(AAA, AAA)b.name BBB
print(a.name) #输出AAA
print(b.name) #输出BBB
print(id(a.name),id(b.name))
print(id(A.name))输出结果
AAA AAA
AAA
BBB
1484146593648 1484146337456
14841465936481.5.4 私有属性和公有属性
Python类的成员没有访问控制限制这与其他面向对象的语言不同。
公有属性前面类中定义的属性都是公有属性可以通过“对象名.成员”的方式来进行访问。
私有属性Python定义私有类型的方式很简单约定两个下划线“__”开头、但是不以两个下划线结束的属性是私有的Private其他即为公有的Public。不能直接访问私有属性但可以在类方法中访问。
# 类属性和对象属性示例
class Dog:name旺财__age1dog Dog()
dog.name #输出 旺财
# dog.__age #输出 AttributeError: Dog object has no attribute __age如何访问私有属性
类的外部不能直接访问私有属性但我们可以利用类内部的方法通过“self.私有成员名”的方式进行访问。
私有属性是为数据的封装和保密设计的一般只能在类的内部访问。
# 类属性和对象属性示例
class Dog:__name旺财 #私有属性def getName(self): #在方法中获取私有属性值return self.__namemydogDog()
# print(mydog.__name)
print(mydog.getName()) #输出旺财1.6 类对象方法
1.6.1 方法的声明和调用
方法是与类相关的函数它的定义与普通的函数一致区分只在于类的方法定义在类体中且其第一个形式参数必须为对象本身通常为self。
方法的声明格式
def 方法名(self,[形参列表]):函数体 方法的调用格式
对象.方法名([实参列表])注意虽然类方法的第一个参数为self但调用时用户不需要也不能给该参数传值Python会自动把对象实例传递给该参数。
1.6.2 self变量
类方法中都至少有一个名为self的参数并且是第一个参数用于表示对象本身在调用方法时不需要为这个参数赋值。由同一个类可以生成无数个对象当一个对象的方法被调用的时候对象会将自身作为一个参数传给该方法Python知道需要操作哪个对象和方法。
例如假设已声明一个类MyClass其中包括类方法my_func(self,p1,p2)。
在以下代码中
obj1 MyClass() #创建MyClass实例obj1
obj1.my_func(p1,p2) #调用对象obj1的方法调用对象obj1的方法obj1.my_func(p1,p2)Python自动转化为obj1.my_func(obj1,p1,p2)即自动把对象实例obj1传值给self参数。
备注Python中的self等价于C中的this指针和Java、C#中的this关键字。虽然没有限制第一个参数名必须是self但建议大家遵循惯例这样便于阅读和理解且集成开发环境IDE也会提供相应的支持。
示例定义Dog类中的两个方法setowner()和getowner()分别为设置主人的姓名和获取主人的姓名。
# self作用示例
class Dog:def setowner(self, name): # 方法1设置对象的主人姓名self.owner namedef getowner(self): # 方法2获取对象的主人姓名print(我的主人是{}.format(self.owner))def run(self): # 方法3pass
a Dog() # 创建小狗对象a
a.setowner(张三) # 张三认领小狗a
b Dog() # 创建小狗对象b
b.setowner(李四) # 李四认领小狗b
a.getowner() # 输出我的主人是张三
b.getowner() # 输出我的主人是李四1.6.3 __init__方法构造函数
Python类体中可以定义特殊的方法__init__方法。
__init__是特殊的方法在个方法名称的开头和末尾各有两个下划线每当我们创建对象时都会自动调用。
__init__方法即构造函数构造方法用于执行类实例化的初始化工作。
__init__方法在创建完对象后调用初始化当前对象无返回值。
init单词initialize的简写初始化之意。
# __init__的使用示例
class Dog:leg4; tail1; ear2 def __init__(self,a,b):self.nameaself.ownerbdog1Dog(旺财1号,Adam)
dog2Dog(旺财2号,Grit)print(dog1.owner,的小狗叫,dog1.name) #输出 Adam 的小狗叫 旺财1号
print(dog2.owner,的小狗叫,dog2.name) #输出 Grit 的小狗叫 旺财2号dog1.name 改名1
dog2.owner Lucyprint(dog1.owner,的小狗叫,dog1.name) #输出 Adam 的小狗叫 改名1
print(dog2.owner,的小狗叫,dog2.name) #输出 Lucy 的小狗叫 旺财2号1.6.5 __del__方法析构函数
Python类体中可以定义一个特殊的方法__del__方法。
__del__方法即析构函数析构方法用于实现销毁类的实例所需的操作如释放对象占用的非托管资源如打开的文件网络连接等。
默认情况下当对象不再被使用时__del__方法运行由于Python解释器实现自动垃圾回收即无法保证这个方法究竟在什么时间运行。
通过del语句可以强制销毁一个对象实例从而保证调用对象实例的__del__方法。
1.7 面向对象的三个基本特征
面向对象的程序设计具有三个基本特征封装、继承和多态可以大大增加程序的可靠性、代码的可重用性和程序的可维护性从而提高程序开发效率。
1.7.1 封装
封装Encapsulation是面向对象的主要特征。所谓封装也就是把客观事物抽象并封装成对象即将数据成员、属性、方法和事件等集合在一个整体内。通过访问控制还可以隐藏内部成员只允许可信的对象访问或操作自己的部分数据或方法。
封装保证了对象的独立性可以防止外部程序破坏对象的内容数据同时便于程序的维护和修改。
生活中处处都是封装的概念比如家里的电视机从开机浏览节目换台到关机我们不需要知道电视机里面的具体细节只需要在用的时候按下遥控器就可以完成操作又比如在使用移动支付的时候只需要把付款二维码提供给收款方扫一下就可以完成支付不需要知道后台是怎样处理数据的这都体现了一种封装的概念。
把各类数据放进列表是一种封装是数据层面的封装把常用的代码打包为一个函数也是一种封装是语句层面的封装面向对象的封装更先进一步即有数据又有函数。
在面向对象的编程语言中“封装”就是将抽象得到的属性和行为相结合形成一个有机的整体即类。 一个房间有名称name、房间主人的名字owner、房间长length、宽width、高height等属性我们构建了 Room类并实例化了一个对象现在若需要计算房间面积可定义函数 area()。
# 封装示例——Room类class Room: # 定义一个房间的类def __init__(self, n, o, l, w, h):self.name nself.owner oself.length l # 房间的长self.width w # 房间的宽self.height h # 房间的高r1 Room(客厅, Adam, 20, 30, 9) # 类的实例化def area(room):print({0}的{1}面积是{2}.format(room.owner, room.name, room.length * room.width))area(r1) # 输出Adam的客厅面积是600封装可以简化编程使用者不必了解具体的实现细节。可以直接在Room类的内部定义访问数据的函数area ()。
# 封装示例——Room类
class Room: # 定义一个房间的类def __init__(self, n, o, l, w, h):self.name nself.owner oself.length l # 房间的长self.width w # 房间的宽self.height h # 房间的高def area(self): # 计算房间面积print({0}的{1}面积{2}.format(self.owner, self.name, self.length * self.width))r1 Room(客厅, Adam, 20, 30, 9) # 实例化一个房间
r1.area() # 输出Adam的客厅面积是600
封装带来的好处是增强安全性。
封装也提供了良好的可扩展性。
思考如果在上述例子中增加求体积的功能仍然在area方法中实现使功能增加该如何改动代码
# 封装示例——Room类
class Room: # 定义一个房间的类def __init__(self, n, o, l, w, h):self.name n;self.owner oself.length l # 房间的长self.width w # 房间的宽self.height h # 房间的高def area(self): # 计算房间面积print({0}的{1}面积为{2}.format(self.owner, self.name, self.length * self.width), end)print(体积是{0}。.format(self.length * self.width * self.height))r1 Room(客厅, Adam, 20, 30, 9) # 实例化一个房间
r1.area() # 输出Adam的客厅面积600体积是54001.7.2 继承
1继承的概念
继承Inheritance是面向对象的程序设计中代码重用的主要方法。继承允许使用现有类的功能并在无需重新改写原来的类的情况下对这个功能进行扩展。继承可以避免代码复制和相关代码维护等问题。
继承的过程就是从一般到特殊的过程。被继承的类称为“基类Base Class”、“父类”或“超类Super Class”通过继承创建的新类称为“子类Subclass”或“派生类Derived Class”。
知识要点 被继承的类称为父类继承者称为子类。 子类是父类的特殊化子类继承了父类的特性同时可以对继承到的特性进行更改也可以拥有父类没有的特性。
2继承的方法
Python支持多重继承一个子类可以继承于多个父类。子类的声明格式如下
class 子类名(父类1[父类2…]):类体子类名后为所有父类的名称元组。
如果在类定义中没有指定父类则默认其父类为object。object是所有对象的根父类定义了公用方法的默认实现如__new__()。
例如
class Foo: pass等同于
class Foo(object):pass声明子类时必须在其构造函数中调用父类的构造函数。
调用格式如下
父类名.__init__(self,参数列表)#父类和子类示例class Person:def __init__(self,name,age):self.name nameself.age agedef say_hi(self):print(您好我是{0}今年{1}岁。.format(self.name,self.age))class Student(Person):def __init__(self,name,age,stu_id):Person.__init__(self,name,age)self.stu_id stu_iddef say_hi(self):Person.say_hi(self)print(我是学生我的学号是{}。.format(self.stu_id))#父类和子类示例续
p1 Person(张三,33)
p1.say_hi()
s1 Student(李四,20,P171823001)
s1.say_hi()输出结果
您好我是张三今年33岁。
您好我是李四今年20岁。
我是学生我的学号是P171823001。3类成员的继承和重写
通过继承子类继承父类中除构造方法之外的所有成员。如果在子类中重新定义从父类继承的方法则子类中定义的方法覆盖从父类中继承的方法。即若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表则新方法将覆盖原有的方法这称之为方法重写。
程序案例定义父类Dimension包含2个数据成员x和y定义继承于Dimension的两个子类Circle和RectangleCircle只有一个数据成员r重写area方法输出信息。定义两个实例输出相关信息。
# 类成员的继承和重写示例
import math
class Dimension:def __init__(self, x, y):self.x xself.y ydef area(self):passdef show_info(self):print(Dimension类的show_info方法。)class Circle(Dimension):def __init__(self, r):Dimension.__init__(self, r, 0)def area(self):return round(math.pi*self.x**2,2)class Rectangle(Dimension):def __init__(self, w, h):Dimension.__init__(self, w, h)def area(self):return self.x * self.yd1 Circle(2.0)
d2 Rectangle(2.0, 4.0)
print(d1.area(), \n, d2.area(),sep)
d1.show_info()
d2.show_info()输出结果
12.57
8.0
Dimension类的show_info方法。
Dimension类的show_info方法。4输出继承关系
多个类的继承可以形成层次关系通过类的方法mro()或类的属性__mro__可以输出其继承的关系。例如
# 输出继承关系示例class A: pass
class B: pass
class C(A) : pass
class D(B) : pass
class E(A,B): pass
print(C.mro())
print(E.mro())输出结果
[class __main__.C, class __main__.A, class object]
[class __main__.E, class __main__.A, class __main__.B, class object]5super()函数
super函数能够帮助我们自动找到父类的方法而且还不用传入self参数可以省事一些。
super函数的“超级”之处在于不需要明确给出任何父类的名字它会自动帮我们找出所有父类以及对应的方法。由于不用给出父类名称这意味着如果需要改变类的继承关系只要改变class语句里的父类即可而不必在大量代码中去修改所有被继承的方法。
# 类成员的继承和重写示例
import math
class Dimension:def __init__(self, x, y):self.x xself.y ydef area(self):passdef show_info(self):print(Dimension类的show_info方法。)class Circle(Dimension):def __init__(self, r):super().__init__(r, 0) #此处有改变def area(self):return round(math.pi*self.x**2,2)class Rectangle(Dimension):def __init__(self, w, h):super().__init__(w, h) #此处有改变def area(self):return self.x * self.yd1 Circle(2.0)
d2 Rectangle(2.0, 4.0)
print(d1.area(), \n, d2.area(),sep)
d1.show_info()
d2.show_info()输出结果
12.57
8.0
Dimension类的show_info方法。
Dimension类的show_info方法。1.7.3 多态
多态是多种表现形态的意思它是一种机制、一种能力而非某个关键字。在面向对象的编程中多态在类的继承和类的方法调用中得以体现。多态在不清楚对象的具体类型时根据引用对象的不同而表现出不同的行为方式。当不知道对象到底是什么类型但又要让对象“做点儿什么”的时候都会用到多态。
对象可以表示多个类型的能力称为多态Polymorphism。多态性允许每个对象以自己的方式去响应共同的消息从而允许用户以更明确的方式建立通用软件提高软件开发的可维护性。
Python是一种动态语言变量或参数无法也无需确定其类型。程序运行过程中根据实际的对象类型确定变量的类型。
严格意义上讲Python不支持多态性即动态确定变量指向的对象类型。
1对象的多态表现
声明Dog类和Cat类同时包括方法move分别创建dog对象和cat对象调用move方法然后根据其类型的不同它会表现出不同的行为。
# 对象的多态表现示例
from random import choice
class Dog:def move(self):print(飞快地跑)
class Cat:def move(self):print(慢悠悠地走。)dog Dog()
cat Cat()obj choice([dog, cat]) # choice函数实现从列表中随机选择一个元素print(type(obj)) # type函数可以查看对象类型
obj.move() # 若obj为Cat输出慢悠悠地走若obj为Dog输出飞快地跑输出结果
class __main__.Dog
飞快地跑(2函数和运算符的多态表现
# 函数和运算符的多态表现示例
def sum(a, b):return a b
a 1
b 2
c 深度
d 学习
print(sum(a, b))
print(sum(c, d))输出结果
3
深度学习3 Python应用多态注意事项
Python和其他静态形态检查类的语言如C等不同在参数传递时不管参数是什么类型都会按照原有的代码顺序执行这就很可能会出现因传递的参数类型错误而导致程序崩溃的现象。
# 示例
def is_odd_number(a):return not a%20a 3
print(is_odd_number(a)) # 输出Trueb 2.1
print(is_odd_number(b)) # 输出True没报错但结果是错的c [3]
# print(is_odd_number(c))
# 输出TypeError: unsupported operand type(s) for %: list and int思考怎样避免这种因传递的参数类型错误而导致程序崩溃的现象
安全起见需要自己编写代码来检验参数类型的正确性。
# 示例
def is_odd_number(a):if isinstance(a,int):return not a%20else:return -1 #类型不合法时返回-1a 2
print(is_odd_number(a)) # 输出False
b 2.1
print(is_odd_number(b)) # 输出-1
c [3]
print(is_odd_number(c)) # 输出-1 1.8 综合案例汉诺塔图形化移动
案例名称汉诺塔的图形化移动
问题描述图形化实现将汉诺塔上的N个盘子按规则移动到右侧。
解题思路 声明“塔柱”类数据存储塔柱上的盘子列表方法包括向“塔柱”添加盘子列表增加、移去盘子列表删除、获取塔柱的高度列表长度以及最高处存放的盘子编号列表最后一个值等。 导入turtle库创建并画出三个塔柱。同时创建塔柱类并初始化第一个塔柱数据。 创建N个盘子列表。画出N个盘子外形为方形将盘子编号和外形尺寸对应起来。 移动汉诺塔将数据层面的移动和图形化移动结合起来。注意要先完成图形化移动再实现数据层面移动。
递归移动方法将n个盘子中的第n个看作为一个大盘剩余n-1个盘子看作为一个小盘。先借助最右侧柱移动小盘到中间柱再移动大盘到右侧柱最后借助最左侧柱移动中间柱上的小盘到右侧柱。
汉诺塔汉诺塔又称河内塔问题是源于印度一个古老传说的益智玩具。传说大梵天创造世界的时候做了三根金刚石柱子在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定在小圆盘上不能放大圆盘在三根柱子之间一次只能移动一个圆盘。
代码示例如下
import turtle as t
from random import randomN 3 # 要移动的盘数class Pole: # 定义杆类def __init__(self): # 初始化列表存储本杆当前的盘子self.plates []def platePush(self, i): # 列表中添加元素入栈self.plates.append(i)def platePop(self): # 列表中减少一个元素出栈return self.plates.pop()def poleHeight(self): # 返回当前杆的高度即元素个数return len(self.plates)def draw_create_poles(n): # 画出三个杆定义并返回N个盘子的列表p [t.Turtle() for i in range(3)]t.setup(1200, 500)t.hideturtle()for i in range(3):p[i].penup()p[i].hideturtle()p[i].goto(400 * (i - 1), 100)p[i].pendown()p[i].pensize(10)p[i].color(random(), random(), random())p[i].goto(400 * (i - 1), -100)p[i].goto(400 * (i - 1) - 20, -100)p[i].goto(400 * (i - 1) 20, -100)pl [Pole() for i in range(3)] # 定义三个杆列表for i in range(N): # 向第一个杆中放入N个盘子pl[0].platePush(i)return pldef draw_create_plates(n): # 创建、画出并返回N个盘子的列表p [t.Turtle() for i in range(n)]for i in range(n):p[i].shape(square)p[i].color(random(), random(), random())p[i].penup()p[i].shapesize(1, 8 - i)p[i].goto(-400, -90 20 * i)return pdef move_plate(pl, pa, a, b):i pl[a].plates[len(pl[a].plates) - 1]pa[i].goto(400 * (a - 1), 120)pa[i].goto(400 * (b - 1), 120)j pl[b].poleHeight()pa[i].goto(400 * (b - 1), -90 20 * j)def hanoi(poleList, plates, n, a, b, c):if n 1:hanoi(poleList, plates, n - 1, a, c, b)print(从{}柱移动到{}柱。.format(a, c))move_plate(poleList, plates, a, c)poleList[c].platePush(poleList[a].platePop())hanoi(poleList, plates, n - 1, b, a, c)def main():pl draw_create_poles(N)pa draw_create_plates(N)hanoi(pl, pa, N, 0, 1, 2)t.mainloop() if __name__ __main__:main()输出文字示例如下动画效果自行尝试
从0柱移动到2柱。
从0柱移动到1柱。
从2柱移动到1柱。
从0柱移动到2柱。
从1柱移动到0柱。
从1柱移动到2柱。
从0柱移动到2柱。