Python3类和对象

类和对象

定义类

  1. 语法如下 :
	class Person:
	# 类变量
	hair = 'black'
	# 构造方法
	def __init__(self, name='Alex', age=24):
		self.name = name
		self.age = age
	# 实例方法
	def say(self, content):
		print(content)
  1. 类名:类名必须由一个或多个有意义的单词连缀而成,每个单词 首字母大写,其它字母小写,单词与单词之间 不要使用任何分隔符

  2. Python类所包含的 类变量可以动态增加或删除。在类体中为新变量赋值就是 增加类变量,程序也可在任何地址为已有的类及其实例增加变量;程序可 通过 del 语句删除已有类或实例的变量

  3. 类中定义的方法默认是 实例方法,实例方法至少应该定义一个参数,该参数通常命名为 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
"""
  • 装饰器的作用:
    1. 将funB作为 funA()的参数传入
    2. 将funB替换成第1步执行的结果
    3. 它即可以在被修饰函数的前面添加一些额外的处理逻辑(比如权限检查、记录日志),还可以在目标方法抛出异常时进行一些修复操作等

使用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

转载于:https://my.oschina.net/zerobit/blog/3073758

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值