Python:class简单介绍

Python class

一、类的构造 & 初始化

通过 __init__ 内置函数进行初始化:

class Student:

	def __init__(self, name, age):
		print('Start initialization...')
		self.name = name
		self.age = age
		
alice = Student('Alice', 20)
bob = student('Bob', 20)
# show address
print(id(alice)) # different address
print(id(bob))
# show dictionary of each student
print(alice.__dict__)
# {'name': 'alice', 'age': 20}
print(bob.__dict__)
# {'name': 'bob', 'age': 20}

通过__dict__ 实现多字段初始化的代码优化:

class person:
	'''
	def __init__(self, name, age, hobby, address, email):
		# intialization
		# self.name = name
		# ...
		# self.email = email
	'''
	# using __dict__ to init
	def __init__(self, info):
		self.__dict__.update(info)


perinfos = open('person_info.txt', 'r')
persons = []
for p in perinfos:
	info = p.split(', ')
	persons.append(person(info))

print(persons)

二、类的特点

  • 多态 Polymorphism
  • 封装 Capsulation
  • 继承 Inheritation

2.1 类的继承:Inheritation

2.1.1 继承的定义
###########################################################################################################
###########################################################################################################
###     ___                     ______    ____    ___   _______           _______   ___    ___             
###      |    |\   |   |     |  |        |    \    |       |        /\       |       |    /   \   |\   |   
###      |    | \  |   |_____|  |____    |____/    |       |       /  \      |       |   |     |  | \  | 
###      |    |  \ |   |     |  |        |   \     |       |      /----\     |       |   |     |  |  \ |   
###     _|_   |   \|   |     |  |_____   |    \   _|_      |     /      \    |      _|_   \___/   |   \|   
###########################################################################################################
###########################################################################################################


# derived_class - Class this class derived from
class class_name(derived_class):
    
    # some variables
    # some override functions such as: __init__, __call__
    # some user defined function       
2.1.2 多重继承

Python 支持多重继承,子类会继承父类的所有变量和方法。变量搜索方式:

  • 从下往上
  • 从左往右
class parent1:
    x = 'parent1 x'
    parent_name = 'parent1'
class parent2:
    x = 'parent2 x'
    parent_name = 'parent2'
class child(parent1, parent2):
    myname = 'myname is child'
    
child = child()
print(child.myname)
print(child.parent_name) # output: parent1 which is first in parent list
2.1.3 搜索方式
  • 深度优先搜索(DFS, Depth-First-Search)
  • 广度优先搜索(BFS, Broadth-First-Search)
Python2:经典类和新式类区别

经典类:

class A:

	def echo(self):
		print('I am A')

class B(A):
	# do nothing
	pass

class C:

	def echo(self):
		print('I am C')


class D(B,C):
	pass


d = D()
print(d.echo()) # I am A

新式类:

class A(Object):

	def echo(self):
		print('I am A')

class B(A):
	# do nothing
	pass

class C:

	def echo(self):
		print('I am C')


class D(B,C):
	pass


d = D()
print(d.echo()) # I am C
Python3:统一为广度优先搜索

广度搜索

2.1.4 变量和方法

通过利用显式调用父类中的同名函数,实现代码优化。

功能函数的继承相关

首先我们定义了三个类:

  • person:基类,包含一个 say 方法和一个增加薪水的 `
  • staff:根据普通员工的薪水公式,重写父类中的薪水方法
  • manager:同上,但是薪水计算方法不同

我们在每个类中都定义了不同的薪水计算公式,并且设置了相应的形式参数:

class person:

	def __init__(self, name, age, salary):
		self.name = name
		self.age = age
		self.salary = salary

	def say(self):
		s = 'My name is %s, my age is %s, and my price is %s' %(self.name, self.age, self.price)

	def raise_salary(self, percentage):
		self.salary = self.salary * (1 + percentage)

class staff(person):

	def __init__(self):
		pass

	def raise_salary(self, percentage, performance):
		self.salary = self.salary * (1 + percentage + performance)

class manager(person):

	def __init__():
		pass

	def raise_salary(self, percentage, performance, shareoutbonus):
		self.salary = self.salary * (1 + percentage + performance + shareoutbonus)

显然,此时当我们希望对薪水计算公式,或者是参数进行修改时,我们需要对每个函数都进行修改,但是通过在子类的功能函数中通过显式调用父类的功能函数来实现,便可以直接对父类函数中的方法进行修改即可:

# staff
def raise_salary(self, percentage, performance):
	# self.salary = self.salary * (1 + percentage + performance)
	person.raise_salary(percentage = percentage + performance)
# manager
def raise_salary(self, percentage, performance, shareoutbonus):
	# self.salary = self.salary * (1 + percentage + performance + shareoutbonus)
	person.raise_salary(percentage = percentage + performance + shareoutbonus)
构造函数的继承相关

当子类中添加了新的成员变量,并且在希望在构造过程中传递新的变量时:

## 构造函数的继承

class person:
	def __init__(self, name, age, price):
		self.name = name
		self.age = age
		self.price = price


class manager(person):

	def __init__(self, address):
		self.address = address


m2 = manager('m2', 20, 1000, 'Dongguan') # error 'cause __init__ has been overrrided

此时如果子类的初始化函数仅包含新的字段形参,而在构造的时候传递了包括父类初始化函数中的参数,报错,因为 __init 的方法是在子类中被完全重写,并且 Python 并不会为多余的参数隐式调用父类的初始化函数,因此需要完整的重写初始化函数,给出相应的每个字段的赋值语句:

## 构造函数的继承

class person:
	def __init__(self, name, age, price):
		self.name = name
		self.age = age
		self.price = price


class manager(person):

	def __init__(self, name, age, price, address):
        self.name = name
		self.age = age
		self.price = price
		self.address = address


m2 = manager('m2', 20, 1000, 'Dongguan') # error 'cause __init__ has been overrrided

显然,此时子类和父类的初始化函数中存在较多的重复代码。

当子类的初始化函数中和父类存在大量重复的赋值语句时,可以通过显式调用父类的初始化函数来实现代码优化:

class person:
	def __init__(self, name, age, price):
		self.name = name
		self.age = age
		self.price = price


class manager(person):

	def __init__(self, name, age, price, address):
		self.address = address
		'''
		self.name = name
		self.age = age
		self.price = price
		'''
		# instead explicitly called person's initialization method
		person.__init__(self, name, age, price)


m2 = manager('m2', 20, 1000, 'Dongguan') # pass
2.1.5 继承的应用场景
  • 合成
  • 聚合
  • 复用
合成

部分和整体的生命周期一致,整体拥有对其组织部份的支配权,且一个成分只属于一个合成关系,不可共享

例如:

  • 房子:包含房间s,房间s只属于这个房子,房子消失,房间消失,一种强拥有的关系
  • 房间:房子内部,生命周期小于或者等于房子,房子消失必然伴随房间消失
class room:
	def create_room(self):
		print("this is a new room")


class house:
	def __init__(self):
		self.room = room()

	def create_house(self):
		self.room.create_room()


h1 = house()
h1.create_house()
聚合

表示一种拥有关系,整体与部分之间的关系

例如:

  • 学生:部分,学校倒闭了,但是学生依然存在,不会因为整体的消失而消失,即部分的生命周期可以超过整体
  • 班机班级:包含每个学生部分的整体
# 学生,教室的一部分
class student:
	pass

# 教室,包含学生的整体
class classroom:
	def __init__(self, student):
		self.student = student


s1 = student()
c1 = classroom(s)

对象关系:

  • IS-A :我是一个人(?),显然这是一种继承关系
  • HAS-A:人拥有脑子(?),显然是一种合成关系

例子:
m a n { i n   c o m p a n y : e m p l o y e e a t   h o m e : h u s b a n d f a t h e r a t   s c h o o l : s t u d e n t man\begin{cases} in\ company:employee\\ at\ home:husband&father\\ at\ school:student \end{cases} manin company:employeeat home:husbandat school:studentfather

class person:
	def show(self):
		print('live a happy life')

class staff:
	def show(self):
		print("try to work hard")



class husband(person):

	def show(self):
		print("work and earn money")


class student(person):

	def show(self):
		pritn("good good study day day up")


p = staff()
p.show()
# different person, not able to create a person with different roles
p = husband()
p.show()


class role:
	def show(self):
		pass


class staff(role):
	def show(self):
		print("try to work hard")



class husband(role):

	def show(self):
		print("try best to make family happy")


class student(role):

	def show(self):
		pritn("good good study day day up")

class person:
	def set_role(self, role):
		self.role = role

	def get_role(self):
		self.role.show()


p = person()
p.set_role(staff)
p.get_role() # "try to work hard"

p.set_role(husband)
p.get_role() # "try best to make family happy"

p.set_role(student)
p.get_role() # "good good study day day up"
复用

l o a d i n g … loading\dots loading

2.1.6 迪米特原则:最小知道原则

保证封装性,减少类的内部暴露,例子:

  • A 类:被 B 依赖,只暴露必须提供的方法和属性,即定义好方法和属性的可见范围
  • B 类:依赖于 A,只依赖应该依赖的对象,即只想需要提供信息的对象提供信息,不向无关的类暴露内容

例如:

class A:
	def __init__(self, name):
		self.name = name
	def get_b(self, name):
		return B(name)

	# A -> B -> C to work
	def work(self):
		b = self.get_b('b')
		c = b.get_c('c')
		c.work()

class B:
	def __init__(self, name):
		self.name = name
	def get_c(self, name):
		return C(name)


class C:
	def __init__(self, name):
		self.name = name
	def work(self):
		print('Done! by' + self.name)


a = A('a')
a.work()

可以发现,此时在 A 中调用了 C 相关的代码,但是显然 C 应该是对 A 隐藏的,也就是说,我们应该利用 B 来让 C 完成相关的工作,而 A 只需要联系 B 即可:

class A:
	def __init__(self, name):
		self.name = name
	def get_b(self, name):
		return B(name)

	# A -> B -> C to work
	def work(self):
		b = self.get_b('b')
        # c = b.get_c('c')
		# c.work()
		b.work()

class B:
	def __init__(self, name):
		self.name = name
	def get_c(self, name):
		return C(name)
    def work(self):
        c = self.get_c('c')
        c.work()


class C:
	def __init__(self, name):
		self.name = name
	def work(self):
		print('Done! by' + self.name)


a = A('a')
a.work()a.work()

此外,对于被依赖者来说,依赖者应该尽可能的减少内部具体的流程方法的暴露,而只向用户提供一个用户友好的并且细节隐藏的方法,既提高类的封装性,又能提高用户的使用体验:

class computer:
    # private methods
	def __stop_service(self):
		print('wait for stopping process...done!')

	def __poweroff(self):
		print('wait for power off...done!')

	def __shut_screen(self):
		print('screen is going to sleep...done!')

	def __save_data(self):
		print('writing back data...done!')

	# public 
	def shutdown(self):
		self.__stop_service()
		self.__save_data()
        self.__shut_screen()
		self.__poweroff()


if __name__ == '__main__':
	c = computer()
	c.shutdown()
    # c.__save_data() error
    # c.__stop_service() error

2.2 类的封装:Capsulation

########################################################################################################
########################################################################################################
###     ___              ____     ___                             _______   ___    ___             #####
###    /   \     /\     |    \   /   \   |     |  |         /\       |       |    /   \   |\   |   #####
###   |         /  \    |____/   \___    |     |  |        /  \      |       |   |     |  | \  |   #####
###   |        /----\   |            \   |     |  |       /----\     |       |   |     |  |  \ |   #####
###    \___/  /      \  |        \___/   |_____|  |_____ /      \    |      _|_   \___/   |   \|   ###
############################################################################################################
############################################################################################################

首先,在 Python 中,封装只是一种约定,也就是说,事实上任何一个对象的内部变量都可以通过某种方式在外部访问。对于一个普通的变量来说,外部可以随意访问,比如:

class temp:
    
    var = 1
    
    # some definitions
        

这个变量 var 可以在外部随意访问。

不可访问类型,Python 约定了两种内部变量:

  • _varname:变量名以下划线开头的变量
  • __varname:变量名以双下划线开头的变量

例如:

class temp:
    
    var = 1
    
    def __init__(self):
        
        self._var = 2
        self.__var = 3
    
    # other definitions


t = temp()
print(t.var) # 1
print(t._var) # 2,依然可以访问,仅仅是约定
print(t.__var) # error,双下划线不可以访问
print(t._temp__var) # 3, 但是依然可以通过字典访问,进一步说明 Python 的私有仅仅只是约定,并没有完全限制访问

2.3 类的多态:Polymophism

class animal:
	def run(self):
		print('it is running')

class dog(animal):
	def run(self):
		print('dog is running')

class cat(animal):
	def run(self):
		print('cat is running')

if __name__ == '__main__':
	d = dog()
	d.run()

	c = cat()
	c.run()

	print(isinstance(d, dog)) # True
	print(isinstance(d, animal)) # True
	print(isinstance(c, animal)) # True
	print(isinstance(c, dog)) # False

三、抽象类

  • 不能实例化(当存在抽象方法时)
  • 通过函数装饰器 @abstractmethod 将抽象类中相应的功能函数设置为抽象函数,子类必须实现
from abc improt ABCMeta, abstractmethod

class animal(metaclass=ABCMeta):

	def__init__(self, name, age):
		self.name = name
		self.age = age
	@abstractmethod
	def run(self):
		pass

class dog(animal):

	def __init__(self, name, age):
		self.name = name
		self.age = age

	def run(self):
		print('a dog runs with four legs running')


class kangroo(animal):

	def __init__(self, name, age):
		self.name = name
		self.age = age

	def run(self):
		print('a kangroo runs with two legs jumping')


d = dog('dd', 3)
d.run()

k = kangroo('kk', 5)
k.run()

通过抽象类:

  • 保证子类包含并且实现相应的功能
  • 保证命名的规范
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值