深入理解python面向对象-类成员

Python是一种面向对象的语言,但由于python语言的特点,我们大多数python程序员只是把它当作工具。在我们项目的实际使用中,除了使用Django框架外,其他都是使用python最基本的方式,这与pythonic无关,当然,主要是因为我们的能力太差。面向对象是写各种框架的基础。python的面向对象不仅具有一般面向对象的特点,而且具有一些极其强大的特点,可以充分发挥其便利性。本文将详细介绍Python 类别成员、成员修饰符、类别特殊成员。
类的成员
成员可分为三个方面:字段、方法和属性。
定义一个类后,方法、属性和静态字段属于类,内存中只保存一个,只有普通字段属于类对象,每个类对象都会创建和保存一个。
存储区可分为程序存储区、全局存储区、静态存储区、栈存储区。
程序存储区: 存储在普通函数、类函数、类等程序中的所有位置。
全局存储区:所有全局变量存储区。
静态存储区:类静态变量存储区。
堆栈存储区:堆栈存储区是局部变量存储,所有局部变量、类对象等都存储在这里。
字段
字段包括:普通字段和静态字段,使用和定义不同,最本质的区别是内存中保存的位置不同。
一般字段属于对象
静态字段属于类
classDemo: aa="我是静态字段" def__init__(self,name): self.bb=namedefcustom_func(self,name): self.cc=name
obj1=Demo(11)
Demo.aa=111111obj1.aa=1obj1.custom_func(1111)
obj2=Demo(22)
obj2.aa=2Demo.aa=222222obj2.custom_func(2222)
print("obj1.aa=",obj1.aa)
print("obj1.bb=",obj1.bb)
print("obj1.cc=",obj1.cc)
print("Demo.aa=",Demo.aa)
print("obj2.aa=",obj2.aa)
print("obj2.bb=",obj2.bb)
print("obj2.cc=",obj2.cc)
print("Demo.aa=",Demo.aa)
print("id(Demo.aa)=",id(Demo.aa))
print("id(obj1.aa)=",id(obj1.aa))
print("id(obj2.aa)=",id(obj2.aa))输出
obj1.aa=1 obj1.bb=11 obj1.cc=1111 Demo.aa=222222 obj2.aa=2 obj2.bb=22 obj2.cc=2222 Demo.aa=222222 id(Demo.aa)=4645988944 id(obj1.aa)=4530158768 id(obj2.aa)=4530158800
从上面我们可以看出,bb、CC是一个普通的字段,每个类别都是独一无二的,不相互影响,需要使用类对象访问,而Demo.aa和obj.aa是不同的,我们看到obj.如果去除obj1,aa的行为类似于普通字段.aa=xx和obj2.aa=xx,那么obj1.aa和Demo.aa是一样的,内存中的地址也是一样的。它涉及到python的另一个特征——临时属性。
通常,我们使用普通字段。当一个变量在类的所有对象中共用并共享数据时,我们可以使用静态字段。
方法
方法包括:普通方法、静态方法和类别方法。它们之间的区别在于不同的调用方法。
普通方法:由对象调用;包含self参数;执行普通方法时,将调用该方法的对象自动赋值self;
类法:由类调用; 包含cls参数;执行类方法时,调用该方法的类自动复制到cls;
静态方法:由类调用;无默认参数;
classFoo:
FooName="静态字段"
defcustom_func(self,name):
#普通方法至少包含一个self参数
print("普通方法")@classmethod
defclass_func(cls,name):
#类方法至少包含一个cls参数
print("类方法")@staticmethod
defstatic_func(name):
#静态方法,没有默认参数
print("静态方法")
f=Foo()#调用普通方法f()#.custom_func("aaa")#Fooo调用类方法.class_func("bbb")#调用静态Foo.static_func("ccc")对象的普通字段self可以在普通方法中直接使用.name
静态字段clss可直接用于分类方法.FooName
普通字段和静态字段不能直接用于静态方法
注:Foooo:静态字段.Fooname可以在任何地方调用,包括上述三种场景,如果也可以在普通方法中使用 self.Fooname调用,前提是对象没有同名的普通字段
属性
我们已经介绍了Python中的方法,所以属性很简单,因为Python中的属性实际上是普通方法的变体。
属性有以下两个知识点:
基本使用
两种定义方法
classFoo:
deffunc(self):
pass@property
defprop(self):
print("属性")
f=Foo()#调用函数f.func()#调用属性f.prop通过以上例子,我们知道属性有以下几点:
一般方法添加@property装饰器
只有一个self参数,不能添加额外的参数
不需要括号来调用
当我们做网页数据显示时,页面上显示数据的数据不可能一次在页面上显示数据库中的所有内容,通常通过分页功能实现。因此,每个请求都将根据当前页面数量curent_page和每页显示的数量page_count取出指定范围的数据
classPager: def__init__(self,current_page): #当前显示的页码 self.current_page=current_page#默认显示每个页面的数据 self.per_items=10@property defstart(self): return(self.current_page-1)*self.per_items@property defend(self): returnself.current_page*self.per_items pages=Pager(1) pages.start#起始值pages.end#结束值
两种定义属性的方法
定义属性有两种方式:
装饰器:装饰器的应用
静态字段:定义值为property对象的静态字段
我们知道Python中有经典类和新类。如果类继承自object,那么类是新类,新类的属性比经典类更丰富。但是python3已经用过了,而python3中的默认类继承自object,所以python3都是新类。
1. 装饰方法:普通方法加@property装饰器
classGoods:@property
defprice(self):
print("@property")@price.setter
defprice(self,val):
print("@price.setter:",val)@price.deleter
defprice(self):
print("@price.deleter")
obj=Goods()
obj.price#price方法自动执行@property修改,获取方法的返回值obj.price=100
#自动执行@price.setter修改的price方法,并将100分配给方法的参数delobj.price
#自动执行@price.deleter修改的price方法2. 使用property创建静态字段的静态字段
property是builtins中的一个类别.初始化函数在py文件中:def __init__(self, fget=None, fset=None, fdel=None, doc=None),有四个参数
第一个参数fget是方法名,调用 对象.属性 执行方法自动触发
第二个参数fset是方法名,调用 对象.属性 = XXX 执行方法自动触发
第三个参数fdel是方法名,调用 del 对象.属性 执行方法自动触发
第四个参数doc是字符串,调用 对象.属性.doc ,该参数是该属性的描述信息
classFoo: def__init__(self): self.price=10 defget_price(self): returnself.price#set函数必须有两个参数 defset_price(self,value): self.price=valuedefdel_price(self): delself.price PRICE=property(get_price,set_price,del_price,"descriptionPrice") f=Foo() print(f.PRICE)#get_自动调用get_自动调用get_pricef.PRICE=20 #set_自动调用set_自动调用set_priceprint(f.PRICE) #del_自动调用del_pricedelf.PRICE #description自动调用
