Python面向对象30个微代码(含解释)

# 部分代码参考自网络
#0 认识对象里方法的调用
class Animal:
    def run(self):
        print("I can run")

a = Animal()
a.run()
#Animal.run(a) 等同于上述方法,类名.方法名传入对象为参数
#结果: I can run

# 1 创建类并生成对象
from collections import defaultdict


class Stu:
    name="JohnShen"
    score=80
if __name__ == '__main__':
    s1= Stu()
    print(s1.name+"\t"+str(s1.score))
#结果JohnShen	80


# 2 创建一个空类

class Stu:
    pass
if __name__ == '__main__':
    s1 = Stu()
    print(s1)
# 结果: 打印出对象的内存地址:<__main__.Stu object at 0x0000021s1DF9F5E0>>

# 3 通过type生成对象

s1 = type("Stu",(),{})()
s1.name = "JohnShen"
s1.score=80
print(s1.name+"\t"+str(s1.score))
#结果:JohnShen	80


# 4 在类方法定义及调用
 
class Stu:
    name = "JohnShen"
    score = 70
    def getGrade(self):
        if self.score>=60 and self.score<=80:
            return "您的工资级别是中级"
        elif self.score>80 and self.score<=100:
            return "您的工资级别是高级"
        elif self.score>100:
            return "分数不合法"
        else:
            return "您的工资级别是低级"
if __name__ == '__main__':
    s1= Stu()
    print(s1.getGrade())
#结果:您的工资级别是中级

# 5 通过init方法初始话对象

class Stu:
    def __init__(self,name="JohnShen",score=80):
        self.name=name
        self.score=score
if __name__ == '__main__':
    #s1= Stu() 如果不传参数,则取默认的参数值即name="JohnShen",score=10000
    s1=Stu("John","80") #指定参数name和score
    print(s1.name + "\t" + str(s1.score))
#结果:John	80


# 6 更新对象里属性

class Stu:
    def __init__(self, name="JohnShen", score=80):
        self.name = name
        self.score = score
if __name__ == '__main__':
    s1=Stu()
    print("更新前:\t"+s1.name + "\t" + str(s1.score))
    s1.score=90
    print("更新后:\t" + s1.name + "\t" + str(s1.score))
# 更新前:	JohnShen	70
# 更新后:	JohnShen	90


# 7 删除对象里属性
class Stu:
    def __init__(self, name="JohnShen", score=80):
        self.name = name
        self.score = score
if __name__ == '__main__':
    s1=Stu()
    print("删除前:\t"+s1.name + "\t" + str(s1.score))
    del s1.score
    print("删除后:\t" + s1.name)
    del s1
# 删除前:	JohnShen	80
# 删除后:	JohnShen

 #对比
class Stu:
    name="JohnShen"
    score=90
if __name__ == '__main__':
    s1=Stu() #注意因为该方式下s1类并没有定义属性,所以在执行del s1.score时会报错,同理del s1.name时也会报错
    print("删除前:\t"+s1.name + "\t" + str(s1.score))
    del s1.score
    print("删除后:\t" + s1.name)
# AttributeError: score


#8 查看对象的类型并进行对比
class Stu:
    name="JohnShen"
    score=90
if __name__ == '__main__':
    s1=Stu()
    s2=Stu()
    print("s1的对象类型是:\t"+str(type(s1)))
    print(type(s1) is type(s2))
# s1的对象类型是:	<class '__main__.Stu'>
# True


#9 拷贝一个对象的属性到另外个对象
class Stu:
    name="JohnShen"
    score=90
if __name__ == '__main__':
    s1=Stu()
    s2=Stu()
    s1.score=100
    s2.__dict__.update(s1.__dict__) #s2从s1里更新属性
    print("更新后s1的分数:\t"+str(s1.score))
    print("更新后s2的分数:\t" + str(s2.score))
# 更新后s1的分数:	100
# 更新后s2的分数:	100


#10 获取对象的属性名
class Stu:
    id = 0;
    def __init__(self, name="JohnShen", score=80):
        self.name = name
        self.score = score
    def getInfo(self):
        return self.name+"\t"+str(self.score)

if __name__ == '__main__':
    s1=Stu()
    print( [i for i in dir(s1) if not i.startswith("__")])
# 结果:	['getInfo', 'id', 'name', 'score']


#11 遍历对象的属性及其内容
class Stu:
    id = 0;
    def __init__(self, name="JohnShen", score=80):
        self.name = name
        self.score = score
    def getInfo(self):
        return self.name+"\t"+str(self.score)

if __name__ == '__main__':
    s1=Stu()
    #print(vars(s1))
    for i in vars(s1):
        #print(str(i)+"\t"+str(vars(s1)[i]))
        print("{0}:{1}".format(i,vars(s1)[i]))
# name:JohnShen
# score:80 


#12 创建对象后再新增属性并赋值
class Stu:
    id = 0;
    def __init__(self, name="JohnShen", score=80):
        self.name = name
        self.score = score
    def getInfo(self):
        return self.name+"\t"+str(self.score)
if __name__ == '__main__':
    s1=Stu()
    print(s1.name+"\t"+str(s1.score))
    s1.__setattr__("edu","本科")
    setattr(s1,"addr","HF")
    print(s1.name + "\t" + str(s1.score)+"\t"+str(s1.addr)+"\t"+str(s1.edu))
    delattr(s1,"addr")
    print(s1.name + "\t" + str(s1.score) + "\t"  + str(s1.edu))
    # JohnShen	80
    # JohnShen	80	HF	本科
    # JohnShen	80	本科

#13 对象实例作为参数

# class Emp 有个name,id属性以及学历对象列表
# class Edu, 有个name属性
class Stu:
    def __init__(self,id,name):
        self.id = id
        self.name = name
        self.edu=[]
    def addEdu(self,edu):
        self.edu.append(edu)
class Edu:
    def __init__(self,name):
        self.name = name
if __name__ == '__main__':
    s = Stu(10,'John')
    for i in ('本科、研究生、博士').split("、"):
        e = Edu(i)
        s.edu.append(e)
    for j in s.edu:
        print(j.name)
#结果
#本科
#研究生
#博士

#14 自定义类实例(对象)参数的名字
                                   
class Stu:                            
    def __init__(this,id,name):       
        this.id = id                  
        this.name = name              
if __name__ == '__main__':            
    s = Stu(10,'John')                
    print(s.id,s.name)                
# 结果                                  
# 10 John                             


#15 使用类静态变量
class Stu:
    addr="hefei"
    def __init__(this,id,name):
        this.id = id
        this.name = name
if __name__ == '__main__':
    s = Stu(10,'John')
    print(s.id,s.name,Stu.addr)
    s.addr="nanjing"
    print(s.id,s.name,Stu.addr,s.addr)

# 结果
# 10 John


#16 方法里定义类并实例化
def getExperience(des,edu = None):
    class Edu:
        def __init__(self,name):
            self.name =name

    if not edu:
        e = Edu("本科")
    return des+e.name

if __name__ == '__main__':
    #print(getExperience("John",None))
    print(getExperience("John"))
#结果:John本科    


#17 计算两点之间的距离
import math
class Point:
    def __init__(self,x=0,y=0):
        self.x=x
        self.y=y
    def distance(self,p1):
        return round(math.sqrt((self.x-p1.x)**2+(self.y-p1.y)**2),2)

if __name__ == '__main__':
    p1 = Point(3,4)
    p2 = Point(6,8)
    print(p1.distance(p2))
#结果: 5.0


# 18 内置contains方法重载
class Evennums:
    def __contains__(self, item):
        if (not isinstance(item,int) or item%2):
            return False
        else:
            return True
e = Evennums()
print(e.__contains__(4))
#结果:True



# 19 重构对象基本信息方法repr 
class Stu:
    def __init__(self,id,name):
        self.id=id
        self.name=name
    def __repr__(self): #如果不重新则,默认是打印对象的内存地址
        return "您的序号是:{0},姓名是:{1}".format(self.id,self.name)
if __name__ == '__main__':
    s = Stu(1,'JohnShen')
    print(s) 
#结果:您的序号是:1,姓名是:JohnShen

 
#20 继承与重载内置类实例
class ContactList(list):
    def match(self,name):
        matchResult=[]
        for contact in self:
            if name in contact.name:
                matchResult.append(contact)
        return matchResult

class Contact:
    allContacts=ContactList()
    def __init__(self,name,email):
        self.name = name
        self.email = email
        Contact.allContacts.append(self)

class Supplier(Contact):
    def order(self,order):
        print(f"'{order}' order to '{self.name}'")

c1 = Contact("shen","Shen@hotmail.com")
c2 = Contact("shenLiang","liang@163.com")
c3 = Contact("Liang","liang@163.com")
s = Supplier("Mike","mike@qq.com")
print([i.name for i in Contact.allContacts.match("shen")])
s.order("I need water")
#结果
#['shen', 'shenLiang']
#'I need water' order to 'mike'


#20 构造方法重写及调研父类构造方法
class Contact:
    def __init__(self,id,name,email):
        self.id = id
        self.name = name
        self.email = email
#法1
class Student(Contact):
    def __init__(self,id,name,email,stuid,school):
        self.id = id
        self.name = name
        self.email = email
        self.stuid = stuid
        self.school = school
#法2
class Student(Contact):
    def __init__(self,id,name,email,stuid,school):
        #super(Student, self).__init__(id,name,email)
        super().__init__(id,name,email)
        self.stuid = stuid
        self.school = school
s = Student(1,"John","John@163.com",1000,"NanJing university")
print("名称:{0}\t学校:{1}".format(s.name,s.school))
#结果:名称:John	学校:NanJing university

 #21 多继承的钻石问题
class BaseClass:
    basenum=0
    def call_me(self):
        print("call me at BaseClass")
        self.basenum+=1
class LeftClass(BaseClass):
    leftnum=0
    def call_me(self):
        BaseClass.call_me(self)
        print("call me at LeftClass")
        self.leftnum+=1
class RightClass(BaseClass):
    rightnum=0
    def call_me(self):
        BaseClass.call_me(self)
        print("call me at RightClass")
        self.rightnum+=1
class SubClass(LeftClass,RightClass):
    subnum =0
    def call_me(self):
        LeftClass.call_me(self)
        RightClass.call_me(self)
        print("call me at SubClass")
        self.subnum+=1
s = SubClass()
s.call_me()
print(s.basenum,s.leftnum,s.rightnum,s.subnum)

#结果:
# call me at BaseClass
# call me at LeftClass
# call me at BaseClass
# call me at RightClass
# call me at SubClass
# 2 1 1 1

#用supper方式调用
class BaseClass:
    basenum=0
    def call_me(self):
        print("call me at BaseClass")
        self.basenum+=1
class LeftClass(BaseClass):
    leftnum=0
    def call_me(self):
        super().call_me()
        print("call me at LeftClass")
        self.leftnum+=1
class RightClass(BaseClass):
    rightnum=0
    def call_me(self):
        #BaseClass.call_me(self)
        super().call_me()
        print("call me at RightClass")
        self.rightnum+=1
class SubClass(LeftClass,RightClass):
    subnum =0
    def call_me(self):
        #LeftClass.call_me(self)
        #RightClass.call_me(self)
        super().call_me()
        print("call me at SubClass")
        self.subnum+=1
s = SubClass()
s.call_me()  # 这里调用的是next方法,因为LeftClass的"父类"是RightClass,所以LeftClass->RightClass->BaseClass
print(s.basenum,s.leftnum,s.rightnum,s.subnum)
#结果:
# call me at BaseClass
# call me at RightClass
# call me at LeftClass
# call me at SubClass
# 1 1 1 1

 #22 多继承的钻石问题
# MRO及对象继承关系分析示例
class A:
    def callme(self):
        print("call me at A")
class B(A):
    def callme(self):
        super().callme()
        print("call me at B")
class C(B):
    def callme(self):
        super().callme()
        print("call me at C")
class D(B):
    def callme(self):
        super().callme()
        print("call me at D")
class E(C):
    def callme(self):
        super().callme()
        print("call me at E")
class F(D):
    def callme(self):
        super().callme()
        print("call me at F")
class G(E,F):
    def callme(self):
        super().callme()
        print("call me at G")
g = G()
g.callme()
print(G.__mro__)
# MRO顺序,首先G继承自E,E继承自C,C继承自B,这时B又有分支(即D继承自B,F继承自D,所以C"继承"自F),B继承自A,所有顺序为
# G -> E -> C -> F -> D -> B -> A -> Object,画出树形图更直观些
#
# 结果:
# call me at A
# call me at B
# call me at D
# call me at F
# call me at C
# call me at E
# call me at G
# (<class '__main__.G'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
#
# Process finished with exit code 0

 #23 __init__结合*args、**keyargs多继承使用案例,当确定构造函数里的参数时用*args、**keyargs
# 这里的*args、**keyargs即指定参数是动态传递,分别按照位置和键值对
# V1 版本1
class Human(object):
    humannum=0
    def __init__(self,name):
        self.name = name
        self.humannum+=1
class Person(Human):
    personnum=0
    def __init__(self,name,gender):
        self.gender = gender
        Human.__init__(self,name)
        self.personnum+=1
class Age(Human):
    agenum=0
    def __init__(self,name,age):
        Human.__init__(self,name)
        self.age = age
        self.agenum+=1
class Student(Person,Age):
    stunum=0
    def __init__(self,name,gender,age,school):
        Person.__init__(self,name,gender)
        Age.__init__(self,name,age)
        self.school = school
        self.stunum+=1
s = Student("john","Female",26,"NanJing University")
print(s.name,s.school)
print(s.humannum,s.personnum,s.agenum,s.stunum)

# V2 版本2
class Human:
    humannum=0
    def __init__(self,name,**keyargs):
        self.name=name
        super().__init__(**keyargs)
        self.humannum+=1
class Person(Human):
    personnum=0
    def __init__(self,gender,**keyargs):
        self.gender=gender
        super().__init__(**keyargs)
        self.personnum+=1
class Age(Human):
    agenum=0
    def __init__(self,age,**kwargs):
        self.age = age
        super().__init__(**kwargs)
        self.agenum+=1
class Student(Person,Age):
    stunum=0
    def __init__(self,stuid,**kwargs):
        self.stuid = stuid
        super().__init__(**kwargs)
        self.stunum+=1

s = Student(name="Liang",gender="Male",age=30,stuid=10000)
print(s.name,s.stuid)
print(s.humannum,s.personnum,s.agenum,s.stunum)
print(Student.__mro__)

#结果:
#Liang 10000
#1 1 1 1
#(<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Age'>, <class '__main__.Human'>, <class 'object'>)



 #24 super()__init__结合*args的案例
class Human:
    def __init__(self,id,name,*args):
        self.id = id
        self.name = name
        #super().__init__(*args)

class Person:
    def __init__(self,age,*args):
        self.age = age
        #super().__init__(*args)
class Student(Human,Person,):
    def __init__(self,*args):
        super().__init__(*args)
        #super(P,S).__init__(age)
        #super().__init__(self,age)
s = Student("John",10,30)
print(Student.__mro__)
print(s.id,s.name,s.age)
# 结果 AttributeError: 'Student' object has no attribute 'age'
# 错误分析,因为继承顺序是 Student -> Human -> Person -> Object,而Human里并未定义调用父类的方法,所有无法读取age属性
# 解决方法,这里打开Human和Person里的#super().__init__(*args)注释即可。



#25 动态参数*args和**keyargs案例
def dynamic_args(*args,**keyargs): #位置参数(tuple)和关键字参数(dic)
    print(f'{type(args)}\t{args}')
    print(f'{type(keyargs)}\t{keyargs}')
if __name__ == '__main__':
    dynamic_args(8,9,11,name="john",addr="hefei")

    a = 100
    b = 200
    c = 400
    d = {'name':'john','addr':'hefei'}
    dynamic_args(a,b,c,**d) #注意 用**keyargs参数时变量前也得加上**,即传成**d

#结果:
# <class 'tuple'>	(8, 9, 11)
# <class 'dict'>	{'name': 'john', 'addr': 'hefei'}
# <class 'tuple'>	(100, 200, 400)
# <class 'dict'>	{'name': 'john', 'addr': 'hefei'}


 #26 动态指定对象属性并赋值
class Person():
    def __init__(self, name, gender, **kwargs):
        super().__init__() #注意继承自Object的不用**kwargs参数,否则报错TypeError: object.__init__() takes exactly one argument (the instance to initialize)
        self.name = name
        self.gender = gender
        for k, v in kwargs.items():
            setattr(self, k, v)
p = Person('Bob', 'Male', age=18, course='Python',edu="bachelor")
print (p.age,p.course)
print([ i for i in dir(p) if not i.startswith('__')])



#27 对象类的__init__只有一个参数 TypeError: object.__init__() takes exactly one argument (the instance to initialize)
class Animal:
    def __init__(self,**kwargs):
        #super().__init__(**kwargs) #因为改类继承自object,而对象类只能有1个参数,所以不能加**kwargs参数
        super().__init__()
        for k, v in kwargs.items():
            setattr(self, k, v)
a= Animal(name="Wolf")
print(a.name)


# 28 多态示例
class Animal:
    def say_who(self):
        print('我是动物')
class Cat(Animal):
    def say_who(self):
        print('我是只猫')
class Human(Animal):
    def say_who(self):
        print('我是个人')
class Fish(Animal):
    def say_who(self):
        print("我是只鸟")
def commonUse(obj):
    obj.say_who()
c = Cat()
h = Human()
f= Fish() #新增类和修改相应的调用即可
for item in(c,h):
    commonUse(item)
#for item in (c,h,f): #新增调用
    #commonUse(item)
#结果:
#我是猫咪
#我是人类

#我是只猫
#我是个人
#我是只鸟


# 29 异常捕获示例
def div(num):
    try:
        if num >100:
            raise ValueError("Too big than 100")
        elif not isinstance(num,int):
            raise TypeError("Type error")
        else:
            return (100/num)
    except ZeroDivisionError:
        return "除数不能为0"
    except TypeError:
        return "必须是数值类型"
    except ValueError:
        return "值大于100了"
    #finally:
        #return 0
print(div(500))
#结果:值大于100了


#30 Python property及装饰器法实现getter/setter
class Color:
    def __init__(self,rgb_value,name):
        self._rgb_value=rgb_value
        self._name = name
    def _set_name(self,name):
        if not name:
            raise Exception ("Invalid value")
        print(f"You are set color to {name}")
        self._name = name
    def _get_name(self):
        print("You get color {0}".format(self._name))
        return self._name
    def _del_name(self):
        print(f"You are killing color {self._name}")
        del self._name

    name = property(_get_name,_set_name,_del_name,"Color's name property")

c = Color("#000F001","Bright Red")
c.name = "Red"
c.name
print([i for i in dir(c) if not i.startswith("__")])
del c.name
print([i for i in dir(c) if not i.startswith("__")])
c.name

class Color:
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self,name):
        self._name = name
    @name.deleter
    def name(self):
        del self._name

c = Color()
c.name="Bright Red"
print(c.name)


#31 Python 用面向对象思维编写文件的解压、替换、压缩
import sys
import shutil
import zipfile
from pathlib import Path

class ZipReplace:
    def __init__(self,filename,search_string,replace_string):
        self.filename = filename
        self.search_string= search_string
        self.replace_string = replace_string
        self.temp_dir = Path(f"temp-{Path(filename).stem}")
    def zip_replace(self):
        self.unzip()
        self.replace_value()
        self.zip()
    def unzip(self):
        self.temp_dir.mkdir()
        with zipfile.ZipFile(self.filename,"r") as unzip:
            unzip.extractall(self.temp_dir)
    def replace_value(self):
        for filename in self.temp_dir.iterdir():
            with filename.open("r") as f:
                contents= f.read()
            contents = contents.replace(self.search_string,self.replace_string)
            with filename.open("w") as f:
                f.write(contents)
    def zip(self):
        with zipfile.ZipFile(self.filename,"w") as unzip:
            for filename in self.temp_dir.iterdir():
                unzip.write(filename,filename.name)
        shutil.rmtree(self.temp_dir)
if __name__ == '__main__':
    ZipReplace(*sys.argv[1:4]).zip_replace()
#V2 将解压和压缩环节定义为一个压缩类,文件处理(字符串替换)定义为一个类,文件处理继承自压缩类
#处理文本(字符串替换),处理图像(文件缩放),此时需要一个处理类,但是对文件的解压和压缩是通用步骤,所以可以定义在父类里

import sys
import zipfile
import shutil
from pathlib import Path
class ZipProcessor:
    def __init__(self,zipname):
        self.zipname = zipname
        self.temp_dir = Path(f"temp-{Path(zipname).stem}")
    def process_zip(self):
        self.unzip()
        self.process_files()
        self.zip()
    def unzip(self):
        self.temp_dir.mkdir()
        with zipfile.ZipFile(self.zipname,'r') as unzip:
            unzip.extractall(self.temp_dir)
    def zip(self):
        with zipfile.ZipFile(self.zipname,'w') as zip:
            for filename in self.temp_dir.iterdir():
                zip.write(filename,filename.name)
        shutil.rmtree(self.temp_dir)
class ZipReplace(ZipProcessor):
    def __init__(self,filename,search_string,replace_string):
        super().__init__(filename)  #引用父类属性,需显式调用
        self.search_string = search_string
        self.replace_string = replace_string
    def process_files(self):
        for filename in self.temp_dir.iterdir():
            with filename.open("r") as f:
                contents= f.read()
            contents = contents.replace(self.search_string,self.replace_string)
            with filename.open("w") as f:
                f.write(contents)
if __name__ == '__main__':
    ZipReplace(*sys.argv[1:4]).process_zip()




#32 Python里函数的参数传递示例
def default_arg(x,y="y1",a,b="b1"): #SyntaxError: non-default argument follows default argument
    print(x,y,a,b)
default_arg("x1","y2")

def default_args(x,a,y="y1",b="b1"):
    print(x,a,y,b)
default_args("x1","y2") # x和a是必选参数
def default_args2(x,y="y1",*,a,b="b1"):
    print(x,a,y,b)
#default_args2("x1") # TypeError: default_args2() missing 1 required keyword-only argument: 'a'
default_args2("x1",a="y2")

number = 5
def funky_function(number=number):
    print(number)
number=6
funky_function(8)
funky_function() #函数定义了参数,但没传递时,如果函数里用到了该变量,则值为调用时的参数的值。
print(number)