D10 类与对象

mac2024-10-16  51

在对象里也有变量,用来存储数据,这时变量又称字段 (fields) 在对象里也有函数,用来操作数据,这时函数又称方法 (methods) 字段和方法统称为类的属性 (attributes)

本帖的讲述逻辑如下: 第一章先用 Python 里面内置的 int, list, ndarray 和 dataframe 变量举例,感受一下 Python 中万物皆对象,体会一下对象里的属性 (字段和方法)

第二章详细介绍面向对象编程的细节,内容包括:实例变量、类变量、实例方法、类方法、静态方法、继承、多态、魔法方法、属性装饰器等。 第一章 - 对象初体验 1.1 整型 int 1.2 列表 list 1.3 NumPy 数组 - ndarray 1.4 Pandas 数据帧 - dataframe 第二章 - 面向对象编程 2.1 极简类和对象 2.2 init() 和 self 2.3 类变量 (千人千面) 2.4 类变量 (千人一面) 2.5 类方法 + 静态方法 2.6 其他构建函数 2.7 继承和多态

1.1 整形int 这样我们脑海里应该复现这样的类比: 类 : 对象 int : i

i=1024 i.numerator #字段显示1024 i.bit_length()#字段长度的方法,显示为11

1.2列表 list

l = [1, 2, 3] l.append(4) l.__getitem__(2) #得到索引对象的值 print(l + l)#[1, 2, 3, 4, 1, 2, 3, 4] print(l.__add__(l))#[1, 2, 3, 4, 1, 2, 3, 4] print(l * 2)#[1, 2, 3, 4, 1, 2, 3, 4] print(l.__mul__(2))#[1, 2, 3, 4, 1, 2, 3, 4]

1.3 NumPy 数组 - ndarray

import numpy as np arr = np.array( [[1,2,3],[4,5,6],[7,8,9]] ) arr.ndim#2 # 对象.方法() arr.sum()#45 # 类.方法(对象) np.sum(arr)#45 print( arr + arr ) print(arr.__add__(arr))

后两行代码的输出结果: 1.4 Pandas 数据帧 - dataframe

import numpy as np import pandas as pd df = pd.DataFrame( np.arange(6).reshape(2,3), columns=list('abc') ) print(df.columns)#Index(['a', 'b', 'c'], dtype='object') print(df.cumsum())

2.1 极简类和对象 创建一个类,创建两个 Employee 类的对象 emp_1 和 emp_2,打印它们的信息包含对象储存的位置,但也证实对象创建成功,只不过可读性极差 (后面会改进)。

class Employee: pass emp_1 = Employee() emp_2 = Employee() print(emp_1)#<__main__.Employee object at 0x0000025DEFC05E10> print(emp_2)#<__main__.Employee object at 0x0000025DEFC05E48>

2.2__init__() 和 self 上节的类里是空的,实际的类是将属性聚集的,用的就是 init 方法。这种将属性聚在一起称作封装 (encapsulation),这是类的第一个特征. 调用 init 方法就是在构建类的实例,即对象. 注意到 init 方法第一个参数永远是 self,表示在创建对象本身;后面的参数都是 Employee 字段 (fields),常见的赋值方式就是

class Employee: def __init__(self,first,last,pay): self.first=first self.last=last self.pay=pay def fullname(self): return '{},{},{}'.format(self.first,self.last,self.pay) emp_1=Employee('zhang','san','1000') emp_2=Employee('yang','shan','1000') print(emp_1.fullname())#zhang,san,1000 print(emp_2.fullname())#yang,shan,1000 print( Employee.fullname(emp_1))#zhang,san,1000 print( Employee.fullname(emp_2))#yang,shan,1000

2.3 类变量 (千人千面)

class Employee: raise_rate=2.99 def __init__(self,first,last,pay): self.first=first self.last=last self.pay=pay def fullname(self): return '{},{}'.format(self.first,self.last) def apply_raise(self): self.pay= int(self.pay) *int(self.raise_rate) emp_1=Employee('zhang','san','100000') emp_2=Employee('yang','shan','1000') print(emp_1.pay) emp_1.apply_raise() print(emp_1.pay)

如果通过类访问来改变类变量 raise_rate ,那么类和对象下的 raise_rate 值都会变。 如果通过对象 emp_1 访问来改变类变量 raise_rate ,那么只会是对象 emp_1下的 raise_rate 值会变,而类下的和对象 emp_2 的 raise_rate 值不会变。 总结:如果想让类变量千人一面,用 self.类变量 Python 的 self 相当于 C++ 的 this 指针。 2.4 类变量 (千人一面) 增加雇员数目的类变量

class Employee: raise_rate=2.99 num_of_emps=0 def __init__(self,first,last,pay): self.first=first self.last=last self.pay=pay Employee.num_of_emps +=1 def fullname(self): return '{},{}'.format(self.first,self.last) def apply_raise(self): self.pay= int(self.pay) *int(self.raise_rate) print(Employee.num_of_emps)#0 emp_1=Employee('zhang','san','100000') print(Employee.num_of_emps)#1 emp_2=Employee('yang','shan','1000') print(Employee.num_of_emps)#2

总结:如果想让类变量千人一面,用 类名.类变量 2.5 类方法 + 静态方法 到目前为止,类里的方法都是实例方法 (instance method),它们都适用于对象。本节介绍类方法 (class method) 和静态方法 (static method)。

class Employee: raise_rate=2.99 num_of_emps=0 def __init__(self,first,last,pay): self.first=first self.last=last self.pay=pay Employee.num_of_emps +=1 def fullname(self): return '{},{}'.format(self.first,self.last) def apply_raise(self): self.pay= int(self.pay) *int(self.raise_rate) @classmethod #类方法 def set_raise_rate(cls,rate): cls.raise_rate=rate @staticmethod #静态方法 def is_workday(day): if day.weekday()==5 or day.weekday()==6: return False return True

先讲类方法,类方法适用于该类,即对该类下的所有对象的作用的相同的。类方法有两个特点:

第一行要有装饰器 @classmethod (记住就行了)函数第一个参数必须是关键词 clf (对象一个参数必须是关键词 self) emp_1=Employee('zhang','san','100000') emp_2=Employee('yang','shan','1000') print(Employee.raise_rate)#2.99 print(emp_1.raise_rate)#2.99 print(emp_2.raise_rate)#2.99

用类 Employee 来调用类方法,将薪水涨幅调成 1.1,所有用类和对象来访问的 raise_rate 都变成了 1.1。

Employee.set_raise_rate( 1.1 ) print( Employee.raise_rate )#1.1 print( emp_1.raise_rate )#1.1 print( emp_2.raise_rate )#1.1

用对象 emp_1来调用类方法,将薪水涨幅调成 1.2,所有用类和对象来访问的 raise_rate 都变成了 1.2。

emp_1.set_raise_rate( 1.2 ) print( Employee.raise_rate )#1.2 print( emp_1.raise_rate )#1.2 print( emp_2.raise_rate )#1.2

小结:类方法是所有对象和类都能调用,而且产生的效果是一样。 再讲静态方法 一个类还会有些效用函数 (utility function),它们不随对象和类的属性而改变,因此我们称它们为静态方法。 静态方法也有两个特点:

第一行要有装饰器 @staticmethod (记住就行了)函数参数绝对不能有关键词 clf 和 self import datetime my_date = datetime.date(2019, 11, 1) print( Employee.is_workday(my_date) ) #True

2.6 其他构建函数

def from_string(cls,emp_str): first,last,pay=emp_str.split('-') return cls(first,last,pay) emp_str_1='Steven-zhang-2000000' emp_1=Employee.from_string(emp_str_1) print(emp_1)

2.7 继承和多态 继承 (inheritance) 是类的一大特征。有继承就必有父类 (parent class) 和子类 (child class)。 下面构建雇员 Employee 的两个子类,开发者 Developer 和经理 Manager。由父类衍生出来多个子类称为多态 (polymorphism)。 子类Developer

class Developer(Employee): pass dev_1=Developer('steven','wang','2000000') print(dev_1.email)#steven.wang@gmail.com

虽然在 Develop 子类里没有定义任何操作,但是他们继承了父类 Employee 里面的邮箱地址的字段。 如果在子类中更改父类的字段,那么不再使用父类的字段。 现在完善子类 Developer,但是 init 方法里面的代码重复。那么怎么办呢?可以用super方法 以上的super方法让其更简化。输出结果是: 子类manager

class Employee: raise_rate=2.99 num_of_emps=0 def __init__(self,first,last,pay): self.first=first self.last=last self.pay=pay self.email=first+'.'+last+'@gmail.com' def fullname(self): return '{},{}'.format(self.first,self.last) def apply_raise(self): self.pay= int(self.pay*self.raise_rate) class Developer(Employee): def __init__(self,first,last,pay,prog_lang): super().__init__(first,last,pay) self.prog_lang=prog_lang self.email=first+'.'+last+'@gmail' class Manager(Employee): def __init__(self,first,last,pay,employees=None): super().__init__(first,last,pay) if employees==None: self.employees==[] else: self.employees=employees def add_emp(self,emp): if emp not in self.employees: self.employees.append(emp) def remove_emp(self,emp): if emp in self.employees: self.employees.remove(emp) def print_emp(self): for emp in self.employees: print('-->',emp.fullname()) dev_1=Developer('steven','wang',1000000,'py') dev_2=Developer('LILY','yang',20000000,'java') mgr_1=Manager('Jack','Black',500000,[dev_1]) print(mgr_1.email) mgr_1.print_emp()

两种检查函数

-函数 isinstance(a, A) 是检查 a 是不是 A 的一个实例。

函数 issubclass(A, B) 是检查 A 是不是 B 的一个子类。 形如,print( issubclass(Manager, Employee) ),结果为True 或 False 多态:不同对象对同一方法响应不同的行动 class Animal: def run(self): raise AttributeError('子类必须实现这个方法') class People(Animal): def run(self): print('人正在走') class Pig(Animal): def run(self): print('pig is walking') class Dog(Animal): def run(self): print('dog is running') def func(animal): animal.run() func(Pig()) # pig is walking
最新回复(0)