python面向对象进阶
1.成员
面相对低昂中的所有成员:
- 变量
- 实例变量
- 类变量
- 方法
- 绑定方法
- 类方法
- 静态方法
- 属性
1.1变量
- 实例变量,属于对象,每个对象中各自维护自己的数据
- 类变量,属于类,可以被所有的对象共享,一般用于给对象提供公共数据(类似于全局变量)
类变量实例
当把每个对象中都存在的相同的实例变量时,可以选择把它放在类变量中,可以避免对象中维护多个相同的数据
class Person:
country="中国"
def __init__(self,name):
self.name=name
def show(self):
message="我叫{},我在{}".format(self.name,self.country)
print(message)
p=Person("wxy")
print(p.name)#wxy
#通过对象调用变量
print(p.country) #中国
p.show() #我叫wxy,我在中国
#通过类调用变量
print(Person.country) #中国
易错点
- 读和写的区别
#读
class Person:
country="中国"
def __init__(self,name):
self.name=name
def show(self):
message="我叫{},我在{}".format(self.name,self.country)
print(message)
p=Person("wxy")
print(p.name)#wxy
#通过对象调用变量
print(p.country) #中国
p.show() #我叫wxy,我在中国
#通过类调用变量
print(Person.country) #中国
#写1
class Person:
country="中国"
def __init__(self,name):
self.name=name
def show(self):
message="我叫{},我在{}".format(self.name,self.country)
print(message)
p=Person("wxy")
print(p.name)#wxy
#通过对象调用变量
print(p.country) #中国
p.show() #我叫wxy,我在中国
#通过类调用变量
print(Person.country) #中国
#写2
class Person:
country="中国"
def __init__(self,name):
self.name=name
def show(self):
message="我叫{},我在{}".format(self.name,self.country)
print(message)
#Person.country修改的是类中country的值
Person.country="安徽"
p=Person('wxy')
#country已被修改
print(p.country)
# 安徽
- 继承关系中的读写
class Base(object):
country = "中国"
class Person(Base):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
# message = "{}-{}-{}".format(Person.country, self.name, self.age)
message = "{}-{}-{}".format(self.country, self.name, self.age)
print(message)
# 读
print(Base.country) # 中国
print(Person.country) # 中国
obj = Person("wxy",19)
print(obj.country) # 中国
obj.show()
# 写
Base.country = "china"
Person.country = "泰国"
obj.country = "日本"
1.2方法
-
绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】
-
类方法,默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】
-
静态方法,无默认参数,用类和对象都可以调用【对象&类均可调用】
在python中比较灵活,方法都可以通过对象和类调用;而在java,c#等语言中,绑定方法只能由对象调用,类方法或静态方法只能由类调用
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def f1(self):
print("绑定方法",self.name)
@classmethod
def f2(cls):
print("类方法",cls)
@staticmethod
def f3():
print("静态方法")
#绑定方法对象
f=Foo("wxy",18)
f.f1() #绑定方法经常通过对象调用
Foo.f1(f)
#类方法
Foo.f2() #cls就是当前调用这个方法的类(类方法经常通过类调用)
f.f2() #cls就是当前调用这个方法的对象的类
#静态方法
Foo.f3() #类执行方法(静态方法经常通过类调用)
f.f3() #对象执行方法
1.3属性
属性其实就是有绑定方法+特殊装饰器组合创造出来的,让我们在调用方法是不用加括号
class Foo:
def __init__(self,name):
self.name=name
@property
def f1(self):
return 123
f=Foo('wxy')
#被属性装饰的方法,直接加方法名,不用加()
result=f.f1
print(result) #123
属性编写有两种方式
-
方式一,基于装饰器
class C: @property def x(self): print("property") @x.setter def x(self,value): print(value) @x.deleter def x(self): pass o=C() a=o.x print(a) o.x=123 del o.x
-
方式二,基于定义变量
class C: def getx(self): print('getx') def setx(self,value): print('setx') def delx(self): print('delx') x=property(getx,setx,delx,"I'm the 'x' property.") c=C() #调用getx c.x #调用setx,将值传递给value c.x=123 # 调用delx del c.x
由于属性和实例变量的调用方式相同,所以在编写时要注意:属性名称不要和实例变量重名,一旦重名,可能会报错
如果想在名称上创建一些关系,可以在实例变量上加一个下划线
class Foo: def __init__(self,name): self._name=name @property def name(self): return self._name o=Foo('wxy') #调用类变量 print(o._name) #调用类方法 print(o.name)
2.成员修饰符
python中成员的修饰符就是指:共有,私有
- 共有,在任何地方都可以调用这个成员
- 私有,只有在类的内部才可以调用该成员(成员是以两个下划线开头,则表示该成员为私有)
示例一:私有变量
class Foo:
def __init__(self,name,age):
self.__name=name
self.age=age
def get_data(self):
#私有变量可以在类中使用
return self.__name
def get_age(self):
return self.age
o1=Foo('wxy',18)
#共有成员
print(o1.age)
print(o1.get_age())
#'Foo' object has no attribute '__name'
print(o1.__name) #私有变量外部不能调用,会报错,只能在类中进行使用
#调用私有成员
v=o1.get_data()
print(v)
示例二:私有方法
class Foo:
def get_age(self):
print("共有方法get_age")
def __get_data(self):
print("私有方法__get_data")
def proxy(self):
print("共有方法proxy")
#私有方法可以在类中使用
self.__get_data()
o=Foo()
o.get_age()
o.proxy()
o.__get_data()#报错,私有方法不能再外部使用
# 共有方法get_age
# 共有方法proxy
# 私有方法__get_data
示例三:属性+私有方法
class Foo:
@property
def __name(self):
print("私有的name")
@property
def proxy(self):
print("共有的proxy")
self.__name
return 1
o=Foo()
v=o.proxy
print(v)
# 共有的proxy
# 私有的name
# 1
提示:父类中的私有成员,子类无法继承
class Base:
def __data(self):
print("base.__data")
def num(self):
print('base.num')
class Foo(Base):
def func(self):
#自己没有找父类
self.num()
#'Foo' object has no attribute '_Foo__data'
#自己没有找父类,父类中是私有方法,不能使用,所以报错
self.__data()
o=Foo()
o.func()
#这样调用可以
class Base:
def __data(self):
print("base.__data")
def num(self):
print("base.num")
#可以调用自己的私有方法
self.__data()
class Foo(Base):
def func(self):
self.num()
o=Foo()
o.func()
# base.num
# base.__data
用一些特殊的语法也可以被外部调用【不推荐这样写】
class Foo:
def __init__(self):
self.__num=123
self.age=19
def __msg(self):
print(123)
o=Foo()
print(o.age)
#通过对象._方法名__私有变量名可以调用私有变量
print(o._Foo__num)
#通过对象._方法名__私有方法名可以调用私有方法
o._Foo__msg()
判断什么时候创建私有和共有
- 判断是否可以作为独立的功能暴露给外部,让外部调用并使用
- 可以,用共有。不可以,放在内部给其他方法辅助,私有
3.对象嵌套
组合,关联,依赖等(java的称呼),即各种嵌套
4.特殊成员
在python的类中存在一些特殊的方法,这些方法都是__init__格式,这种方法在内部均有特殊含义
-
__init__
,初始化方法class Foo: #创建对象时,自动执行 def __init__(self,name): self.name=name o=Foo('wxy')
-
__new__
,构造方法class Foo(object): def __init__(self,name): print("第二步,初始化对象") #没有创建这个方法,会去默认父类object中找 def __new__(cls, *args, **kwargs): print("第一步,创建对象返回") return object.__new__(cls) o=Foo('wxy') # 第一步,创建对象返回 # 第二步,初始化对象
-
__call__
class Foo(object): def __call__(self, *args, **kwargs): print("执行call方法") o=Foo() #对象(),自动执行call方法 o()
-
__str__
class Foo: #返回值是字符串类型 def __str__(self): return '你好' o=Foo() data=str(o) print(data) #你好
-
__dict__
class Foo: def __init__(self,name,age): self.name=name self.age=age o=Foo('wxy',18) #返回字典类型 print(o.__dict__) # {'name': 'wxy', 'age': 18}
-
__getitem__
,__setitem__
,__delitem__
class Foo: def __getitem__(self, item): pass def __setitem__(self, key, value): pass def __delitem__(self, key): pass a=Foo() a['x1']=123 a['x2']=123 b=a['x1'] print(b) del a['x2']
-
__enter__
,__exit__
class Foo: def __enter__(self): print("进入") return 666 def __exit__(self, exc_type, exc_val, exc_tb): print("出去了") f=Foo() #data是返回值 #上下文管理语法 with f as data: print(data)
应用场景:数据库连接
-
连接=连接数据库
-
操作数据库
-
关闭数据库
class SqlHelper(object): def __enter__(self): self.连接 = 连接数据库 return 连接 def __exit__(self, exc_type, exc_val, exc_tb): self.连接.关闭 with SqlHelper() as 连接: 连接.操作..
-
-
__add__
等class Foo: def __init__(self,name): self.name=name def __add__(self, other): return '{}-{}'.format(self.name,other.name) v1=Foo('wxy1') v2=Foo('wxy2') #对象+值,内部会执行,对象.__add__方法,并将+后面的值当参数传递过去 v3=v1+v2 print(v3) # wxy1-wxy2
-
__iter__
- 迭代器定义
- 当类中定义了
__iter__
和__next__
两个方法 __iter__
方法需要返回对象本身,即self__next__
方法,返回下一个数据,如果没有数据,则需要抛出一个StopIteration异常
- 当类中定义了
#创建:迭代器类型 class IT: def __init__(self): self.counter=0 def __iter__(self): return self def __next__(self): self.counter+=1 if self.counter==3: raise StopIteration() return self.counter #实例化创建一个迭代器对象 a=IT() #执行方式一 # a.__next__() # a.__next__() # a.__next__() #取值结束抛出异常StopIteration #执行方式二 next(a) #a.__next__() next(a) next(a) #取值结束抛出异常StopIteration #执行方式三,首先会执行迭代器对象的__init__方法并获取返回值,一直反复执行(有异常则终止循环) # for i in a: # print(a)
- 生成器(其实生成器类是一种特殊的迭代器类,生成器类也是一种特殊的迭代器类)
def func(): yield 1 yield 2 #创建生成器对象(内部是根据生成器类generator创建的对象),生成器类的内部也声明了:__iter__,__next__方法 a=func() #方式二 # v1=next(a) # print(v1) # v2=next(a) # print(v2) # v3=next(a) #取多抛出异常StopIteration # print(v3) #方式一 for i in a: print(i)
- 可迭代对象(如果一个类中有
__iter__
方法且返回一个迭代器对象:称这个类创建的对象为可迭代对象)
class Foo: def __iter__(self): return 迭代对象 a=Foo() #a是可迭代对象 #可迭代对象可以使用for进行循环,在循环的内部其实是先执行__iter__方法,获取其迭代器对象,然后再内部执行这个迭代器对象的next功能,逐步取值 for i in a: print(a)
class IT(object): def __init__(self): self.counter = 0 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter class Foo: def __iter__(self): return IT() #a为迭代器对象 a=Foo() #循环可迭代对象,内部执行a.__iter__并获取迭代器对象,不断的执行迭代器对象的next方法 for i in a: print(i)
- 迭代器定义
判断是否是迭代器和迭代器对象
from collections.abc import Iterator,Iterable
v1=[11,22,33]
#判断是否是迭代器,依据:是否有__iter__,__next__
print(isinstance(v1,Iterator)) #False
v2=v1.__iter__()
print(isinstance(v2,Iterator)) #True
#判断依据;是否有__iter__且返回迭代器对象
print(isinstance(v1,Iterable))#True
print(isinstance(v2,Iterable))#True
https://www.luffycity.com/