类和对象
定义类
- 语法如下 :
class Person:
# 类变量
hair = 'black'
# 构造方法
def __init__(self, name='Alex', age=24):
self.name = name
self.age = age
# 实例方法
def say(self, content):
print(content)
-
类名:类名必须由一个或多个有意义的单词连缀而成,每个单词 首字母大写,其它字母小写,单词与单词之间 不要使用任何分隔符
-
Python类所包含的 类变量可以动态增加或删除。在类体中为新变量赋值就是 增加类变量,程序也可在任何地址为已有的类及其实例增加变量;程序可 通过
del语句删除已有类或实例的变量 -
类中定义的方法默认是 实例方法,实例方法至少应该定义一个参数,该参数通常命名为
self,该参数 会被绑定到类的实例上
对象的产生和使用
# 实例化Person类
p = Person()
# 调用实例变量
print(p.name, p.age)
# 为实例变量赋值
p.name = 'Jack'
# 调用实例方法
p.say("Hello")
# 新增实例变量
p.skills = ['programming', 'swimming']
# 删除实例变量
del p.name
print(p.name) # AttributeError
类的方法
类调用实例方法
使用类调用实例方法时,必须显式地为方法第一个参数
self传入方法调用者,否则会报错
p = Person()
Person.say(p, "Hello") # 使用类调用实例方法,效果与 p.say("hello")一样
类方法与静态方法
- 类方法与静态方法都推荐 使用类来调用
- 类方法的第一个参数(通常建议命名为cls)会自动绑定;静态方法则不会自动绑定,必须显式传入
class Bird:
# 类方法
@classmethod
def fly(cls):
print(cls)
# 静态方法
@staticmethod
def info(p):
print(p)
Bird.fly()
Bird.info("crazyit")
@函数装饰器
def funA(fn):
print('A')
fn() # 执行传入的函数参数
return 'fkit'
@funA
def funB():
print('B')
print(funB)
"""
输出结果:
A
B
fkit
"""
- 装饰器的作用:
- 将funB作为 funA()的参数传入
- 将funB替换成第1步执行的结果
- 它即可以在被修饰函数的前面添加一些额外的处理逻辑(比如权限检查、记录日志),还可以在目标方法抛出异常时进行一些修复操作等
使用property函数定义类的属性
如果为Python类定义了getter、setter等方法,则可以使用property()函数将类变量定义为属性(相当于实例变量)
- 语法
property(fget, fset, fdel, doc)
- 4个参数分别代表getter方法、setter方法、del方法和doc字符串(说明该属性)
- 也可以传入0个(即不能读,也不能写)、1个(只读)、2个(读写)、3个(读写、删除)参数
class User :
def __init__ (self, first, last):
self.first = first
self.last = last
def getfullname(self):
return self.first + ',' + self.last
def setfullname(self, fullname):
first_last = fullname.rsplit(',')
self.first = first_last[0]
self.last = first_last[1]
fullname = property(getfullname, setfullname) # fullname属性可读可写,不可删除
u = User("悟空", "孙")
print(u.fullname) # 访问属性
u.fullname = "八戒,猪" # 修改属性
print(u.first) # 八戒
print(u.last) # 猪
隐藏和封装
Python类定义的所有成员默认都是公开的,如果程序希望将Python类中的某些成员隐藏起来,只要让该成员的名字以双下画线开关即可。
class User :
# 隐藏的方法,外部不能直接访问
def __hide(self):
pass
def getname(self):
return self.__name # 隐藏的成员变量__name,外部也不能直接访问
def setname(self, name):
if len(name) < 3 : # 对用户设置的name属性进行控制
raise ValueError("用户名长度必须超过3位")
self.__name = name
name = property(getname, setname)
u = User()
u.name = 'fk' # 会引发ValueError错误,因为该成员变量已被控制进行有效检查
类的继承
继承的语法
class SubClass(SuperClass1, SuperClass2, ...) :
# 类定义部分
- object类是所有类的父类
关于多继承
虽然Python在语法上明确支持多继承,但通常推荐:如果不是很有必要,则尽量不要使用多继承
重写父类的方法
class Bird:
def fly(self):
print("Bird fly...")
class Ostrich(Bird):
def fly(self):
print("Ostrich run...")
os = Ostrich()
os.fly() # 输出结果:"Ostrich run..."
在子类中调用父类的方法
class ParentClass:
def __init__(self, salary):
self.salary = salary
def foo(self):
pass
class SubClass(ParentClass):
def __init__(self, salary):
# 调用父类的构造方法
super().__init__(salary)
# 重写父类的方法
def foo(self):
pass
def bar(self):
# 调用自己的方法
self.foo()
# 调用父类的方法
ParentClass.foo(self)
sc = SubClass(5000)
sc.bar()
Python类的动态性
动态属性与__slots__
Python类的属性、方法都可以动态增加和修改。但程序定义好的类,有可能在后面被其它程序修改,这就带来了一些不确定性。
- __slots__:可以限制为某个类动态添加属性和方法
- __slots__属性的值是一个目标元组,该无组的所有元素列出了该类的实例 允许动态添加的所有属性名和方法名
class Dog:
# 只允许为实例动态添加walk, age, name这三个属性或方法
__slots__ = ('walk', 'age', 'name')
def __init__(self, name):
self.name = name
def test():
pass
d = Dog('Snoopy')
from types import MethodType
# 动态添加walk方法
d.walk = MethodType(lambda self: print("%s is walking..." % self.name), d)
d.walk()
# 动态添加age属性
d.age = 5
# 添加其它属性会抛AttributeError异常
d.foo = 30
使用模板类metaclass
- 如果希望创建某一批类全部具有某种特征,则可通过模板类
metaclass来实现
# 定义模板类
class ItemMetaClass(type):
# cls代表被动态修改的类
# name代表被动态修改的类名
# bases代表被动态修改的类的所有父类
# attr代表被动态修改的类的所有属性、方法组成的字典
def __new__(cls, name, bases, attrs):
# 为使用该模板类的所有类添加一个方法
attrs['cal_price'] = lambda self: self.price * self.discount
return type.__new__(cls, name, bases, attrs)
# 使用上面定义的模板类
class Book(metaclass = ItemMetaClass):
def __init__(self, price, discount):
self.price = price
self.discount = discount
b = Book(300, 0.8)
# Book类会自动拥有cal_price方法
print(b.cal_price()) # 240.0
多态
多态性
class Canvas:
def draw_pic(self, shape):
print("--开始绘图--")
shape.draw(self)
class Trangle:
def draw(self, canvas):
print("绘制三角形")
class Circle:
def draw(self, canvas):
print("绘制圆形")
c = Canvas()
c.draw_pic(Trangle())
c.draw_pic(Circle())
同一个变量
shape在执行同一个draw()方法时,由于指向不同的对象(Trangle()、Circle()),因此它呈现出不同的行为特征,这就是多态
类型检查
- issubclass(cls, class_or_tuple):检查
cls是否为后一个类或元组包含的多个类中任意类的子类 - isinstance(obj, class_or_tuple):检查
obj是否为后一个类或元组包含的多个类中任意类的实例对象
枚举类
import enum
Season = enum.Enum('Season', ('SPRING', 'SUMMER', 'FALL', 'WINTER'))
# 直接访问指定枚举
print(Season.SPRING) # 输出:Season.SPRING
# 访问枚举成员的变量名
print(Season.SPRING.name) # 输出:SPRING
# 访问枚举成员的值
print(Season.SUMMER.value) # 输出:2
11万+

被折叠的 条评论
为什么被折叠?



