面向对象:classmethod、staticmethod、property

一、classmethod(类方法)、staticmethod(静态方法)

方法包括:普通方法、类方法和静态方法,三种方法在内存中都归属于类,区别在于调用方式不同。

# 普通方法
    由对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self。
# 类方法
    由类调用,至少一个cls参数,执行类方法时,自动将调用该方法的类赋值给cls;当一个方法的操作只涉及静态属性的时候,就应该使用classmethod来装饰这个方法。
# 静态方法
    由类调用,无默认参数;在面向对象的程序中,如果一个函数既和对象没有关系,也和类没有关系,那么就用staticmethod将这个函数变成一个静态方法。
class Person(object):
    country = "美国"

    def __init__(self, name):
        self.name = name

    def func(self):
        """定义普通方法,至少有一个self参数"""
        print(self.name)

    @classmethod
    def change_country(cls):
        """定义类方法,至少有一个cls参数"""
        cls.country = "中国"

    @staticmethod
    def sleep():
        """定义静态方法,无默认参数"""
        print("正在睡觉...")


person = Person("pd")
########## 调用普通方法 ##########
person.func()  # pd

########## 调用类方法 ##########
Person.change_country()    # 可以通过类的名字调用类方法
# person.change_country()  # 还可以通过这个类创建出来的对象去调用类方法
print(Person.country)      # 中国

########## 调用静态方法 ##########
Person.sleep()  # 通过类的名字去调用静态方法
person.sleep()  # 通过实例对象去调用静态方法

相同点:对于所有的方法而言,均属于类(非对象)中;所以,在内存中也只保存一份。

不同点:方法调用者不同,调用方法时自动传入的参数不同。

二、property(属性)

属性非常简单,因为Python中的属性其实是普通方法的变种。

2.1 属性的基本使用

class Person(object):
    def __init__(self, name):
        self.name = name

    def func1(self):
        print(self.name)

    @property  # 定义属性
    def func2(self):
        print(self.name)

obj = Person("pd")

obj.func1()  # pd
obj.func2    # 调用属性,结果同上

由属性的定义和调用要注意以下几点:

定义时,在普通方法的基础上添加 @property 装饰器
定义时,属性仅有一个self参数
调用时,无需括号
      方法:obj.func1()
      属性:obj.func2

属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象。

属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

2.2 属性的两种定义方式

装饰器方式:在类的普通方法上应用装饰器

Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。(如果类继object,那么该类是新式类)

经典类,只有一种@property装饰器(如上面的示例那样)

新式类,具有三种@property装饰器

class Goods(object):
    def __init__(self):
        self.__price = 100   # 设定原价
        self.discount = 0.8  # 设定折扣

    @property
    def price(self):
        """获取价格"""
        return self.__price * self.discount

    @price.setter
    def price(self, value):
        """设置价格"""
        self.__price = value

    @price.deleter
    def price(self):
        """删除商品原价这个属性"""
        del self.__price


obj = Goods()
print(obj.price)  # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 200   # 自动执行 @price.setter 修饰的 price 方法,并将200赋值给方法的参数
print(obj.price)
del obj.price     # 自动执行 @price.deleter 修饰的 price 方法,删除商品原价这个属性
print(obj.price)  # 报错,AttributeError: 'Goods' object has no attribute '_Goods__price'
View Code

静态字段方式:在类中定义值为property对象的静态字段

当使用静态字段的方式创建属性时,经典类和新式类无区别。

示例:

class Foo(object):

    def get_name(self):
        return "pd"

    NAME = property(get_name)

obj = Foo()
ret = obj.NAME  # 自动调用func方法,并获取方法的返回值
print(ret)      # pd

property的构造方法中有个四个参数:

第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 对象.属性.__doc__,此参数是该属性的描述信息
class Goods(object):
    def __init__(self):
        self.__price = 100   # 设定原价
        self.discount = 0.8  # 设定折扣

    def get_price(self):
        """获取价格"""
        return self.__price * self.discount

    def set_price(self, value):
        """设置价格"""
        self.__price = value

    def del_price(self):
        """删除商品原价这个属性"""
        del self.__price

    PRICE = property(get_price, set_price, del_price, "价格属性描述...")

obj = Goods()

ret = obj.PRICE     # 自动调用第一个参数中定义的方法:get_name
print(ret)          # 80.0
obj.PRICE = 200     # 自动调用第二个参数中定义的方法:set_name,并将"200"当作参数传入
print(obj.PRICE )   # 160.0
del obj.PRICE       # 自动调用第三个参数中定义的方法:del_name

注意:Python 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)
    
    ############### Look Here ###############
    def _get_post(self):
        if not hasattr(self, '_post'):
            self._load_post_and_files()
        return self._post

    ############### Look Here ###############
    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

    ############### Look Here ###############
    POST = property(_get_post, _set_post)
    FILES = property(_get_files)
    REQUEST = property(_get_request)
Django源码

 

posted @ 2018-09-14 11:15  就俗人一个  阅读(361)  评论(0编辑  收藏  举报