代码如下:
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 1
@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++也辣鸡咯? |