[python]面向对象高级编程1

__slots__限制class实例能添加的属性

class 类名(object):
    __slots__ = (‘a', ‘b') # 用tuple定义允许绑定的属性名称```
`__slots__`定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。除非在子类中也定义`__slots__`,这样,**子类实例允许定义的属性就是自身的`__slots__`加上父类的`__slots__`**。


**多重继承**
只需要在`class a(多写几个就可以啦,都需要是已经定义过的类)`
`MixIn`只是为了便于区分自行在类名后面加上的,不是一种方法

**重要!!!使用@property**
`@property `将方法变成了属性,就跟写在__init__中一样。因此其不能用()调用,只能直接赋值
这时候你可以决定这个属性可以读写或者只读。
只读: 不加setter方法。
读写:再加一个`@a.setter`方法
另外:没有`__init__`就没有属性,除非在方法中输入数据。


a = 1
b = a
a = 2
b = 1

b指向的不是a而是1这个数据的内存位置,每次给变量赋值都是直接到位置,而不是指向变量a,实例与类也是如此。

定义a为类1
定义实例在类1中
重新定义a为类2
实例仍然在类1中 ```

练习

>>> class Screen(object):
...     @property
...     def width(self):
...         return self.width
...     @width.setter
...     def width(self,value):
...         self.width = value
... 
>>> s = Screen()
>>> s.width = 1024
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in width
  File "<stdin>", line 7, in width
  File "<stdin>", line 7, in width
  [Previous line repeated 495 more times]
RecursionError: maximum recursion depth exceeded```

不知道哪里错了就对比了教程前面的代码,发现是少了下划线,于是加上测试。

class Screen(object):
... @property
... def width(self):
... return self._width
... @width.setter
... def width(self,value):
... self._width = value
...
s = Screen()
s._width = 1024

然后就没有报错,WHY!

原因
因为此时的width方法已经变成了属性,调用的时候直接self.width,所以内部的数据要用self._width更合适,否则会重名造成嵌套死循环
循环次数过多的时候就会造成错误:
RecursionError: maximum recursion depth exceeded

最终结果

class Screen(object):
    @property
    def width(self):
        return self._width
    @width.setter
    def width(self,value):
        self._width = value
    @property
    def height(self):
        return self._height
    @height.setter
    def height(self,value2):
        self._height = value2   
    @property
    def resolution(self):
        return self._height * self._width

s = Screen()
s._width = 1024
s.height = 768
print(s.resolution)```

输出正确啦!这时候的s.height 其实和s._height输出就一样了,一个是方法变成的属性,一个是方法中返回的属性。
然后发现自己还没有给setter加上限制条件。

class Screen(object):
@property
def width(self):
return self._width
@width.setter
def width(self,value):
if not isinstance(value,int):
raise ValueError('width must be an integer!')
if value < 0:
raise ValueError('width must bigger then 0 ')
self._width = value
@property
def height(self):
return self._height
@height.setter
def height(self,value2):
if not isinstance(value2,int):
raise ValueError('height must be an integer!')
if value2 < 0:
raise ValueError('height must bigger then 0')
self._height = value2
@property
def resolution(self):
return self._height * self._width```

然而 ,可是

>>> s = Screen()
>>> s._width = '1'
>>> s.height = 10
>>> s.resolution
'1111111111'```
WHAT???为什么没报错?
然后把教程里的代码试了一下 发现依然不报错..不懂。


------
解决:怪我前面不认真看,结合前面的限制访问章节。
1.其实@property和@a.setter实际上是看做是定义的一个函数,其中的`s._width`可以省略,相当于直接return value,于是如果是使用`s.width`,就相当于是修改value,如果value满足了条件就会提示错误。
2.但是如果是使用`s._width`,其实只是一个传递的媒介,改变了self.width的属性值,但这时候的属性值并不是通过value传入的,而是从中间传入,因此不会出错,因为条件判断的是value的值。
3.其实实际调用方法查看属性的时候,我们是不知道内部函数的,如果你不小心知道了,就可以随便修改,就很不安全。虽然我们默认一个下划线就属于private内部变量,但是全靠自觉。但是不是每个人都是好人的!!
So!如果想要隔绝内部与外部的联系,看限制访问章节,提供了一个方法:
把内部的变量定义为`s.__width`(2个下划线),来限制访问,注意区分,如果是`__init__`之类的前后都有两个下划线的是外部变量。即你在外部如果修改`s.__width`是做不到的,这时候写`s.__width=...`相当于重新加了一个外部变量(属性),即内部和外部的变量名相同但其实不一样。这时候就算你知道了内部函数名也修改不了它的值。它已经被解析为了`_类名__name`

**这就告诉我们,如果是自己写程序的话,在定义方法的时候,一定要注意限制访问**
我把定义中的`_height`改为`__height`有下面的结果:

a = Screen()
a.height
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 14, in height
AttributeError: 'Screen' object has no attribute '_Screen__height'
a.height = '11'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 18, in height
ValueError: height must be an integer!
a.__height = 123
a.__height
123
a.height = 12
a.__height
123
a.height
12

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 1. 使用__slots__ 正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实...
    时间之友阅读 292评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 使用 __slots__ 限制实例属性, 比如,只允许对Student实例添加name和age属性。 然后,我们试...
    时间之友阅读 403评论 0 0
  • 01 上学期女儿班里UOI课正在探究《如何表达你自己》这个主题,邀请家长去给孩子们做个小演讲。我本来想给孩子们读亲...
    芦屋主人阅读 1,182评论 4 17
  • 日行西边落 水去东海流 天下无聊事 瞬间到白头 细数来时路 暗生几许愁 曾欲关山外 却泊太湖舟 经春复又夏 青丝早...
    东风888阅读 146评论 0 0