我们已经知道 Python 中“万物皆对象”,每个对象都有特定的类型,现在我们来尝试创建自己的类型——这需要使用 class 关键字来定义一个新的“类”(Class),class 是用于生成对象的“模板”,对象是其类的“实例”——下面是在交互方式下自定义Thing类,调用其默认构造函数生成Thing类的实例对象(注意: self 定义类的命名约定要求单词首字母大写):
In [1]: class Thing:
...: """最简单的自定义类"""
...:
In [2]: type(Thing)
Out[2]: type
In [3]: t = Thing()
In [4]: type(t)
Out[4]: __main__.Thing
可见,Thing对象属于type类型,是type类的实例; t对象属于Thing类型,是Thing类的实例——当你在程序中定义自己的类来生成实例对象时,就被认为是“面向对象”。面向对象编程”(Object-Oriented Programming,简称OOP)。面向对象编程使用类来模拟和组织现实世界中的事物,可以使程序结构更加灵活和清晰。
上面定义的Thing类生成的实例对象什么也做不了。让我们创建一个包含特定子语句的“ship”类,并生成两个“ship”对象:
In [5]: class Ship:
...: """船类"""
...: def __init__(self, name=None):
...: """初始化船实例"""
...: self.name = name # 船名
...: self.crew = 0 # 船员人数
...: def join(self, number):
...: """船员加入"""
...: self.crew += number
...: return self.crew
...:
In [6]: s1 = Ship("郑和")
In [7]: s1.crew = 200
In [8]: s2 = Ship("戚继光")
In [9]: s2.join(100)
Out[9]: 100
In [10]: s2.crew
Out[10]: 100
Ship类定义了一个特殊的“初始化”方法__init__,以便在调用构造函数生成实例时可以添加一个新的实例“属性”(Property)。所谓实例属性就是实例对象的“成员变量”,比如Ship类的实例增加了name和crew属性——从现实的概念理解,任何一艘船都有ship这两个数据姓名和船员编号,但每艘船都有自己特定的数据值。实例属性和实例方法是两个最常见的类成员。 Python 规定特殊的类成员名称以两个下划线开头和结尾。其他类成员名称遵循标准变量命名约定。注意这里有一个详细的概念:_作为类成员_init__属于函数,__init__作为实例成员属于方法。在类中定义函数时,约定第一个参数为“self”,会指向生成的实例对象来操作其成员,而对应的实例方法是没有这个参数的,所以只需要传入调用 Ship 构造函数时的一个参数(也可以不传入任何参数,因为 name 指定了默认值)。除了实例属性之外,你还可以定义新的实例方法,让实例可以做更多的事情——例如,“ship”类也有一个“crew join”方法。
In [11]: help(Ship)
Help on class Ship in module __main__:
class Ship(builtins.object)
| 船类
|
| Methods defined here:
|
| __init__(self, name=None)
| 初始化船实例
|
| join(self, number)
| 船员加入
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
In [12]: type(Ship.__init__)
Out[12]: function
In [13]: type(s2.__init__)
Out[13]: method
In [14]: s1.__dict__
Out[14]: {'crew': 200, 'name': '郑和'}
实例对象之所以有不需要自定义但默认存在的特殊成员,是因为面向对象编程的一个重要特性“继承”(Inheritance)——利用继承机制将复杂系统有机地组织起来,所有的类都是同一个大家族的一员——定义类时,可以在类名后加括号指定“基类”,新类将成为它的“子类”;如果不指定基类,则默认为最基本的“对象”类的子类。子类会继承基类已有的成员,如果子类定义了与基类成员同名的属性和方法,则会“覆盖”基类成员。例如,下面的程序定义了“ship”类及其子类“warship”类:
"""ship.py 船的家族"""
class Ship:
"""船类"""
def __init__(self, name=None):
"""初始化船实例"""
self.name = name # 船名
self.crew = 0 # 船员人数
def join(self, number):
"""船员加入"""
self.crew += number
return self.crew
class Warship(Ship):
"""战舰类"""
def __init__(self, name=None, level=None):
super().__init__(name) # 先调用基类初始化方法
self.level = level # 舰级
if __name__ == "__main__":
ws1 = Warship("蓝色空间", "恒星级")
ws1.join(500)
print("{}战舰{}号,现有舰员{}人。".format(ws1.level, ws1.name, ws1.crew))
可以注意到Warship类重定义了__init__,它会覆盖Ship类中的__init__,所以可以先调用基类的__init__来继承基类定义的实例属性name和crew。
接下来的示例是一个简单的计算器:
"""tkcalc.pyw 简单的计算器
"""
import tkinter as tk
class Calc(tk.Tk):
"""计算器窗体类"""
def __init__(self):
"""初始化实例"""
tk.Tk.__init__(self)
self.title("计算器")
self.memory = 0 # 暂存数值
self.create()
def create(self):
"""创建界面"""
btn_list = ["C", "M->", "->M", "/",
"7", "8", "9", "*",
"4", "5", "6", "-",
"1", "2", "3", "+",
"+/-", "0", ".", "="]
r = 1
c = 0
for b in btn_list:
self.button = tk.Button(self, text=b, width=5,
command=(lambda x=b: self.click(x)))
self.button.grid(row=r, column=c, padx=3, pady=6)
c += 1
if c > 3:
c = 0
r += 1
self.entry = tk.Entry(self, width=24, borderwidth=2,
bg="yellow", font=("Consolas", 12))
self.entry.grid(row=0, column=0, columnspan=4, padx=8, pady=6)
def click(self, key):
"""响应按钮"""
if key == "=": # 输出结果
result = eval(self.entry.get())
self.entry.insert(tk.END, " = " + str(result))
elif key == "C": # 清空输入框
self.entry.delete(0, tk.END)
elif key == "->M": # 存入数值
self.memory = self.entry.get()
if "=" in self.memory:
ix = self.memory.find("=")
self.memory = self.memory[ix + 2:]
self.title("M=" + self.memory)
elif key == "M->": # 取出数值
if self.memory:
self.entry.insert(tk.END, self.memory)
elif key == "+/-": # 正负翻转
if "=" in self.entry.get():
self.entry.delete(0, tk.END)
elif self.entry.get()[0] == "-":
self.entry.delete(0)
else:
self.entry.insert(0, "-")
else: # 其他键
if "=" in self.entry.get():
self.entry.delete(0, tk.END)
self.entry.insert(tk.END, key)
if __name__ == "__main__":
Calc().mainloop()
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 如何在python中编写不等号10/10
- ♥ python如何注释代码行12/07
- ♥ 如何在python中使用随机数09/27
- ♥ 如何在python中选择32位或64位09/19
- ♥ 如何在 Python 中查找素数?12/04
- ♥ python模块的内置属性是什么?09/13
内容反馈