代码如下:
class Student(object): def __init__(self,name,age,school): self.__name = name self.__age = age self.__school = school def toString(self): print('我是%s,我%s 岁了,在%s 上学.' %(self.__name,self.__age,self.__school)) class XiaoMing(Student): def __init__(self,name,age,school): self.__name = name self.__age = age self.__school = school ''' 覆写父类 toString()方法''' # def toString(self): # print('我是%s,我%s 岁了,在%s 上学.' %(self.__name,self.__age,self.__school))
''' 接受 Student 任何子类对象''' def fun(stu): stu.toString() ###测试 xm = XiaoMing('小明',25,'北大') fun(xm)
按照继承, XiaoMing
继承自 Student
, 且属性是一模一样的,则toString
函数再写一遍是多余的, 道理讲,应该直接使用父类的 toString
方法,就可以了, 但是我去掉XiaoMing
的toString
方法后,就找不到 自身实例的私有属性了, 因为 python 解释器将私有属性名改变了, 我就觉得在这里多态基本都是废的, 代码复用完全无效了,
顺便问下大家, 继承/多态 在python中还有那些有用的地方?
经过各位大神的提示, 再翻阅了各个博客 官方文档 好像都是单下划线[_]标识 私有 , 然后使用
super().__init__(name,age)
实现继承,个人觉得这里好别扭啊 ,python提供了 __
限制访问,但是这种方式在继承上又支持一半, 真是好不爽啊, 虽然__
也不安全,但是相比 _
感觉_
就是赤身裸体站在别人面前。
最终代码像这样:
class Person(object): def __init__(self,name,age): self._name = name self._age = age def toString(self): print(self) print('hello,%s,%s' %(self._name, self._age)) class Student(Person): def __init__(self,name,age): super().__init__(name,age) def fun(p): p.toString() stu = Student('学生1',23) fun(stu) ## hello,学生1,23
强迫症犯了 ,这点好别扭啊 !!!!! 啊啊啊啊啊啊啊啊
再吐槽下python, 木有 ;
木有 {
}
大爷的!!!!! 变量都不知道在哪里声明的 javasctipt 好歹还有一个 var
let
大爷的~~~~~~~~
1 arischow 2017-02-04 16:32:49 +08:00 你这里为什么要重写一次 XiaoMing 的 __init__? 如果你必须重写 __init__,还可以看下这个: http://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html |
![]() | 3 cszeus 2017-02-04 16:50:05 +08:00 class XiaoMing(Student): def __init__(self,name,age,school): Student.__init__(self, name, age, school) |
![]() | 4 ijustdo 2017-02-04 16:56:28 +08:00 def __str__(self): return '我是%s,我%s 岁了,在%s 上学.' %(self.__name,self.__age,self.__school) 看代码 你 toString 也多余 一般都直接 __str__ 然后你 str(实例)或者 print 实例 看看呢 |
![]() | 6 dwood 2017-02-04 16:59:06 +08:00 via Android 楼主这是用父类的来访问子类的成员变量了。其他语言也不是这么继承的吧…子类需要调用父类的构造函数。 |
![]() | 7 palmers OP @cszeus 不行 还是提示 `AttributeError: 'XiaoMing' object has no attribute '_Student__name'` |
![]() | 9 chris5641 2017-02-04 17:02:11 +08:00 class XiaoMing(Student): def __init__(self,name,age,school): super().__init__(name,age,school) |
![]() | 12 palmers OP @arischow 1#说不写构造 我就尝试了直接 pass 不行的, 我想的是, 子类如果要编写一个和父类一模一样的方法, 那子类应该就不用再重复编写了, 至于 self 应该在传递 xm 的时候就应该指向 xm 对象才对的 ,但是 根据错误提示 还是指向了 Student 对象了 |
![]() | 13 chris5641 2017-02-04 17:12:35 +08:00 LZ 你的命名有问题,如果一般的私有变量用一个下划线,两个下划线的变量通过继承是无法被覆盖的 http://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p05_encapsulating_names_in_class.html |
![]() | 14 dwood 2017-02-04 17:13:38 +08:00 via Android 用的 python2 吧, super(Student,self).__init__(name,age,school)。 |
![]() | 17 dwood 2017-02-04 17:26:56 +08:00 那 def __init__(self,name,age,school): super().__init__(name, age, school) 这样写没问题啊。 |
![]() | 18 Allianzcortex 2017-02-04 19:02:34 +08:00 ![]() @palmers pip 和 virtualenv 的作者说: Never, ever use two leading underscores.This is annoying private. 所以这个就别管 PEP8 了,@kennethreitz 写的代码都是用单下划线。 Py3.5+ 后用 super().__init__(*args,**kwargs) 来做到多继承。还有.......toString()......我猜有 Java/Scala 背景? |
![]() | 19 phithon 2017-02-04 19:08:33 +08:00 django 选手表示,多继承撑起了 class based view 的一片天…… 登录验证只需继承一个 LoginRequiredMixin ,需要表单的话再继承一下 FormMixin ,需要模板的话再继承一下 TemplateResponseMixin ,然后选择一个基本父类比如 View 、 ProcessFormView 即可完成一个 view 的编写。 剩下的事就是写写这些父类必须的属性即可,代码量能压缩到最少。 |
![]() | 20 Allianzcortex 2017-02-04 19:12:19 +08:00 @phithon 嗯, Mixin 和 CBVS 是绝配啊,避免了引入多个 utils 函数的烦恼。但我用的最多的还是 FBVS ⊙⊙b 。。。。。 |
![]() | 21 guyskk 2017-02-04 19:15:37 +08:00 via Android @palmers 单下划线也看做私有, Python 里面没有真正的私有,双下划线的属性一样有办法获取。 |
![]() | 22 edimetia3d 2017-02-04 19:15:39 +08:00 |
![]() | 23 palmers OP @Allianzcortex 哈哈哈哈 是啊 java 我看 python 很多特性感觉都是 Javascript 和 java 的结合体 那按照你说 意思 最根本的原因是我使用了双下划线导致属性私有不能继承,所以在 toString 方法中 self 指向不到动态传递的对象 xm 上,是这样的吧?但是我在父类中 toString 方法中打印了 self 确实是子类对象呢? |
![]() | 25 Allianzcortex 2017-02-04 21:07:40 +08:00 @palmers 呃..什么..Python 里的 self 就等价于 Java 里的 this ,唯一不同的是 Java 已经在每个方法里把实例绑定了,不需要手动声明 this ,而 Python 的设计理念要求程序员手动把类里面方法的第一个参数显式(explicit is better than implicit 这种)声明(不用 self 而用 foo/bar/abc/def 等其他变量来声明也可以,只是 self 是约定俗成的一种表现方法)。 |
![]() | 26 palmers OP @Allianzcortex 嗯嗯 这个我也测试过 是这样的 我个人觉得这是因为 python 动态语言特性导致的。 在 python 中,动态调用方法 其实是假象,只要方法签名相同,就能找到这个方法, 即使没有继承关系,就像 javasctipt 可以将一个函数随意的绑定到别的对象上。 |
27 PythonAnswer 2017-02-04 21:29:37 +08:00 要记住, python 的世界全部是 public 。忘掉 java 就能写出来简洁的东西了。不然写出来的东西只能长成 java 的样子。 |
![]() | 28 junnplus 2017-02-04 21:35:01 +08:00 via iPhone 自己把其他语言的惯性思维带到学 python 上,怪 python 咯 |
![]() | 29 workwonder 2017-02-04 21:50:21 +08:00 via Android 对我来说, Javascript 才是略奇怪的。 |
![]() | 30 palmers OP @PythonAnswer 嗯嗯 记住了 |
![]() | 32 palmers OP @workwonder Javascript 不仅仅是奇怪呀 |
![]() | 33 mseasons 2017-02-04 22:35:52 +08:00 不用再写一遍函数,可以用父类的函数的。 |
34 weyou 2017-02-04 23:10:58 +08:00 via Android 如果你指的是传统语言的多态, python 是不支持的, python 支持的是鸭子类型,这可比多态强大多了。传统多态接受的对象必须是有相同的基类的,而 python 只要查找到对象支持某种相同的方法就可以调用。比如飞机对象有方法是“ fly()”,鸟也有相同的方法“ fly()”,你就可以写一个函数“ dofly(obj): obj.fly()”,同时接受飞机对象和鸟对象, 尽管它们不是同一个基类。 |
35 weyou 2017-02-04 23:16:18 +08:00 via Android 看了代码,感觉楼主就是想一对一翻译一下 Java 的代码,尽管 oop 思想是一致的,但要做到 pythonic 还是要系统的按部就班的学习一下 python |
36 greatonce 2017-02-04 23:50:52 +08:00 __init__ 不是构造方法,这个是初始方法 __new__ 才是构造方法 |
37 Gem 2017-02-05 00:28:27 +08:00 看到 toString(),莫名其妙的想到了 Scala... |
![]() | 38 yinian1992 2017-02-05 03:40:54 +08:00 toString 的话可以重写 __str__ 。 |
![]() | 39 20015jjw 2017-02-05 03:44:20 +08:00 via Android 建议你在骂语言辣鸡的之前 好好学一下 |
40 tairan2006 2017-02-05 07:01:49 +08:00 via Android Python 的思路和 Java 完全不一样…另外楼主你的用法有问题 |
![]() | 41 ryd994 2017-02-05 08:36:48 +08:00 via Android 道理很简单,因为你在子类里又声明了一套同名变量,而父类里试图打印的是父类里的变量。名可名非常名 你怎么不在 C++里继承然后声明同名变量试试? C++也辣鸡咯? |