进阶面向对象——类的成员
类的成员可以分为三大类:字段、方法、属性。

@:所有成员中,只有普通字段的内容保存在对象中,即:根据此类创建了多少对象,在内存中就有多少普通字段。而其他的成员都是保存在类中的,即:无论对象的多少,在内存中只创建一份。
一、字段:(普通字段和静态字段)
1、普通字段:属于对象
2、静态字段:属于类
class Yitian: #静态字段 user = "张无忌" def __init__(self,name): #普通字段 self.name = name #直接访问普通字段 obj = Yitian("明教") print(obj.name) #直接访问静态字段 print(Yitian.user)
@普通字段需要通过对象来访问,静态方法通过类访问。(两者的归属不同)

由图可知:
静态字段在内存中只保存一份
普通字段在每个对象中都要保存一份
class Yitian: #静态字段 user = "张无忌" def __init__(self,name): #普通字段 self.name = name #直接访问普通字段 obj1 = Yitian("明教") obj2 = Yitian("峨眉") print(obj1.name) print(obj2.name) #增加了一个对象”峨眉“ #直接访问静态字段 Yitian.user = "周芷若" #改变了静态字段 结果:周芷若 print(Yitian.user) #最终结果:周芷若
应用的场景:通过类创建对象时,如果每个对象都具有相同字段,那么就用静态字段。
二、方法:(普通方法、静态方法、类方法-->在内存中都归属于类,调用方式不同)
1、普通方法:
由对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self。
2、类方法:
由类方法调用,至少一个cls参数,执行方法时,自动将调用该方法的类复制给cls.
3、静态方法:
由类调用,无默认值参数。
class Foo: def __init__(self,name): self.naem = name def ord_func(self): '''定义一个普通方法,至少有一个self参数''' print(self.naem) print("普通方法") @classmethod def class_func(cls): '''定义一个类方法,至少一个cls参数''' print("类方法") @staticmethod def static_func(): '''定义一个静态方法,无默认值参数''' print("静态方法") #调用普通方法 f = Foo() f.ord_func() #调用类方法 Foo.class_func() #调用静态方法 Foo.static_func()

@区别:
相同点:对于所有的方法而言,均属于类(非对象)中,所以在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同。
三、属性:
1、属性的基本使用:
#==========定义================= class Doo: def func(self): pass #定义属性 @property def prop(self): pass #=========调用=============== doo_obj = Doo() doo_obj.func() doo_obj.prop #调用属性

@定义属性的注意事项:
定义时,在普通方法的基础上添加@property装饰器
定义时,属性仅有一个self参数
调用时,无需括号
方法:obj.func()
属性:obj.prop #没有括号
属性存在的意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果python中没有属性,方法完全可以代替其功能。
#例: 分页显示请求的页面的数据 class Pager: def __init__(self,current_page): #用户当前请求的页码 self.current_page = current_page #每页默认显示10条数据 self.per_intems = 10 @property def start(self): val = (self.current_page - 1) * self.per_intems return val @property def end(self): val = self.current_page * self.per_intems return val #调用 p = Pager(10) print(p.start) print(p.end)
@python属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回
2、属性的两种定义方式
(1)、装饰器:在方法上应用装饰器
装饰器方式:在类的普通方法上应用@property装饰器
经典类:具有一种@property装饰器
#==========定义========= class Goods: @property def price(self): return "张无忌" # ======调用========== obj = Goods() result = obj.price #自动执行@property修饰方法,并获取方法的返回值。 print(result)
新式类:具有三种@property装饰器
#======定义======= class Goods: @property def price(self): print("张无忌") @price.setter def price(self,value): print("周芷若") # print(value) @price.deleter def price(self): print("赵敏") # =====调用============ obj = Goods() obj.price #自动执行@property修饰的price方法,并获取方法的返回值 obj.price = 123 #自动执行@property.setter修饰的price方式,并将123赋值给方法的参数 del obj.price #自动执行@price.deleter修饰的price方法
@ 经典类中的属性只有一种访问方式,其对应被@property修饰的方法
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法。(由于新式类中具有三种访问方式,根据他们几个属性访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除)
class Goods: def __init__(self): #原价 self.original_price = 10 #折扣 self.discount = 0.8 @property def price(self): #实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self,value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() print(obj.price) #获取商品价格 update = obj.price = 200 #修改商品原价 print(update) del obj.price #删除商品原价
(2)、静态字段:在类中定义值为property对象的静态字段
当使用静态字段的方式创建属性时,经典类和新式类无区别
class Foo: def get_bar(self): return "张无忌" BAR = property(get_bar) obj = Foo() reuslt = obj.BAR #自动调用get_bar方法,并获取方法的返回值 print(reuslt) # 结果:张无忌
property的构造方法中有四个参数
第一个参数是方法名,调用对象.属性 时自动触发执行方法
第二个参数是方法名,调用对象.属性 =xxx 时自动触发执行方法
第三个参数是方法名,调用del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用对象.属性.__doc__,此参数是该属性的描述信息
class Foo: def get_bar(self): return "张无忌" #必须两个参数 def set_bar(self,value): return "set value" + value def del_bar(self): return "周芷若" BAR = property(get_bar,set_bar,del_bar,"description...") obj = Foo() obj.BAR #自动调用第一个参数中定义的方法:get_bar obj.BAR = "赵敏" #自动调用第二个参数中定义的方法:set_bar,并将“赵敏”当作参数传入 del Foo.BAR #自动调用第三个参数中定义的方法:del_bar方法 obj.BAR.__doc__ #自动获取第四个参数中设置的值description...
由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点分别将三个方法定义位获取、修改、删除
class Googs(object): def __init__(self): self.original_price = 100 #原价 self.discount = 0.8 #折扣 self.WW = 22 def get_price(self): #实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price def set_price(self,value): self.original_price = value def del_price(self): del self.WW PRICE = property(get_price, set_price, del_price, "价格属性描述。。。") obj = Googs() print(obj.PRICE) #获取商品价格 obj.PRICE = 200 #修改商品原价 del obj.PRICE #删除商品原价
所以在定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。
四、类成员修饰符
对于每一个类的成员而言都有两种形式:
共有成员,在任何地方都能访问
私有成员,只有在类的内部才能访问
1、私有成员的和共有成员的定义不同
私有成员命名时,前两个字符时下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)
class Foo: def __init__(self): self.name = "张无忌" #公有字段 self.__age = 20 #私有字段
2、私有成员和共有成员的访问限制不同:
(1)、静态字段
公有静态字段:类可以访问;类内部可以访问,派生类中可以访问
class Foo: name = "张无忌" #公有静态字段 def func(self): print(Foo.name) class Doo(Foo): def show(self): print(Foo.name) Foo.name #类访问 obj = Doo() obj.func() #内部类可以访问 obj_son = Doo() obj_son.show() #派生类中可以访问
私有静态字段:仅类内部可以访问
class Foo: __name = "张无忌" #私有静态字段 def func(self): print(Foo.__name) class Doo(Foo): def show(self): print(Foo.__name) Foo.name #类访问 ---错误 obj = Doo() obj.func() #内部类可以访问 ---正确 obj_son = Doo() obj_son.show() #派生类中可以访问 ---错误
(2)、普通字段
共有普通字段:对象可以访问,内部类可以访问、派生类可以访问
class Foo: def __init__(self): self.foo = "周芷若" #公有字段 def func(self): print(self.foo) #类内部访问 class Doo(Foo): def show(self): print(self.foo) #派生类中访问 obj = Foo() obj.foo #通过对象访问 obj.func() #类内部访问 obj_son = Doo() obj_son.show() #派生类中访问
私有普通字段:仅类内部可以访问
@如果想要强制访问私有字段,可以通过[对象._类名__私有字段名]访问,(例如:obj._Foo__foo),不建议强制访问私有成员。
class Foo: def __init__(self): self.__foo = "周芷若" #私有字段 def func(self): print(self.__foo) #类内部访问 class Doo(Foo): def show(self): print(self.__foo) #派生类中访问 ---错误 obj = Foo() obj.foo #通过对象访问 ---错误 obj.func() #类内部访问 ---正确 obj_son = Doo() obj_son.show() #派生类中访问 ---错误
@方法、属性的访问于上述方式相似,即:私有成员只能子啊类内部是用
@非要访问私有属性的话,可以通过 对象._类__属性名
五、类的特殊成员
1、__doc__
2、__module__和__class__
3、__init__
4、__del__
5、__call__
6、__dict__
7、__str__
8、__getitem__、__setitem__、__delitem__
9、__getslice__、__setslice__、__delslice__
10、__iter__
11、__new__和__metaclass__
浙公网安备 33010602011771号