技术标签: python Python基础语法
“类的帮助信息” #类文档字符串
class_suite #类体
设计一个卖车的4S店,该怎样做呢?
设计一个卖北京现代车的4S店(有很多北京现代品牌的车,比如伊兰特、索纳塔等),该怎样做呢?
这样做,不太好,因为当北京现代又生产一种新类型的车时,又得在CarStore类中修改,有没有好的解决办法呢?
解决办法1.工厂模式:把生产环节重新创建了一个类,这确实比较像是一种编程习惯,但是此种解决方式确实被称作工厂模式
,简单工厂模式
当买车时,有很多种品牌可以选择,比如北京现代、别克、凯迪拉克、特斯拉等,那么此时该怎样进行设计呢?
工厂方法
的定义定义了一个创建对象的
接口
(可以理解为函数),但由子类决定要实例化的类是哪一个,工厂方法
让类的实例化推迟到子类,抽象的CarStore提供了一个创建对象的方法createCar,也叫作工厂方法
。子类真正实现这个createCar方法创建出具体产品。 创建者类不需要知到实际创建的产品是哪一个,选择了使用了哪个子类,自然也就决定了实际创建的产品是什么。
(4)_new__
方法class A(object):
def __init__(self):
print("这是 init 方法")
def __new__(cls):
print("这是 new 方法")
return object.__new__(cls)
A()
总结
__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__
必须要有返回值,返回实例化出来的实例,这点在自己实现__new__
时要特别注意,可以return父类__new__
出来的实例,或者直接是object的__new__
出来的实例
__init__
有一个参数self,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值
我们可以将类比作制造商,__new__
方法就是前期的原材料购买环节,__init__
方法就是在有原材料的基础上,加工,初始化商品环节。
如这段代码(上述例子中截取)
A.某个类只有一个实例、;
B.必须自行创建这个实例;
C.必须自行向整个系统提供这个实例
A.Python的模块就是天然的单例模式,因为模块在第一次导入时,会生成pyc文件,当第二次导入时,就会直接加载.pyc文 件,而不会再次执行模块代码,因此我们只需要把相关的函数和数据定义在一个模块中就可以获得一个单例模块了。
将上面的代码保存在文件test1.py中,然后这样使用。
B.使用__new__
为了类只能出现一个实例,可以使用__new__来控制实例的创建过程
将该类的实例和一个变量_instance关联起来,如果cls._instance为创建实例,否则直接返回cls._instance.
c.使用装饰器
类装饰器可以动态的修改一个类或函数的功能,我们可以使用装饰器来装饰某个类,使其只能生成一个实例。
构造方法值得是创建对象时其本身所运行的函数,,Python使用__int__()方法作为对象的构造方法,用户要在对象内指向对象本身时,可以使用self关键字,即def __int__(self).self代表对象本身。
类本身有许多的内置方法,这些的方法的开头与结尾都带__(双下划线)
本例中c对象并没有sas属性,所以执行c.sas时,就会调用__getattr__\()函数,也叫.兜底函数
在对a.value重新设置值100的时候,会再次进入__setattr__方法。
需要注意的地方是,在重写__setattr__方法的时候千万不要重复调用造成死循环。
如:
这是个死循环。当我们实例化这个类的时候,会进入__init__,然后对value进行设置值,设置值会进入__setattr__方法,而 __setattr__方法里面又有一个self.name=value设置值的操作,会再次调用自身__setattr__,造成死循环。
除了上面调用object类的__setattr__避开死循环,还可以如下重写__setattr__避开循环。
__delattr__()
中的del语句可能会继续调用该方法,最终导致无限递归。所以在__delattr__()
方法中,必须使用__dict__
来获取属性并进行赋值,或者访问父类同名属性。所以,有下面几种方式避免无限递归调用。
例如:
http://www.imooc.com/article/270469(关于getattr等函数的区别以及用法详情)
总结:内置函数XXXattr()管理属性
(A)通过内置函数getattr()、setattr()、delattr()能简单访问、设置、删除对象上的属性。
先看看它们的帮助文档:
getattr(...)
getattr(object, name[, default]) -> value
Get a named attribute from an object;
getattr(x, 'y') is equivalent to x.y.
setattr(obj, name, value, /)
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to ``x.y = v''
delattr(obj, name, /)
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
(B)给定要操作的对象obj以及要操作的属性名称name。对于getattr()来说,如果要操作的属性不存在默认会报错,可以给定一个default参数表示属性不存在时返回该给定属性值。
例如,:
class Person():
def __init__(self, name):
self.name = name
p = Person("malongshuai")
使用getattr()获取name属性和不存在的age属性:
print(getattr(p, "name"))
print(getattr(p, "age", 23))
上面访问age属性时,如果把第三个参数"23"去掉,将抛出异常。
AttributeError: 'Person' object has no attribute 'age'
使用setattr()和delattr()设置和删除属性:
setattr(p, "age", 25) print(p.__dict__)
delattr(p, "age") print(p.__dict__)
。
如图所示:
删除对象的意思就是这个对象所对应的内存空间被释放了
当cat1被删除了,cat2还在,引用计数减掉1而已,内存还不会被释放
因为两个对象的引用都删除了,则内存空间被释放,会调用__del__方
当删除了cat1,内存空间还没有结束,还不会调用__del__方法,当调用完最后一条语句时,内存空间被释放,调用__del__方法
A.创建多个对象的时候触发__del__方法
Python解释器释放实例对象的时候,调用该对象的__del__方法
各个对象被被Python解释器释放对象的时候调用__del__方法
class Person(object):
def __init__(self,name):
self.name = name
def __del__(self):
print("实例对象:%s"%self.name,id(self))
print("python解释器开始回收%s对象了" % self.name)
print("类对象",id(Person))
zhangsan = Person("张三")
print("实例对象张三:",id(zhangsan))
print("------------")
lisi = Person("李四")
print("实例对象李四:",id(lisi))
B.使用del删除引用时的调用情况
当使用d.el 把内存的所有引用删除立刻调用__del__方法
执行效果
el 对象的引用
C,总结:
创建对象后,Python解释器默认调用__init__()方法;
当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
当有1个变量保存了对象的引用时,此对象的引用计数就会加1。
当使用del删除变量指向的对象时,如果对象的引用计数不会加1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
关于 __call__ 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用 对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
如果在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象,在Python中,方法也是一种高等的对象。这意味着他们也可以被传递到方法中就像其他对象一样。这是一个非常惊人的特性。 在Python中,一个特殊的魔术方法可以让类的实例的行为表现的像函数一样,你可以调用他们,将一个函数当做一个参数传到另外一个函数中等等。 __call__(self, [args...]),允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.__call__() 是相同的。注意 __call__ 参数可变。这意味着你可以定义 __call__ 为其他你想要的函数,无论有多少个参数。
__call__ 在那些类的实例经常改变状态的时候会非常有效。调用这个实例是一种改变这个对象状态的直接和优雅的做法。用一个实例来表达最好不过了:
将类的两个实例X与y相减的结果赋值给实例x
类实例是一个Python 对象,它是所有类可以创建的对象,每一个Python对象,都包含识别码,对象类型,属性(也叫作数据成员通过对象名.属性名可以指向某个对象的属性。)方法、数值等属性.
定义一个Car类;就好比有车一个张图纸,那么接下来就应该把图纸交给生成工人们去生成了
python中,可以根据已经定义的类去创建出一个个对象
创建对象的格式为:
对象名 = 类名()
创建对象demo:
# 定义类
class Car:
# 移动
def move(self):
print('车在奔跑...')
# 鸣笛
def toot(self):
print("车在鸣笛...嘟嘟..")
# 创建一个对象,并用变量BMW来保存它的引用
BMW = Car()
BMW.color = '黑色'
BMW.wheelNum = 4 #轮子数量
BMW.move()
BMW.toot()
print(BMW.color)
print(BMW.wheelNum)
使用id()内置函数,可以返回类的识别码(地址)。
使用type()内置函数,可以返回类的对象类型。
isinstance(instance_object,class_object):用来测试一个类实例instance_object是否是class_object的子类。
(1)类属性:类属性就是类对象
所拥有的属性,它被所有类对象
的实例对象
所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象
和实例对象
访问。
(2)实例属性(对象属性):实例属性是实例对象特有的,类对象不能拥有的。实例属性,不能通过类对象调用 类属性和实例属性混合。
class People(object):
address = '山东' #类属性
def __init__(self):
self.name = 'xiaowang' #实例属性
self.age = 20 #实例属性
p = People()
p.age =12 #实例属性
print(p.address) #正确
print(p.name) #正确
print(p.age) #正确
print(People.address) #正确
print(People.name) #错误
print(People.age) #错误
(3)通过实例(对象)去修改类属性
class People(object):
country = 'china' #类属性
print(People.country)
p = People()
print(p.country)
p.country = 'japan'
print(p.country) #实例属性会屏蔽掉同名的类属性
print(People.country)
del p.country #删除实例属性
print(p.country)
(4)总结
类属性
,必须通过类对象
去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性
,这种方式修改的是实例属性
,不会影响到类属性
,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性
,除非删除了该实例属性
。
(5)修改属性:
类方法是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对 象 ,一般以cls作为类对象参数,能够通过实例对象和类对象去访问。
(1)如果有⼀个对象,当需要对其进⾏修改属性时,有2种⽅法
(2)为了更好的保存属性安全,即不能随意修改,⼀般的处理⽅式将属性定义为私有属性 添 加⼀个可以调⽤的⽅法,供调⽤
eg1:类内部普通方法可以访问私有属性和私有方法,然后在调用普通方法来访问私有属性或方法
eg2:
eg3:类的外部访问私有属性或方法:
上例代码分析:
A("王晓琳").printName()调用A类的printName()函数
B(“张一飞”).printName()会先调用B类的printName()函数,因为已经找到了一个printName()函数,所以不会继续往A类找。
C(“刘天佑”).printName()会先调用C类的printName()函数,因为已经找到了一个printName()函数,所以不会继续往B与A类找。
class <派生类名> (基类名)
单继承使用super调用父类方法:super().方法名=父类名.方法名
多继承,即⼦类有多个⽗类,并且具有它们的特征.
语法格式:
class <类名称> [(基类1,基类2,基类3)]
[ “文件字符串"]
<语句>
多继承的使用注意事项
子类从多个父类派生,而子类又没有自己的构造函数时,
Python 中的 MRO —— 方法搜索顺序
Python
中针对 类 提供了一个内置属性 __mro__
可以查看方法搜索顺序method resolution order
,主要用于在多继承时判断 方法、属性 的调用 路径(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
在搜索方法时,是按照 __mro__
的输出结果 从左至右 的顺序查找的
super() 实际上做了啥呢?简单来说就是:提供一个 MRO 以及一个 MRO 中的类 C , super() 将返回一个从 MRO 中 C 之后的类中查找方法的对象。
所谓重写,就是⼦类中,有⼀个和⽗类相同名字的⽅法,在⼦类中的⽅法会 覆盖掉⽗类中同名的⽅法
继承父类的功能,不是想要的则重写父类方法。重写时与要重写的类的名称要相同。
重写父类的方法的目的是为了给他扩展功能
基类中定义的harvest()
方法,无论派生类是什么水果都显示"水果…",如果想要针对不同水果给出不同的提示,可以在派生类中重写harvest()
方法。例如,在创建派生类Orange()
时,重写harvest()
方法如下:
上例中,当调用myClassL类中的handle 函数时,Python会使用有三个参数的函数handle(self,x,y,z).因此只提供一个参数时,会出现错误。
解决这个问题可以根据函数的参数数目决定调用哪一个函数。
(1)所谓类的封装,就是指类将其属性(变量与方法)封装在该类内,只有该类中的成员,才可以使用该类中的其他成员。这种被封装的变量与方法,称为该类的私有变量与私有方法。Python类中的所有变量与方法都是公用的。只要知道该类的名称与该变量或方法的名称,任何外部对象都可以直接存取类中的属性与方法。
(2)类中所有的属性都存储在该类的名称空间内。如果在类中存储了一个全域变量的值,此值就会被放置在该类的名称空间内。即使以后次全域名的值被改变,类内的值仍然不变。
(1)静态方法: 用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。 静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互,是在类中封装的一个额外的功能,相当于类中一个独立的函数。即在静态方法中,不会涉及到类中的方法和属性的操作。可以理解为将静态方法存在此类的名称空间中。
如上,使用静态函数,既可以将获得时间的函数功能与实例解绑,我想获得当前时间的字符串时,并不一定需要实例化对象,此时更像是一种名称空间。
我们可以在类外面写一个简单的方法来做这些,但是这样做就扩散了类代码的关系到类定义的外面,这样写就会导致以后代码维护的困难。
静态方法不需要使用实例对象的属性和方法,也不需要类的属性和方法,所以无论往静态方法中传一个self还是一个cls都会加载对应的资源,而静态方法有不使用,可以节约资源。
对比代码:
静态函数可以通过类名以及实例两种方法调用!
(2)类方法: 默认有个 cls 参数,可以被类和对象调用,需要加上 @classmeothd 装饰器。类方法是将类本身作为对象进行操作的方法。类对象和实例对象都有单独的内存空间存储当调用一个类方法时会先加载这个类的内存空间。他和静态方法的区别在于:不管这个方式是从实例调用还是从类调用,它都用第一个参数把类传递过来。
(3)普通方法(实例方法): 由对象调用,至少有一个self参数,self代表对象的引用,self指向当前的实例对象,所以只要该方法有self参数,在调用此方法的时候,会先把这个歌对象的内存空间加载进来,以便在该方法中使用该实例对象的属性或方法。
类对象不能调用实例方法。
总结:
(1)
实例方法(普通方法):随着实例属性的改变而改变
类方法(无论是类调用还是实例调用):都是类属性的值,不随实例属性的变化而变化
静态方法:不可以访问类属性,故直接输出传入方法的值
(2)从类方法和实例方法的定义形式可以看出,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法,而实例方法的第一个参数是self,那么通过self引用的可能是类属性,也有可能是实例属性,不过在相同的类属性名和实例属性名相同的情况下,,实例属性优先级高,静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类队形来引用。
(3)不允许类名访问实例属性的原因是:当类里有两个或两个以上的实例对象时,该实例对象指向类,但该类如果想访问实例属性时不知道该访问哪一个实例的属性,即找不到,相当于一对多,不知道是哪一个对象访问,对象访问类属性的时相当于多对一,可以明确的找到一个。
文章浏览阅读2w次,点赞3次,收藏10次。允许master节点部署podkubectl taint nodes --all node-role.kubernetes.io/master-_0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
文章浏览阅读10w+次,点赞194次,收藏969次。【确保服务器集群安装和配置已经完成!】前言请根据读者的自身情况,进行相应随机应变。我的三台CentOS7服务器:主机:master(192.168.56.110)从机:slave0(192.168.56.111)从机:slave1(192.168.56.112)每一个节点的安装与配置是相同的,在实际工作中,通常在master节点上完成安装和配置后,然后将安装目录复制到其他节点就可以,..._安装hadoop安装详细步骤
文章浏览阅读176次。npm和nvm分别为Node.js包管理器和版本管理器,本文列举了我在开发过程中最常用的关于这两个工具的命令行。
文章浏览阅读1.1w次。在vue中当我们要实现点击元素动态添加类名时,我们不能像JQ那样去用(xxx.addClass(‘class’).siblings().removeClass(‘class’))实现,那我们应该怎样去做呢解决方案:1.在data里面申明一个属性,默认值最好为数字类型,并且不得大于当前元素+所有兄弟元素的length,可以默认为0(第一个元素选中)2.在当前元素中添加动态class: “:cl..._vue removeclass
文章浏览阅读2.5k次。原文链接:https://www.fearlazy.com/index.php/post/324.htmlQWidget类没有提供查找子控件的方法,但是它爹QObject有。这个方法就是findChild,它长这样:很显然它是一个模板,因此使用时需要提供一个类型,这个类型就是要查找的对象的类型。函数有两个参数:第一个是要查找的对象名(对象名通过setObjectName设置)第二个表示查找直接孩子还是递归查找(可以查找后代的后代),默认Qt::FindChil.._qwidget孩子的类型
文章浏览阅读3.1k次。Unity开发最好的地方就是有各种强大的插件,有哪些插件让大家事半功倍,稳定强大 值得推荐学习和入手呢?Unity5.0之后,制作UI 以及UI的动画,UI特效,大家一般都使用什么插件?或者说有什么好的插件推荐?关于特效制作,大家又有什么好的插件使用经验?请大家分享下各自的项目经验和插件推荐吧。添加评论 分享按投票排序按时间排序_qhierarchy 下载
文章浏览阅读2.3k次。http://baike.baidu.com/view/560845.htm释义 晴天娃娃,又称扫晴娘,扫天婆,放晴娘,晴天和尚。流行于中国农村和日本,是一种悬挂在屋檐上祈求晴天的布偶。 “晴天娃娃”的日文:照る照る坊主 (teru teru bouzu) 照る (てる teru) 坊主 (ぼうず bouzu) 日本的一部动画片《一休和尚_放晴娘图片
文章浏览阅读1.2w次,点赞4次,收藏13次。遇到的问题:系统重装前有个LVM 做过扩容。重装后后手动挂载是可以的。系统重启后挂载失败。 原ubuntu12.04 server 版本分区如下。磁盘配置 由于在升级glibc 导致系统重启后无法启动,做系统修复操作后还是错。于是重装系统。重装工程中对原 ext4分区进行格式化,LVM 未做改动。新系统磁盘分配 系统安装后安装完。执行以下命令后可以正常..._cannot process volume group pve
文章浏览阅读4.3w次,点赞73次,收藏284次。@Autowired和@Resource区别1.提供方不同 @Autowired 是Spring提供的,@Resource 是J2EE提供的。2.装配时默认类型不同 @Autowired只按type装配,@Resource默认是按name装配。3、使用区别(1)@Autowired与@Resource都可以用来装配bean,都可以写在字段或setter方法上(2)@Autowired默认按类型装配,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为fa_@autowired和@resource的区别
文章浏览阅读461次。Ant Design 官方的文档好像没更新,反正是用起来没配成功,官方的文档和代码也是互相矛盾,我来介绍下我是怎么作国际化的。javascriptAntd 的国际化依赖于 yahoo/react-intl。html在看这篇文章以前,建议你们看看 antd/antd-mobile 国际化方案。这篇文章并非一个 Start Guidelines。java文件目录以下nodesrc/locales 里面..._html中输入框是日期但是英文如果改成中文
文章浏览阅读608次,点赞4次,收藏3次。题目链接:Vases and Flowers大致题意给定一个整数n, 表示有n个花瓶(初始为空花瓶), 编号从0~n-1. 有如下两种操作: ①从编号为x的花瓶开始, 要放y朵花, 从前往后一次遍历, 如果是空花瓶则放一朵花在里面, 直至放完所有花或者遍历到最后一个花瓶为止. 倘若此时还有花放不下, 则将它们直接丢弃. ②清理[l, r]区间的所有花瓶, 如果里面有花则将其丢弃对于每个操作①, 需要输出第一个放花的位置和最后一个放花的位置. 倘若一朵花都放不下, 需要输出"Can not pu_vases and flowers
文章浏览阅读4k次,点赞2次,收藏10次。Insight:以洞察为基础OKR的制定,应该基于洞见,它是OKR责任者的洞察呈现,反映OKR责任者对业务的思考,体现OKR责任者的思维模式、专业经验、观察分析能力、创新意识等。OKR的质量,可以反映制定者的思考与洞察的质量。Objective:选择优先事项,确定目标通过洞察,思考一个周期内的重要事项,通过取舍和权衡,选择优先事项。然后,按照目标撰写要求书写。Key Results:对照..._okr撰写思路