返回总目录页

Python面向对象编程

1.面向对象基本格式

 

# ###### 定义类 ###### 
class 类名:
   def 方法名(self,name):
       print(name)
       return 123
   def 方法名(self,name):
       print(name)
       return 123
   def 方法名(self,name):
       print(name)
       return 123
class 类名:    
def 函数(self):
函数体
#
# ###### 调用类中的方法 ######
# 1.创建该类的对象
obj = 类名()
# 2.通过对象调用方法
result = obj.方法名('alex')
print(result)

应用场景:遇到很多函数,需要给函数进行归类和划分。 【封装】

练习题:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Db:
   def db_read(self):
       pass

   def db_write(self):
       pass

   def db_delete(self):
       pass

   def db_update(self):
       pass

class File:
   def file_read(self):
       pass

   def file_write(self):
       pass

   def file_delete(self):
       pass

   def file_update(self):
       pass

class Redis:
   def redis_read(self):
       pass

   def redis_write(self):
       pass

   def redis_delete(self):
       pass

   def redis_update(self):
       pass
几个使用:代码从上到下执行

1)  print('你好') def func():  pass func() -------------结果: 你好

2) class Foo:  X = 1  def func(self):  pass Foo.X ---------结果:

3) class Foo:  print('你好') #类里面第一层的成员在创建类的时候会执行  def func(self):  pass ------------结果: 你好

4) class Foo:  print('你')  x = 1  def func(sef):  pass  class Meta: #类里面第一层的成员,比如方法func和类Meta都相当于类变量一样,类可以当做一个变量。类里面还可以定义类,创建这个类的时候它的第一层也会执行。  print('好')  y = 123  def show(self):  pass  -------------结果:  

4)直接传参进去可以调用

class mcw():
  def func(self,name):
      self.name=name
      print(self.name)
obj=mcw()
obj.func("小马过河")
-----------结果:
小马过河

 

对象调用错误:

1)obj还是类。类.方法()会报错

class mcw():
  def func(self):
      print("mcw")
obj=mcw
obj.func()
----------结果:
TypeError: func() missing 1 required positional argument: 'self'

2.对象的作用

存储一些值,以后方便自己使用。

class File:
   def read(self):
       with open(self.xxxxx, mode='r', encoding='utf-8') as f:
           data = f.read()
       return data

   def write(self, content):
       with open(self.xxxxx, mode='a', encoding='utf-8') as f:
           f.write(content)

# # 实例化了一个File类的对象
obj1 = File()
# # 在对象中写了一个xxxxx = 'test.log'
obj1.xxxxx = "test.log"
# # 通过对象调用类中的read方法,read方法中的self就是obj。
# # obj1.read()
obj1.write('alex')


# 实例化了一个File类的对象
obj2 = File()
# 在对象中写了一个xxxxx = 'test.log'
obj2.xxxxx = "info.txt"
# 通过对象调用类中的read方法,read方法中的self就是obj。
# obj2.read()
obj2.write('alex')
class Person:
   def show(self):
       temp = "我是%s,年龄:%s,性别:%s " %(self.name,self.age,self.gender,)
       print(temp)
       

p1 = Person()
p1.name = '李邵奇'
p1.age = 19
p1.gender = '男'
p1.show()

p2 = Person()
p2.name = '利奇航'
p2.age = 19
p2.gender = '男'
p2.show()
class Person:
   def __init__(self,n,a,g): # 初始化方法(构造方法),给对象的内部做初始化。
       self.name = n
       self.age = a
       self.gender = g

   def show(self):
       temp = "我是%s,年龄:%s,性别:%s " % (self.name, self.age, self.gender,)
       print(temp)

# 类() 实例化对象,自动执行此类中的 __init__方法。
p1 = Person('李兆琪',19,'男')
p1.show()

p2 = Person('利奇航',19,'男')
p2.show()

总结:将数据封装到对象,方便使用。

总结

"""
如果写代码时,函数比较多比较乱。
1. 可以将函数归类并放到同一个类中。
2. 函数如果有一个反复使用的公共值,则可以放到对象中。
"""

class File:
   def __init__(self,path):
       self.file_path = path
       
   def read(self):
       print(self.file_path)
   
   def write(self,content):
       print(self.file_path)
   
   def delete(self):
       print(self.file_path)
   
   def update(self):
       print(self.file_path)
   
p1 = File('log.txt')
p1.read()

p2 = File('xxxxxx.txt')
p2.read()
# 1. 循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。
# ########## 以前的写法
USER_LIST = []
while True:
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    email = input('请输入邮箱:')
    temp = {'username':user,'password':pwd,'email':email}
    USER_LIST.append(temp)
for item in USER_LIST:
    temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],)
    print(temp)
    
# ########## 面向对象写法

class Person:
    def __init__(self,user,pwd,email):
        self.username = user
        self.password = pwd
        self.email = email
	
USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    email = input('请输入邮箱:')
    p = Person(user,pwd,email)
    USER_LIST.append(p)

for item in USER_LIST:
    temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
    print(temp)

# ########## 面向对象写法

class Person:
    def __init__(self,user,pwd,email):
        self.username = user
        self.password = pwd
        self.email = email
        
	def info(self):
        return "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
    
USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    email = input('请输入邮箱:')
    p = Person(user,pwd,email)
    USER_LIST.append(p)

for item in USER_LIST:
    msg = item.info()
    print(msg)

3.游戏开发

class Police:
	def __init__(self,name) 
		self.name = name 
         self.hp = 10000
    
    def tax(self):
        msg = "%s收了个税。" %(self.name,)
        print(msg)
	
    def fight(self):
        msg = "%s去战了个斗。" %(self.name,)

lsq = Police('李邵奇') 
zzh = Police('渣渣会')
tyg = Police('堂有光')


class Bandit:
    def __init__(self,nickname) 
		self.nickname = nickname 
		self.hp = 1000
	
    def murder(self,name):
        msg = "%s去谋杀了%s" %(self.nickname, name,)
        
        
lcj = Bandit('二蛋')
lp = Bandit('二狗')
zsd = Bandit('狗蛋')

# 1. 二狗去谋杀渣渣会,二狗生命值-100; 渣渣会生命值减5000
lp.murder(zzh.name)
lp.hp = lp.hp - 100
zzh.hp = zzh.hp - 5000
# ... 
class Police:
	def __init__(self,name) 
		self.name = name 
         self.hp = 10000
    
    def dao(self,other):
        msg = "%s个了%s一刀。" %(self.name,other.nickname)
        self.hp = self.hp - 10
        other.hp = other.hp - 50
        print(msg)
	
    def qiang(self):
        msg = "%s去战了个斗。" %(self.name,)
        
	def quan(self,other):
        msg = "%s个了%s一全。" %(self.name,other.nickname)
        self.hp = self.hp - 2
        other.hp = other.hp - 10
        print(msg)
        
        
class Bandit:
    def __init__(self,nickname) 
		self.nickname = nickname 
		self.hp = 1000
	
    def qiang(self,other):
        msg = "%s个了%s一全。" %(self.nickname,other.name)
        self.hp -= 20
        other.hp -= 500
    
	
lcj = Bandit('二蛋')


lsq = Police('李邵奇')
lsq.dao(lcj)
lsq.quan(lcj)
lcj.qiang(lsq)

4.继承

# 父类(基类)
class Base:
    def f1(self):
        pass
# 子类(派生类)
class Foo(Base):
    def f2(self):
        pass

# 创建了一个字类的对象
obj = Foo()
# 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。
obj.f2()
obj.f1()

# 创建了一个父类的对象
obj = Base()
obj.f1()

问题:什么时候才能用到继承?多个类中如果有公共的方法,可以放到基类中避免重复编写。

class Base:
    def f1(self):
        pass
    
class Foo(Base):
    def f2(self):
        pass
    
class Bar(Base):
    def f3(self):
        pass

obj1 = Foo()

obj2 = Bar()

继承关系中的查找方法的顺序:

# 示例一
class Base:
    def f1(self):
        print('base.f1')
        
class Foo(Base):
    def f2(self):
        print('foo.f2')
        
obj = Foo()
obj.f1()
obj.f2()

# 示例二
class Base:
    def f1(self):
        print('base.f1')
        
class Foo(Base):
    def f2(self):
        self.f1()
        print('foo.f2')
        
obj = Foo()
obj.f2()

# 示例三
class Base:
    def f1(self):
        print('base.f1')
        
class Foo(Base):
    def f2(self):
        self.f1()
        print('foo.f2')
	def f1(self):
        print('foo.f1')
        
obj = Foo()
obj.f2()

# 示例四
class Base:
    def f1(self):
        self.f2()
        print('base.f1')
	def f2(self):
        print('base.f2')
class Foo(Base):
    def f2(self):
        print('foo.f2')
        
obj = Foo()
obj.f1()

# 示例五
class TCPServer:
    pass
class ThreadingMixIn:
    pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    pass

# 示例六
class BaseServer:
    def serve_forever(self, poll_interval=0.5):
        self._handle_request_noblock()
	def _handle_request_noblock(self):
        self.process_request(request, client_address)
        
	def process_request(self, request, client_address):
        pass
    
class TCPServer(BaseServer):
    pass

class ThreadingMixIn:
    def process_request(self, request, client_address):
        pass
    
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    pass

obj = ThreadingTCPServer()
obj.serve_forever()

注意事项:

  • self 到底是谁?

  • self 是哪个类创建的,就从此类开始找,自己没有就找父类。

 

5.多态(多种形态/多种类型)鸭子模型

# Python
def func(arg):
    v = arg[-1] # arg.append(9)
    print(v)

# java
def func(str arg):
    v = arg[-1]
    print(v)

面试题:什么是鸭子模型。

对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法)。
这就是鸭子模型,类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们要想的类型)

 

总结

  1. 面向对象的三大特性:封装/继承/多态

    • 封装

      class File:
          def read(self):
              pass
          def write(self):
              pass
      
      class Person:
          def __init__(sef,name,age):
              self.name = name
              self.age = age
      p = Person('alex',19)
      
    • 继承

      class Base:
          pass
      class Foo(Base):
          pass
      
      • 多继承

      • self到底是谁?

      • self是由于那个类创建,则找方法时候就从他开始找。

    • 多态

      def func(arg): # 多种类型,很多事物
          arg.send() # 必须具有send方法,呱呱叫
      
  2. 格式和关键词

    class 类:
        def __init__(self,x):
            self.x = x 
            
        def 方法(self,name):
            print(self.x, name)
            
    # 实例化一个类的对象
    v1 = 类(666)
    v2.方法('alex')
    

    三个词:

    • 对象

    • 方法

  3. 什么时候用面向对象?

    • 函数(业务功能)比较多,可以使用面向对象来进行归类。

    • 想要做数据封装(创建字典存储数据时,面向对象)。

    • 游戏示例:创建一些角色并且根据角色需要再创建人物。

    •  

 

 类的成员

1)

class Request:
  def __init__(self,a1,a2):
      self.a1 = a1
      self.a2 = a2
def func(arg):
  print(arg.a1,arg.a2)
obj = Request(1,2) #实例化一个类,把对象的数据封装到类,以供下次使用
func(obj) #封装数据到对象,将对象以函数的参数形式传进函数,在函数中可以调用类变量
--------------结果:
1 2

2)类变量

class Foo:
  city = '北京' #在类的内存空间里面创建变量。
  def __init__(self, name): #方法是Foo类中成员。包括init方法
      self.name = name
  def func(self): #
      pass
obj1 = Foo('小马过河') #类加括号创建对象,开辟内存,并且与类的地址有联系,执行init,初始化之后,在对象内存中赋值了。
obj2 = Foo('小郭吹雪')  #对象和类的内存是两个
print(obj1.name)   #外部访问类中init里的变量 :类.类变量(注意:类.init的变量是错的) 对象.变量(类变量,init里的变量都可以)
print(obj2.name)
print(Foo.city) #按理说对象取类中变量应该是类.类变量。python比较灵活,可以直接对象.类变量(对象内存中没找到类变量,去类空间中找到。)
print(obj1.city) #创建一个对象之后,创建对象内存空间。如果取一个变量,没有的话可以去类中定义的变量去取(类的内存空间中定义的变量)。java不可以这样
print(obj2.city) #所以Python访问类变量的方法有两种。假如对象里面有自己的同名变量,那么对象.变量先用自己的,没有才去类的内存空间中找这个变量
--------------结果:
小马过河
小郭吹雪
北京
北京
北京
#类变量。在类的内存空间里面创建变量。创建一个对象之后,如果取一个变量,没有的话可以去类中定义的变量去取。java不可以这样。按理说对象取类中变量应该是类.类变量。python比较灵活,可以直接对象.类变量。所以Python访问类变量的方法有两种。假如对象里面有自己的同名变量,那么对象.变量先用自己的,没有才去类的内存空间中找这个变量

3)

class Base:
  x = 1
obj = Base() #类的空间和对象的空间不是同一个
print(obj.x) # obj使用变量x先去obj对象中找,没有再去类中找。
obj.y = 123 # 在obj对象中添加了一个y=123的变量。
print(obj.y)
obj.x = 123 #在对象obj里定义一个变量x=123,
print(obj.x) #obj里面有x,123,
print(Base.x) #Base里面有x,1


4)
class Parent:
  x = 1
class Child1(Parent):
  pass
class Child2(Parent):
  pass
print(Parent.x, Child1.x, Child2.x) # 1 1 1
#P里的x是1;C1找x,没有找到就去基类P中去找x=1;C2找x,没有找到就去基类P中去找,
Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1
#P里的x是1;C1找x,x已经定义,x = 2;C2找x,没有找到就去基类P中去找,x=1,
Child2.x = 3
print(Parent.x, Child1.x, Child2.x) # 1 2 3
#P里的x是1;C1找x,x已经定义,x = 2;C2找x,x已经定义,x = 3

总结:找变量优先找自己,自己没有找 类 或 基类;修改或赋值只能在自己的内部设置。

1.3 方法(绑定方法/普通方法)

  • 定义:至少有一个self参数

  • 执行:先创建对象,由对象.方法()。

class Foo:
  def func(self, a, b):
      print(a, b)
obj = Foo()
obj.func(1, 2)
# ###########################
class Foo:
  def __init__(self):
      self.name = 123 #绑定方法: self代表对象
  def func(self, a, b):#对象成员: 实例变量(即对象的变量name=123),obj创建后初始化类(执行init时在obj中创建)时被赋予的变量值 
      print(self.name, a, b)
obj = Foo() #实例化一个类,类.方法,传参1,2
obj.func(1, 2)
---------------结果:
1 2
123 1 2

4 静态方法

  • 定义:

    • @staticmethod装饰器

    • 参数无限制

  • 执行:

    • 类.静态方法名 ()

    • 对象.静态方法() (不推荐)

class Foo:
  def __init__(self):
      self.name = 123
  def func(self, a, b):
      print(self.name, a, b)
  @staticmethod #静态方法.方法前面加@静态方法 它是python内置装饰器
  def f1(): #静态方法参数无限制,如果有形参也是需要传参的,否则报错。
      print(123)
obj = Foo()
obj.func(1, 2)
Foo.f1() #静态方法执行直接类.方法()。
obj.f1() # 静态方法执行也可以:对象.静态方法 ,但是容易混淆,没有意义。java不可以使用对象调用静态方法
-------------结果:
123 1 2
123
123

#使用场景:封装数据用绑定方法,不用封装数据就用静态方法。如果只调用静态方法那么就不用创建对象了。类.方法

 

面试题: 在对象中赋值 对象.变量=值 在类中赋值 类.变量=值

继承,子类没有的类变量,可以去父类里面中。子类中赋值同名变量后,不会修改父类中的变量,而是在自己的空间里创建一个,调用的时候去自己空间去找,不再去父类中去找。别人的可以读到,但是不可以修改 p8规范:类前空两行 方法间空一行

 

1.5 类方法

  • 定义:

    • @classmethod装饰器

    • 至少有cls参数,当前类。

  • 执行:

    • 类.类方法()

    • 对象.类方法() (不推荐)

class Foo:
  def __init__(self):
      self.name = 123
  def func(self, a, b):
      print(self.name, a, b)
  @staticmethod #静态方法.方法前面加@静态方法 它是python内置装饰器
  def f1():
      print(123)
  @classmethod #定义方法:方法前面加一个@类方法,至少一个参数cls,cls代表当前的类。
  def f2(cls,a,b):
      print('cls是当前类',cls)
      print(a,b)
obj = Foo()
obj.func(1, 2)
Foo.f1() #静态方法执行直接类.方法()。
Foo.f2(1,2)#类方法的执行:类名.方法(类方法的执行也可以是:对象.方法调用,但是不建议使用)
----------结果:
123 1 2
123
cls是当前类 <class '__main__.Foo'>
1 2

 

  • # 问题: @classmethod和@staticmethod的区别?
    """
    一个是类方法一个静态方法。
    定义:
    类方法:用@classmethod做装饰器且至少有一个cls参数。
    静态方法:用staticmethod做装饰器且参数无限制。
    调用:
    类.方法直接调用。
    对象.方法也可以调用。
  • 使用场景:在类中用到当前的类名的时候使用类方法。 (类方法用静态方法也能实现,传递一个值,类名也可以实现)

 

1.6 属性

  • 定义:

    • @property装饰器

    • 只有一个self参数

  • 执行:

    • 对象.方法 不用加括号。

class Foo:  
  @property #@property 在除了self没有其它参数的方法前面加,由方法变成属性
  def func(self): #属性:(方法变异过来的)
      print(123)
      return 666
obj = Foo()
result = obj.func #属性执行的时候就不用加括号了(其它方法执行的时候都是加括号才执行的,不加括号代表的是方法)
print(result)
-------------结果:
123
666
  • 应用场景:分页功能,记录索引位置 (就是免去不需要传参的方法的括号)

# 属性的应用
class Page:
  def __init__(self, total_count, current_page, per_page_count=10): #给每页显示的数量给个默认值10个
      self.total_count = total_count #将总页数,每页显示的数,当前第几页以变量传参进来
      self.per_page_count = per_page_count
      self.current_page = current_page
  @property #@property 在除了self没有其它参数的方法前面加,由方法变成属性
  def start_index(self): #这样属性执行的时候就不用加括号了
      return (self.current_page - 1) * self.per_page_count
  @property #@property 在除了self没有其它参数的方法前面加,由方法变成属性
  def end_index(self):
      return self.current_page * self.per_page_count
USER_LIST = []     #创建空列表,并加加入321个列表元素,作为分页展示的条目
for i in range(321):
  USER_LIST.append('小马过河-%s' % (i,))
# 请实现分页展示:
current_page = int(input('请输入要查看的页码:')) #接收参数,当前页是用户输入要查看的第几页
p = Page(321, current_page) #实例化一个对象,将用户输入的第几页的数据封装起来,以供后面使用
data_list = USER_LIST[p.start_index:p.end_index] #对象.start_index是对象执行类的属性,也代表属性的返回值,返回值是用户输入的页数-1再乘以每页显示的数,表示开始的索引
for item in data_list: #获取到第几页的元素列表,逐个打印
  print(item)
-------------------结果:
请输入要查看的页码:1
小马过河-0
小马过河-1
小马过河-2
小马过河-3
小马过河-4
小马过河-5
小马过河-6
小马过河-7
小马过河-8
小马过河-9

2.成员修饰符

  • 公有,所有地方都能访问到。

  • 私有,只有自己可以访问到。

1)
class Foo:
  def __init__(self, name):
      self.__name = name #在init中定义变量是公有的,内部访问self.变量,外部访问对象.变量,先用对象自己空间内的,没有才去类的内存空间中找这个变量
  def func(self): #变量变成私有的:__变量 。
      print(self.__name) #变成私有的后,内部可以访问self.__变量,外部无法访问,不可以对象.__变量会报错
obj = Foo('小马过河')
#print(obj.__name) #类外部和它的子类都不能访问,访问报错AttributeError: 'Foo' object has no attribute '__name'
obj.func() #外部访问类中init里的变量 :类.变量 对象.变量
-----------结果:
小马过河

2)同过访问类中别的函数或变量等来访问类中的私有变量(有什么使用场景呢)
class Foo:
  __x = 1 #公有变量变成私有变量后(这里的是个类变量),只能这个类中使用这个变量,
  @staticmethod
  def func(): #如果想在类这个类之外使用这个变量,那么可以在类中定义一个方法,方法里可以使用这个变量,在类外部通过使用这个方法而使用这个变量
      print(Foo.__x) #这个方法有点像走后门用的
# print(Foo.__x) #类外部和它的子类都不能访问,访问报错 #变成私有之后,子类也不可以访问。(只能自己知道,其它类都不可以知道的)
Foo.func()
------------结果:
1

3)同过访问类中别的函数或变量等来访问类中的私有函数

class Foo:
  def __fun(self): #变成私有之后,子类也不可以访问。(只能自己知道,其它类都不可以知道的)
      print('msg')
  def show(self):  
      self.__fun() #外部调用类中私有方法,可以调用在这个类中调用这个私有方法的公有方法
obj = Foo()
# obj.__fun()#类外部和它的子类都不能访问,访问报错
obj.show()
-------------结果:
msg
  • 类外部强制访问私有成员方法:对象._类名私有对象变量。例如(obj. _ Foo __x)(对象. _类名 _ _变量)

# 强制访问私有成员
class Foo:
  def __init__(self,name):
      self.__x = name
obj = Foo('小马过河')
print(obj._Foo__x) # 强制访问私有实例变量
---------------结果:
小马过河

 

3.补充用法

1)将类添加进列表,循环类加括号变对象(有参的需要传参)
class Foo:
  def __init__(self, num): #定义只有init接收变量的类
      self.num = num
cls_list = []
for i in range(5):
  cls_list.append(Foo) #将同一个类名多次追加到列表
for i in range(len(cls_list)):
  obj = cls_list[i](i) #用列表中的每个类创建对象并传参。cls_list[i]是索引为i的类,cls_list[i](i)第二个i是创建对象并传参为i
  print(obj.num) #循环打印对象中封装的变量num
-----------结果:
0
1
2
3
4

2)类可以取别名,用其它变量代指类
class Foo:
  def __init__(self, num):
      self.num = num
B = Foo
obj = B('小马过河')
print(obj.num)
-----------结果:
小马过河

3)在类外部,实例化对象并将对象的方法放到列表字典等,循环取值加括号执行(什么场景适合用呢)
class Foo:
  def f1(self):
      print('f1')
  def f2(self):
      print('f2')
obj = Foo()
v = [ obj.f1,obj.f2 ]
for item in v:
  item()
-------------结果:
f1
f2

4)类中定义方法c,用来批量执行类中的方法a、b。使用这个类的时候外部只需创建对象并执行

class Account:   
  def login(self):
      pass
  def register(self):
      pass
  def run(self):
      info = {'1':self.register, '2':self.login }  
      choice = input('请选择:')  
      if info.get(choice):
      method()
if __name__=="__main__"
obj=Account()
obj.run

#在方法中,将对象的方法放到列表字典等(在类中,实现方法调用方法。实例化的每个对象执行一个方法时,也能调用其它方法。就是对象执行类中的运行其它方法的方法),循环取值加括号执行 ,然后外部实例化 ,....登录的run就是利用这个原理

类方法都可以当变量

5)新式类和经典类

class Foo:
  pass
class Foo(object):
  pass
# 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。
# 如果在python2中这样定义,则称其为:经典类 #影响的是继承顺序
class Foo:
  pass
# 如果在python2中这样定义,则称其为:新式类
class Foo(object):
  pass
class Base(object):
  pass
class Bar(Base):
  pass
6)将其它类的对象作为参数传进另一个类中 #对象和对象之间嵌套,复制一下,(联表查询似的)
class School(object):
  def __init__(self, title, addr):
      self.title = title
      self.address = addr
class ClassRoom(object):
  def __init__(self, name, school_object):
      self.name = name
      self.school = school_object
s1 = School('校区一', '北京')
s2 = School('校区二', '保定')
c1 = ClassRoom('工商管理1班', s1) #对象和对象之间嵌套
print(c1.name,c1.school.title,c1.school.address)
-----------------结果:
工商管理1班 校区一 北京

 

 

类成员:类变量 ,绑定方法,静态方法,类方法 (对象可以调用所有方法,#?类也可以调用所有方法吧) 对象成员:实例变量

===========小补充 数据类型之间可以嵌套,数据类型是类,那么类可以嵌套?某个数据类型的元素是另一个数据类型,那么某个类中的元素可以是另一个类?

#思考:什么时候用静态 类方法 ,什么时候用私有成员?

1、学生一个类,课程一个类。班级一个类。数据封装

 

 

 

类的嵌套特殊成员

##

  • 嵌套

  • 特殊方法:__init__

  • type/isinstance/issubclass/super

  • 异常处理

  1. 谈谈你了解的面向对象? 从三个特性说起

  2. 类和对象是什么关系?对象是类的一个实例。

    class Foo:
    def __init__(self,name):
           self.name = name
    def run(self):
           pass  
       
    obj1 = Foo('ale')
    obj2 = Foo('eric')
  3. self是什么?

    # self就是一个形式参数,对象调用方法时,python内部会将该对象传给这个参数。
    class Foo:
    def run(self,num):
           pass
    obj = Foo()
    obj.run(5)
  4. 类成员 & 对象成员 以及他们之间的关系。

    class Foo:
       name = 'alex'
       def run(self):
    pass
    obj = Foo()
  5. 类/方法/对象 都可以当作变量或嵌套到其他类型中。

    class Foo:
       def run(self):
           pass
    v = [Foo,Foo]   #列表里面放多个同一个类
    v = [Foo(),Foo()]# 列表里面可以放多个类+(),即放多个类的实例
    obj = Foo()
    v = [obj.run,obj.run,obj.run] #实例化一个对象,列表里面可以放多个对象的方法,这里不加括号执行
    #多个同一个类,多个类的实例,多个对象的方法也可以放到别的数据类型的吧,比如字典。
    #思考使用场景:当多次要使用同一个类的时候,可以构造一个类的列表;当多次要使用一个类的多个对象的时候,那么可以构造成列表;当多次要使用某个对象的同一个方法的时候,也可以构造成列表。当然不用嵌套在列表里面也一样可以实现功能的。


    class School(object):
       def __init__(self, title):
           self.title = title
    class Course(object):
       def __init__(self, name, school_object):
           self.name = name
           self.school = school_object
    class Classes(object):
       def __init__(self, cname, course_object):
           self.cname = cname
           self.course = course_object
    s1 = School('北京')    #School的一个对象,.title是北京
    c1 = Course('Python',s1) #Course的一个对象,.name是Python,.school是s1对象,内封装s1的变量title北京。想使用北京,可以print(c1.school.title)
    c2 = Course('Go',s1) ##Course的第二个对象,.name是go,.school是s1对象,内封装s1的变量title北京。想使用北京,可以print(c2.school.title)
    cl1 = Classes('全栈1期',c1)#Classes的一个对象,cname是全栈1期,c1是对象。cl1中封装了Course和School的两个对象的数据。可以进行调用
    print(cl1.cname,cl1.course.name,cl1.course.school.title)
    # ---------------结果:
    # 全栈1期 Python 北京
    #在对象cl1中调用另外两个类的对象中封装的数据。 cl1.cname是Classes中的self.cname,cl1.course是类Classes中的传参course_object即c1对象。
    #cl1.course.name是c1对象中的self.name = "Python" ,cl1.course.school是类Course的对象c1中的self.school = s1这个对象。s1有title,cl1.course.school
    # 是s1,s1有title北京,所以cl1.course.school.title是对象cl1使用到其它对象中封装的元素。这里就是类的嵌套。
    #思考:这里将北京封装到了类School的一个对象,对象可以取出学校名;传参将Python封装到了类Course的对象c1,将学校封装到了类Course的对象c1,而学校传参是对象s1,于是c1中可以
    # 取出s1中的学校名;传参将全栈1期封装到了类 Classes的对象cl1,将能取出课程名字和学校名字的对象c1传参入对象cl1中,cl1.course就代表c1对象。      

    class School(object):
       def __init__(self,title):
           self.title = title
       def rename(self,new_title):
           self.title=new_title
    class Course(object):
       def __init__(self,name,school_object):
           self.name = name
           self.school = school_object
       def reset_price(self):
               pass
    class Classes(object):
       def __init__(self,cname,course_object):
           self.cname = cname
           self.course = course_object
       def shangke(self):
           print(self.course.school.title)
    s1 = School('北京')
    c1 = Course('Python',s1)
    c2 = Course('Go',s1)
    cl1 = Classes('全栈1期',c1)

    print(cl1.shangke())
    #通过cl1执行Classes类中shangke方法,self.course是c1,self.course.school是c1.school(即s1)self.course.school.title是s1.title即北京
    #cl1.shangke()会执行方法在shangke中打印北京,cl1.shangke()对象的cl1.shangke方法的返回值,默认为None,打印了一下是None
    # ---------结果:
    # 北京
    # None

    cl1.course.school.rename("小马过河学校")
    print(cl1.course.school.title)
    --------结果:
    小马过河学校
    #想要在cl1中执行School是北京的rename方法,那么先要找到cl1有关联的School的对象。
    #先看cl1传参中有c1,c1传参中有s1,s1是School的对象,由此定位到School的对象,就可以使用里面的方法了。
    #要想参数类中嵌套其它的类的对象,就可以在这个类的init中设置一个形参,形参作为接收其它类的对象,在init中重新初始化,就可以在这个类中对另一个类的对象做操作了。

内容详细

1.嵌套

  • 函数:参数可以是任意类型。

  • 字典:对象和类都可以做字典的key和value。(少量代码实现很长的一个字典吗?可以生成嵌套字典吗?在生成键值对的那里变成生成字典,在加到字典 里,就可以用一个类生成字典嵌套字典了吧)

  • 继承的查找关系

1)类中列表追加对象
在一个类中初始化一个空列表,在这个类中再创建一个方法,用以将执行这个方法传参进来的参数加入到这个列表中,这个参数如果是其他的类,那么就实现了类的嵌套,可以将多个类追加到这个列表里面
class StarkConfig(object):
   def __init__(self,a):
       self.name=a
class AdminSite(object):
   def __init__(self):
       self.data_list = []
   def register(self, arg):
       self.data_list.append(arg)
site = AdminSite()  #创建AdminSite对象
obj = StarkConfig("小马过河")#创建StarkConfig对象
site.register(obj.name) #将对象obj里封装的name传给site变量中的register方法,将小马过河加进列表
print(site.data_list)
----------------结果:
["小马过河"]

2在一个类的init中设置一个变量初始值,创建一个方法将这个变量重新赋值为传参进来的参数。这个参数可以是一个类,这样,通过这个变量就可以对另一个类做操作了
class StarkConfig(object):
   def __init__(self,name,age):
       self.name = name
       self.age = age
class AdminSite(object):
   def __init__(self):
       self.data_list = []
       self.sk = None
   def set_sk(self,arg):
       self.sk = arg
site = AdminSite() # site是AdminSite对象,初始化 对象中的变量 data_list = [] sk = None
site.set_sk(StarkConfig)  #对对象site做操作,执行set_sk方法,将类StarkConfig传进去,给site.sk重新赋值为StarkConfig这个类。
bb=site.sk('小马过河',18) #site.sk已经代表StarkConfig这个类,传参进入
print(bb.name,bb.age) #site.sk=StarkConfig,实例化一个对象bb,打印bb中的变量name,age。
-----------------结果:
小马过河 18
3)在一个类的init中创建空字典。在类中创建一个方法,方法传入两个参数,一个是键,一个是值,在方法中将键值对添加到字典中。每次执行这个类的方法就可以不断添加键值对进这个字典。值可以为类,这样就可以在这个类中使用那些类了。
class StackConfig(object):
   pass
class Foo(object):
   pass
class Base(object):
   pass
class AdminSite(object):
   def __init__(self):
       self._register = {}
   def registry(self,key,arg):
       self._register[key] = arg
site = AdminSite()  #创建一个 AdminSite的对象
site.registry(1,StackConfig) #对实例使用registry函数,第一个参数为键,第二个参数为值,赋值给init中的空字典,
site.registry(2,StackConfig) #每次执行这个方法,都会添加键值对到init中的那个_register字典中。
site.registry(3,StackConfig) #值可以为类,这样就可以在这个对象中对那个类做操作
site.registry(4,Foo)   #值可以是多个类
site.registry(5,Base)
for k,v in site._register.items():
   print(k,v() )  #k代表键,v代表类,加括号后是对象
------------------------结果:
1 <__main__.StackConfig object at 0x021548F0>
2 <__main__.StackConfig object at 0x021548F0>
3 <__main__.StackConfig object at 0x021548F0>
4 <__main__.Foo object at 0x021548F0>
5 <__main__.Base object at 0x021548F0>


4)在一个类中创建空字典,创建一个能不断给字典赋值的方法,创建一个能使用字典的方法。字典值可以为类,这样就可以在这个类中的字典嵌套使用其它类了。(一个类集合几个类的功能)
#注解:在一个类的init中定义一个空字典。创建一个方法,传参为键值对,值为类名,并将它们添加到空字典中。创建一个方法,循环这个字典的值,或者取出某个字典的值,就可以对这个类进行操作了,加括号就创建这个类的对象。
class StackConfig(object):
  pass
class UserConfig(StackConfig):
  pass
class AdminSite(object):
  def __init__(self):
      self._register = {} #init中创建一个空字典,
  def registry(self,key,arg=StackConfig): #通过registry方法将键值对通过这个方法传参进类中,然后键键值对加到init中的字典中。
      self._register[key] = arg #如果执行这个方法时没有传递值进来,那么就就是使用默认值StackConfig这个类。 #
  def run(self):
      for key,value in self._register.items(): #执行registry方法就会生成值是类的字典,这里对字典元素进行操作。
          obj = value() #将字典的每个值也就是每个类,加上括号变成类的对象,
          print(key,obj) #打印出键,打印出这个值为类的对象。
site = AdminSite() #创建一个AdminSite类的对象
site.registry(1) #没有传参,第二个默认传参为StackConfig类
site.registry(2,StackConfig)#有传参,就使用传参
site.registry(3,UserConfig) #可以传多个类到字典
site.run()
-------------------结果:
1 <__main__.StackConfig object at 0x005F58D0>
2 <__main__.StackConfig object at 0x005F5DD0>
3 <__main__.UserConfig object at 0x005F58F0>


5)这个4)的使用案例一: 一个类中生成空字典,类中一个方法是给字典赋值,值为类。一个是使用字典的类,取出类生成对象并取对象的实例变量
class StackConfig(object):
  list_display = '小马过河'
class UserConfig(StackConfig):
  list_display = '魔降风云变'
class AdminSite(object):
  def __init__(self):
      self._register = {}
  def registry(self,key,arg=StackConfig):
      self._register[key] = arg
  def run(self):
      for key,value in self._register.items():
          obj = value()
          print(key,obj.list_display) #这样来使用类中元素
site = AdminSite()
site.registry(1)
site.registry(2,StackConfig)
site.registry(3,UserConfig)
site.run()
-------------------结果:
1 小马过河
2 小马过河  
3 魔降风云变

#思考,如果是同一个属性不同的值,比如很多个人名,那么我把很多个人名写成一个列表,循环列表生成只需要传名字进类的一个对象,这样就可以实现给一个类创建多个对象了。这些对象要做相同的操作,我就写一个方法,对这些对象进行循环,实现一个的操作,就是实现很多个对象的相同的操作了。

#能少量代码实现很长的一个字典吗?可以生成嵌套字典吗?
6)这是4)的使用案例二,5)的基础上变化:一个类中生成空字典,类中一个方法是给字典赋值,值为类。一个是使用字典的类,取出类生成对象并执行对象可用的方法
class StackConfig(object):
    list_display = '小马过河'
    def changelist_view(self):
        print(self.list_display)
class UserConfig(StackConfig):
    list_display = '魔降风云变'
class AdminSite(object):
    def __init__(self):
        self._register = {}
    def registry(self, key, arg=StackConfig):
        self._register[key] = arg
    def run(self):
        for key, value in self._register.items():
            obj = value()
            obj.changelist_view()
site = AdminSite()
site.registry(1)
site.registry(2, StackConfig)
site.registry(3, UserConfig)
site.run()
-------------------结果:
小马过河
小马过河
魔降风云变

#用类和不用类的优势体现案例,有时间加一个

2.特殊成员

2.1 __init__

class Foo:
    def __init__(self, a1):
        self.a1 = a1
        print(self.a1)
obj = Foo('mcw') #创建一个对象,会先执行类中__init__方法,将方法里的变量在对象里形成实例变量。
-------------结果:
mcw

2.2 __new__

class Foo(object):
    def __init__(self): #用于给对象中赋值,初始化方法
        self.x = 123
        print("init")
    def __new__(cls, *args, **kwargs): # 用于创建空对象,构造方法
        print("new")  
        return object.__new__(cls) #如果没有返回object.__new__(cls) ,那么不能打印出init,什么道理
obj = Foo() #类()创建对象,先执行new方法,再执行init方法(父 object)
------------结果:
new   #自己创建一个__new__方法,打印,可以看出先执行new,new是object的方法,用于创建对象,py3继承object类。
init  #


2.3 __cal__

class Foo(object):
    def __call__(self, *args, **kwargs):
        print('执行call方法')
obj = Foo()
obj()
Foo()()
----------结果:
执行call方法
执行call方法
#类()创建对象,先执行new方法,再执行init方法(父 object)   函数()执行函数  方法()执行方法
类中定义__cal__方法,对象可以调用,可以对象(),对象+()执行类中cal方法 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server

def func(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
    return ['你好'.encode("utf-8")  ]

class Foo(object):

    def __call__(self, environ,start_response):
        start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
        return ['你<h1 style="color:red;">不好</h1>'.encode("utf-8")]


# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('127.0.0.1', 8000, Foo())
server.serve_forever()

2.4 __getitem__ __setitem__ __delitem__

class Foo(object):
    def __setitem__(self, key, value):
        pass
    def __getitem__(self, item):
        return item + 'uuu'
    def __delitem__(self, key):
        pass

obj1 = Foo()
obj1['k1'] = 123  # 内部会自动调用 __setitem__方法
val = obj1['xxx']  # 内部会自动调用 __getitem__方法
print(val)
del obj1['ttt']  # 内部会自动调用 __delitem__ 方法

2.5 __str__

class Foo(object):
    def __str__(self): #只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来
        return '小马过河'
obj=Foo()
print(obj,type(obj))    原本打印对象,返回的是对象的地址,使用str方法,就可以修改,指定打印对象,显示出想要显示的内容
-------------结果
小马过河 <class '__main__.Foo'>   #以后看着像字符串的,要记得不一定是字符串  

class User(object):
    def __init__(self,name,email):
        self.name = name
        self.email = email
    def __str__(self):
        return "%s %s" %(self.name,self.email,)
user_list = [User('小马','2g@qq.com'),User('小明','2d@qq.com'),User('小红','xx@qq.com')]
for item in user_list:
    print(item)
---------------------结果:
小马 2g@qq.com  #返回的不是字符串
小明 2d@qq.com
小红 xx@qq.com

2.6 __dict__

class Foo(object):
    lei="xiao"
    def __init__(self,name,age,email):
        self.name = name
        self.age = age
        self.email = email
obj = Foo('小马过河',18,'111@qq.com')
print(obj)
print(obj.name)
print(obj.age)
print(obj.email)
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val)  #对象.__dict__  只是将对象中init里的变量变成字典格式吗
-------------结果:
<__main__.Foo object at 0x01E45670>
小马过河
18
111@qq.com
{'name': '小马过河', 'age': 18, 'email': '111@qq.com'}  
#想要将对象变量变成键值对的形式,就可以用,:对象.__dict__ ,返回的是字典

2.7 上下文管理【面试题】

class Foo(object):
    def __enter__(self):
        self.x = open('a.txt',mode='a',encoding='utf-8')
        return self.x
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.x.close()

with Foo() as ff:
    ff.write('alex')
    ff.write('alex')
    ff.write('alex')
    ff.write('alex')
# class Context:
#     def __enter__(self):
#         print('进入')
#         return self
#
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('推出')
#
#     def do_something(self):
#         print('内部执行')S
#
# with Context() as ctx:
#     print('内部执行')
#     ctx.do_something()


class Foo(object):
    def do_something(self):
        print('内部执行')

class Context:
    def __enter__(self):
        print('进入')
        return Foo()

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('推出')

with Context() as ctx:
    print('内部执行')
    ctx.do_something()

2.8 两个对象相加

val = 5 + 8
print(val)
val = "小马" + "过河"  #字符串对象+对象。
print(val)
class Foo(object):
    def __add__(self, other):  #类的对象与对象做运算,需要定义方法才不报错。
        return 44   #去掉return 报参数错,在实例化对象的时候加参数报参数错误
obj1 = Foo()  
obj2 = Foo() 
val = obj1 + obj2 #两个对象相加之后没报错,但是结果只有一个就是add的返回值,
print(val)    
----------结果:
13
小马过河
44 #将44改为 other,打印结果:<__main__.Foo object at 0x006F5830>

特殊成员:就是为了能够快速实现执行某些方法而生。

3.内置函数补充

3.1 type,查看类型

class Foo:
    pass

obj = Foo()

if type(obj) == Foo:
    print('obj是Foo类的对象')

3.2 issubclass

class Base:  
    pass

class Base1(Base):
    pass

class Foo(Base1):
    pass

class Bar:
    pass

print(issubclass(Bar,Base))  #issubclass 子类 父类  判断是否直系前辈 #前是后的子类吗
print(issubclass(Foo,Base))

3.3 isinstance

class Base(object):
    pass

class Foo(Base):
    pass

obj = Foo()

print(isinstance(obj,Foo))  # 判断obj是否是Foo类或其基类的实例(对象)
print(isinstance(obj,Base)) # 判断obj是否是Foo类或其基类的实例(对象)
#实例(对象,实例)前是后的实例吗,是Ture,否, #判断前面的对象是否是后面这个类或者是其基类的示例,是返回Ture否返回False 

4.super

class Base(object):
    def func(self):
        print('base.func')
        return 123


class Foo(Base):
    def func(self):
        v1 = super().func()
        print('foo.func',v1)

obj = Foo()
obj.func()
# super().func() 去父类中找func方法并执行
class Bar(object):
    def func(self):
        print('bar.func')
        return 123

class Base(Bar):
    pass

class Foo(Base):
    def func(self):
        v1 = super().func()
        print('foo.func',v1)

obj = Foo()
obj.func()
# super().func() 根据类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)
class Base(object): # Base -> object
    def func(self):
        super().func()
        print('base.func')

class Bar(object):
    def func(self):
        print('bar.func')

class Foo(Base,Bar): # Foo -> Base -> Bar
    pass

obj = Foo()
obj.func()

# super().func() 根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)
super案例一:如何用父的同名属性覆盖子的属性super
class Base(object):
    def __init__(self, name):
        self.name = name
class Foo(Base):
    def __init__(self, name):
        self.name = "于大爷"   #self.name于大爷,下面由使用super(),往上级找到它的init函数,传参“小马过河”,于是name重新赋值了。
        super().__init__(name) # super(Foo,self).__init__(name)
obj1 = Foo('小马过河')
print(obj1.name)
--------------结果:
小马过河

5.异常处理

5.1 基本格式

#基本格式:try 代码块 except Exception as e: pass

try:
    pass
except Exception as e:
    pass
try:
    v = []
    v[11111] # IndexError
except ValueError as e:
    pass
except IndexError as e:
    pass
except Exception as e:
    print(e) # e是Exception类的对象,中有一个错误信息。
try:
    int('asdf')
except Exception as e:
    print(e) # e是Exception类的对象,中有一个错误信息。
finally:
    print('最后无论对错都会执行')
    
 #看一段代码执行是否会爆粗,捕获异常,  e是错误信息,e可以打印。
    
# #################### 特殊情况 #########################
def func():
    try:
        # v = 1
        # return 123
        int('asdf')
    except Exception as e:
        print(e) # e是Exception类的对象,中有一个错误信息。
        return 123
    finally:
        print('最后')

func()

5.2 主动触发异常

try:
    int('123')
    raise Exception('阿萨大大是阿斯蒂') # 代码中主动抛出异常
except Exception as e:
    print(e)
def func():
    result = True
    try:
        with open('x.log',mode='r',encoding='utf-8') as f:
            data = f.read()
        if 'alex' not in data:
            raise Exception()
    except Exception as e:
        result = False
    return result

5.3 自定义异常

class MyException(Exception):
    pass

try:
    raise MyException('asdf')
except MyException as e:
    print(e)
class MyException(Exception):
    def __init__(self,message):
        super().__init__()
        self.message = message

try:
    raise MyException('asdf')
except MyException as e:
    print(e.message)

总结

  • 特殊成员 (**)

  • 嵌套

  • type/issubclass/isinstacne

  • super

  • 异常

  •  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2021-08-09 22:12  马昌伟  阅读(0)  评论(0)    收藏  举报
博主链接地址:https://www.cnblogs.com/machangwei-8/