一、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'

静态字段方式:在类中定义值为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源码

面向对象:classmethod、staticmethod、property的更多相关文章

  1. Python类中装饰器classmethod,staticmethod,property,

    @classmethod 有的时候在类中会有一种情况,就是这个方法并不需要使用每一个对象属性 因此 这个方法中的self参数一个完全无用的参数,使用classmethod class A: __cou ...

  2. python面试题之下面这些是什么意思:@classmethod, @staticmethod, @property?

    回答背景知识 这些都是装饰器(decorator).装饰器是一种特殊的函数,要么接受函数作为输入参数,并返回一个函数,要么接受一个类作为输入参数,并返回一个类. @标记是语法糖(syntactic s ...

  3. 初识面向对象(钻石继承,super,多态,封装,method,property,classmethod,staticmethod)

    组合 什么有什么的关系 一个类的对象作为另一个类的对象继承 子类可以使用父类中的名字(静态属性 方法)抽象类和接口类 只能不继承,不能被实例化 子类必须实现父类中的同名方法———规范代码 metacl ...

  4. 初识面向对象-封装、property装饰器、staticmathod(静态的方法)、classmethod(类方法) (五)

    封装 # class Room:# def __init__(self,name,length,width):# self.__name = name# self.__length = length# ...

  5. @classmethod @staticmethod 个人理解

    官方解释 @classmethod 一个类方法把类自己作为第一个实参, 就像一个实例方法把实例自己作为第一个实参. 语法格式: class C: @classmethod def f(cls, arg ...

  6. 面向对象 公有私有 property classmethod staticmethod

    接口类(抽象类)--------就是一种规范 面向对象的私有与公有 对于每一个类的成员而言都有两种形式: 公有成员,在任何地方都能访问 私有成员,只有在类的内部才能方法 私有成员和公有成员的访问限制不 ...

  7. python 全栈开发,Day22(封装,property,classmethod,staticmethod)

    一.封装 封装 : 广义上的 :把一堆东西装在一个容器里 狭义上的 :会对一种现象起一个专门属于它的名字 函数和属性装到了一个非全局的命名空间 —— 封装 隐藏对象的属性和实现细节,仅对外提供公共访问 ...

  8. @classmethod, @staticmethod和@property这三个装饰器的使用对象是在类中定义的函数。下面的例子展示了它们的用法和行为:

    class MyClass(object): def __init__(self): self._some_property = "properties are nice" sel ...

  9. python 之 staticmethod,classmethod,property的区别

    绑定方法和非绑定方法: 普通def定义的都是绑定给对象的方法,对象调用时会自动传入对象本事,而类调用时需手动传入对象. 加上@classmethod装饰器就是绑定给类的方法,会自动传类本身 加上@st ...

  10. Python学习第十六课——静态属性(property, classmethod, staticmethod)

    计算所居住房子的面积 普通写法 class Room: def __init__(self,name,owner,width,length,heigh): self.name=name self.ow ...

随机推荐

  1. js实现存取Map结构的数据

    //控制关联表单元素是否显示 var relateItemMap = {}; for(var i=0; i<formAttributeItemList.length; i++){ var ite ...

  2. 利用mass storage class 做免驱动usb设备.

    当需要使用usb bulk传输,想让设备像串口通讯那样和PC主机通信, 通常需要自己做一个PC端的驱动,比较麻烦. 为避免在pc上编写usb设备驱动的麻烦,可以将设备做成mass storage 类的 ...

  3. 使用git命令 (git reset --hard HEAD) 回退版本信息

    Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100 ...

  4. 动态DNS——本质上是IP变化,将任意变换的IP地址绑定给一个固定的二级域名。不管这个线路的IP地址怎样变化,因特网用户还是可以使用这个固定的域名 这样看的话,p2p可以用哇

    动态域名是因应网络远程访问的需要而产生的一项应用技术.因为没有固定IP,只能运用二级域名来应对经常变化的IP,动态域名的由来因此而产生. 它当前主要应用在:路由器.网络摄像机.带网络监控的硬盘录像机. ...

  5. bzoj2648

    http://www.lydsy.com/JudgeOnline/problem.php?id=2648 kdtree裸题... 抄板子一边抄对了... 挺好理解的,就是说我们先找出中间的元素,然后小 ...

  6. 确定比赛名次(toposort)

    http://acm.hdu.edu.cn/showproblem.php?pid=1285 #include <stdio.h> #include <string.h> ; ...

  7. 【转】linux之type命令

    转自: http://codingstandards.iteye.com/blog/831504 用途说明 type命令用来显示指定命令的类型.一个命令的类型可以是如下之一 alias 别名 keyw ...

  8. HashMap的尾部遍历问题--Tail Traversing

    在看网上HashMap的resize()设计时,提到尾部遍历.   JDK1.7的HashMap在实现resize()时,新table[]的列表采用LIFO方式,即队头插入.这样做的目的是:避免尾部遍 ...

  9. Leetcode0143--Reorder List 链表重排

    [转载请注明]https://www.cnblogs.com/igoslly/p/9351564.html 具体的图示可查看 链接 代码一 /** * Definition for singly-li ...

  10. html5——渐变

    线性渐变 <style> div { width: 700px; height: 100px; /*方向:从右向左*/ /*起始颜色:黄色*/ /*终止颜色:绿色*/ background ...