一、再论静态方法和类方法以及实例方法
- 1.1、类属性、实例属性它们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同
- 实例属性属于对象
- 类属性属于类
class Province(object): # 类属性 country = '中国' def __init__(self, name): # 实例属性 self.name = name # 创建一个实例对象 obj = Province('山东省') # 直接访问实例属性 print(obj.name) # 直接访问类属性 Province.country
- 由上述代码可以看出【实例属性需要通过对象来访问】【类属性通过类访问】,在使用上可以看出 实例属性和类属性的归属是不同的。
- 类属性在内存中只保存一份
- 实例属性在每个对象中都要保存一份
- 应用场景:通过类创建实例对象时,如果每个对象需要具有相同名字的属性,那么就使用类属性,用一份既可
- 1.2、实例方法、静态方法和类方法 (类里面的三种方法,区别在于调用方式不同)
- 实例方法:由对象调用;至少一个self参数;执行实例方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类赋值给cls;
- 静态方法:由类调用;无默认参数;
class Foo(object): def __init__(self, name): self.name = name def ord_func(self): """ 定义实例方法,至少有一个self参数 """ # print(self.name) print('实例方法') @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print('类方法') @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print('静态方法') f = Foo("中国") # 调用实例方法 f.ord_func() # 调用类方法 Foo.class_func() # 调用静态方法 Foo.static_func()
- 相同点:对于所有的方法而言,均属于类,所以 在内存中也只保存一份
- 不同点:方法调用者不同、调用方法时自动传入的参数不同。
二、property 属性
- 2.1、什么是property属性,在方法名的加上property就是 property属性,在调用上
dog.run
优于dog.eat()
class Dog(object): def eat(self): print("吃") # 定义property属性 @property def run(self): print("跑") dog = Dog() dog.eat() # 调用实例方法 dog.run # 调用property属性
- property属性的定义和调用要注意一下几点:
- 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
- 调用时,无需括号
方法:dog.eat() property属性:dog.run
- 2.2、property属性有两种方式
- 装饰器 即:在方法上应用装饰器
- 类属性 即:在类中定义值为property对象的类属性
- 2.2.1、装饰器方式在类的实例方法上应用@property装饰器,Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )
- 经典类,具有一种@property装饰器
class Goods: @property def price(self): return "laowang" # ############### 调用 ############### obj = Goods() result = obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 print(result)
- 新式类,具有三种@property装饰器
# ############### 定义 ############### class Goods: """python3中默认继承object类 以python2、3执行此程序的结果不同,因为只有在python3中才有@xxx.setter @xxx.deleter """ @property def price(self): print('@property') @price.setter def price(self, value): print('@price.setter') @price.deleter def price(self): print('@price.deleter') # ############### 调用 ############### obj = Goods() obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数 del obj.price # 自动执行 @price.deleter 修饰的 price 方法
注意
- 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
- 新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
- 由于新式类中具有三种访问方式,我们可以根据它们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
class Goods(object): def __init__(self): # 原价 self.original_price = 100 # 折扣 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() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 del obj.price # 删除商品原价
- 2.2.2、类属性 方式,创建值为property对象的类属性,我比较喜欢这个方式
- 当使用
类属性
的方式创建property属性
时,经典类 和 新式类 无区别
class Person: def get_name(self): return 'laowang' BAR = property(get_name) obj = Person() reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值 print(reuslt)
- property 方法中有个
四个参数
- 第 1 个参数是方法名,调用
对象.属性
时自动触发执行方法 - 第 2 个参数是方法名,调用
对象.属性 = XXX
时自动触发执行方法 - 第 3 个参数是方法名,调用
del 对象.属性
时自动触发执行方法 - 第 4 个参数是字符串,调用
对象.属性.__doc__
,此参数是该属性的描述信息
class Person(object): def __init__(self,name): self.name = name def get_name(self): return self.name def set_name(self,new_name): self.name = new_name print("设置名字为:%s"%self.name) def del_name(self): del self.name BAR = property(get_name,set_name,del_name,"描述信息...") person = Person("小王") person.BAR # 自动调用第一个参数中定义的方法:get_name person.BAR = "小李" # 自动调用第二个参数中定义的方法:set_name方法,并将 "小李" 当作参数传入 person.del_name # 自动调用第三个参数中定义的方法:del_name方法 desc = Person.BAR.__doc__ # 自动获取第四个参数中设置的值:描述信息... print("描述是:%s"%desc)
- 由于类属性方式创建 property属性 具有3种访问方式,我们可以根据它们几个属性的访问特点,分别将 三个方法定义为对同一个属性:获取、修改、删除,如下商品的价格
class Goods(object): def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 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.original_price PRICE = property(get_price, set_price, del_price, '价格属性描述...') obj = Goods() obj.PRICE # 获取商品价格 obj.PRICE = 200 # 修改商品原价 del obj.PRICE # 删除商品原价
- 2.3、Django框架中应用了property属性(了解)
WEB框架 Django 的视图中 request.POST 就是使用的类属性的方式创建的属性
class WSGIRequest(http.HttpRequest): def __init__(self, environ): script_name = get_script_name(environ) path_info = get_path_info(environ) if not path_info: # Sometimes PATH_INFO exists, but is empty (e.g. accessing # the SCRIPT_NAME URL without a trailing slash). We really need to # operate as if they'd requested '/'. Not amazingly nice to force # the path like this, but should be harmless. path_info = '/' self.environ = environ self.path_info = path_info self.path = '%s/%s' % (script_name.rstrip('/'), path_info.lstrip('/')) self.META = environ self.META['PATH_INFO'] = path_info self.META['SCRIPT_NAME'] = script_name self.method = environ['REQUEST_METHOD'].upper() _, content_params = cgi.parse_header(environ.get('CONTENT_TYPE', '')) if 'charset' in content_params: try: codecs.lookup(content_params['charset']) except LookupError: pass else: self.encoding = content_params['charset'] self._post_parse_error = False try: content_length = int(environ.get('CONTENT_LENGTH')) except (ValueError, TypeError): content_length = 0 self._stream = LimitedStream(self.environ['wsgi.input'], content_length) self._read_started = False self.resolver_match = None def _get_scheme(self): return self.environ.get('wsgi.url_scheme') def _get_request(self): warnings.warn('`request.REQUEST` is deprecated, use `request.GET` or ' '`request.POST` instead.', RemovedInDjango19Warning, 2) if not hasattr(self, '_request'): self._request = datastructures.MergeDict(self.POST, self.GET) return self._request @cached_property def GET(self): # The WSGI spec says 'QUERY_STRING' may be absent. raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '') return http.QueryDict(raw_query_string, encoding=self._encoding) # ############### 看这里看这里 ############### def _get_post(self): if not hasattr(self, '_post'): self._load_post_and_files() return self._post # ############### 看这里看这里 ############### def _set_post(self, post): self._post = post @cached_property def COOKIES(self): raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '') return http.parse_cookie(raw_cookie) def _get_files(self): if not hasattr(self, '_files'): self._load_post_and_files() return self._files # ############### 看这里看这里 ############### POST = property(_get_post, _set_post) FILES = property(_get_files) REQUEST = property(_get_request)
综上所述
- 定义property属性共有两种方式,分别是【装饰器】和【类属性】,而【装饰器】方式针对经典类和新式类又有所不同。
- 通过使用property属性,能够简化调用者在获取数据的流程