初学 Python ,学习到 Python 继承,觉得继承/多态在 Python 中基本是废的,麻烦大家帮我解惑, 非常感谢大家!下附疑惑代码 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
palmers
V2EX    Python

初学 Python ,学习到 Python 继承,觉得继承/多态在 Python 中基本是废的,麻烦大家帮我解惑, 非常感谢大家!下附疑惑代码

  •  
  •   palmers 2017-02-04 16:27:57 +08:00 6623 次点击
    这是一个创建于 3182 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下:

    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方法,就可以了, 但是我去掉XiaoMingtoString方法后,就找不到 自身实例的私有属性了, 因为 python 解释器将私有属性名改变了, 我就觉得在这里多态基本都是废的, 代码复用完全无效了,

    顺便问下大家, 继承/多态 在python中还有那些有用的地方?

    第 1 条附言    2017-02-04 21:13:53 +08:00

    经过各位大神的提示, 再翻阅了各个博客 官方文档 好像都是单下划线[_]标识 私有 , 然后使用

     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 

    强迫症犯了 ,这点好别扭啊 !!!!! 啊啊啊啊啊啊啊啊

    第 2 条附言    2017-02-04 21:23:02 +08:00

    再吐槽下python, 木有 ; 木有 { } 大爷的!!!!! 变量都不知道在哪里声明的 javasctipt 好歹还有一个 var let 大爷的~~~~~~~~

    42 条回复    2017-02-05 13:16:15 +08:00
    arischow
        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
    palmers
        2
    palmers  
    OP
       2017-02-04 16:39:27 +08:00   1
    @arischow 咦??可以不写这个构造方法吗? 我试试 我还不知道这个啊  谢谢!!~  我看看你给的链接
    cszeus
        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)
    ijustdo
        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 实例 看看呢
    palmers
        5
    palmers  
    OP
       2017-02-04 16:58:30 +08:00
    @arischow 尝试了几次不知道怎么写 你能代码展示下吗? 谢谢了
    dwood
        6
    dwood  
       2017-02-04 16:59:06 +08:00 via Android
    楼主这是用父类的来访问子类的成员变量了。其他语言也不是这么继承的吧…子类需要调用父类的构造函数。
    palmers
        7
    palmers  
    OP
       2017-02-04 17:00:36 +08:00
    @cszeus 不行 还是提示 `AttributeError: 'XiaoMing' object has no attribute '_Student__name'`
    arischow
        8
    arischow  
       2017-02-04 17:01:43 +08:00 via iPhone
    @palmers 满足你需求的话,直接给 class 写个 pass 就好了?
    chris5641
        9
    chris5641  
       2017-02-04 17:02:11 +08:00
    class XiaoMing(Student):
    def __init__(self,name,age,school):
    super().__init__(name,age,school)
    palmers
        10
    palmers  
    OP
       2017-02-04 17:02:38 +08:00
    @ijustdo 恩恩 我这个只是用来测试的  继承子类覆盖父类方法  按照道理,子类没有父类有就可以了,一样可以调用的
    palmers
        11
    palmers  
    OP
       2017-02-04 17:03:35 +08:00
    @chris5641 这种我尝试过了 不行的
    palmers
        12
    palmers  
    OP
       2017-02-04 17:06:12 +08:00
    @arischow   1#说不写构造 我就尝试了直接 pass 不行的, 我想的是, 子类如果要编写一个和父类一模一样的方法, 那子类应该就不用再重复编写了, 至于 self 应该在传递 xm 的时候就应该指向 xm 对象才对的 ,但是 根据错误提示 还是指向了 Student 对象了
    chris5641
        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
    dwood
        14
    dwood  
       2017-02-04 17:13:38 +08:00 via Android
    用的 python2 吧, super(Student,self).__init__(name,age,school)。
    palmers
        15
    palmers  
    OP
       2017-02-04 17:20:14 +08:00
    @chris5641 但是使用单下滑下[_]就变成 public 了.
    palmers
        16
    palmers  
    OP
       2017-02-04 17:20:51 +08:00
    @dwood 是 Python 3.6.0
    dwood
        17
    dwood  
       2017-02-04 17:26:56 +08:00
    那 def __init__(self,name,age,school):
    super().__init__(name, age, school) 这样写没问题啊。
    Allianzcortex
        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 背景?
    phithon
        19
    phithon  
       2017-02-04 19:08:33 +08:00
    django 选手表示,多继承撑起了 class based view 的一片天……
    登录验证只需继承一个 LoginRequiredMixin ,需要表单的话再继承一下 FormMixin ,需要模板的话再继承一下 TemplateResponseMixin ,然后选择一个基本父类比如 View 、 ProcessFormView 即可完成一个 view 的编写。
    剩下的事就是写写这些父类必须的属性即可,代码量能压缩到最少。
    Allianzcortex
        20
    Allianzcortex  
       2017-02-04 19:12:19 +08:00
    @phithon 嗯, Mixin 和 CBVS 是绝配啊,避免了引入多个 utils 函数的烦恼。但我用的最多的还是 FBVS ⊙⊙b 。。。。。
    guyskk
        21
    guyskk  
       2017-02-04 19:15:37 +08:00 via Android
    @palmers 单下划线也看做私有, Python 里面没有真正的私有,双下划线的属性一样有办法获取。
    edimetia3d
        22
    edimetia3d  
       2017-02-04 19:15:39 +08:00
    @chris5641 正解.

    我翻译一下:
    派生类构造时没有调用基类的构造函数,导致基类成员没有被创建,直接输出自然报错.
    palmers
        23
    palmers  
    OP
       2017-02-04 21:02:08 +08:00
    @Allianzcortex 哈哈哈哈 是啊 java 我看 python 很多特性感觉都是 Javascript 和 java 的结合体 那按照你说 意思 最根本的原因是我使用了双下划线导致属性私有不能继承,所以在 toString 方法中 self 指向不到动态传递的对象 xm 上,是这样的吧?但是我在父类中 toString 方法中打印了 self 确实是子类对象呢?
    palmers
        24
    palmers  
    OP
       2017-02-04 21:03:01 +08:00
    @guyskk 这个我了解, 但是 。。 可能我有强迫症 唉 算了 我以后就单下划线标识私有吧[_]
    Allianzcortex
        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 是约定俗成的一种表现方法)。
    palmers
        26
    palmers  
    OP
       2017-02-04 21:18:52 +08:00
    @Allianzcortex 嗯嗯 这个我也测试过 是这样的 我个人觉得这是因为 python 动态语言特性导致的。 在 python 中,动态调用方法 其实是假象,只要方法签名相同,就能找到这个方法, 即使没有继承关系,就像 javasctipt 可以将一个函数随意的绑定到别的对象上。
    PythonAnswer
        27
    PythonAnswer  
       2017-02-04 21:29:37 +08:00
    要记住, python 的世界全部是 public 。忘掉 java 就能写出来简洁的东西了。不然写出来的东西只能长成 java 的样子。
    junnplus
        28
    junnplus  
       2017-02-04 21:35:01 +08:00 via iPhone
    自己把其他语言的惯性思维带到学 python 上,怪 python 咯
    workwonder
        29
    workwonder  
       2017-02-04 21:50:21 +08:00 via Android
    对我来说, Javascript 才是略奇怪的。
    palmers
        30
    palmers  
    OP
       2017-02-04 22:13:49 +08:00
    @PythonAnswer 嗯嗯 记住了
    palmers
        31
    palmers  
    OP
       2017-02-04 22:14:10 +08:00
    @junnplus 是的 怪 python
    palmers
        32
    palmers  
    OP
       2017-02-04 22:14:38 +08:00
    @workwonder Javascript 不仅仅是奇怪呀
    mseasons
        33
    mseasons  
       2017-02-04 22:35:52 +08:00
    不用再写一遍函数,可以用父类的函数的。
    weyou
        34
    weyou  
       2017-02-04 23:10:58 +08:00 via Android
    如果你指的是传统语言的多态, python 是不支持的, python 支持的是鸭子类型,这可比多态强大多了。传统多态接受的对象必须是有相同的基类的,而 python 只要查找到对象支持某种相同的方法就可以调用。比如飞机对象有方法是“ fly()”,鸟也有相同的方法“ fly()”,你就可以写一个函数“ dofly(obj): obj.fly()”,同时接受飞机对象和鸟对象, 尽管它们不是同一个基类。
    weyou
        35
    weyou  
       2017-02-04 23:16:18 +08:00 via Android
    看了代码,感觉楼主就是想一对一翻译一下 Java 的代码,尽管 oop 思想是一致的,但要做到 pythonic 还是要系统的按部就班的学习一下 python
    greatonce
        36
    greatonce  
       2017-02-04 23:50:52 +08:00
    __init__ 不是构造方法,这个是初始方法

    __new__ 才是构造方法
    Gem
        37
    Gem  
       2017-02-05 00:28:27 +08:00
    看到 toString(),莫名其妙的想到了 Scala...
    yinian1992
        38
    yinian1992  
       2017-02-05 03:40:54 +08:00
    toString 的话可以重写 __str__ 。
    20015jjw
        39
    20015jjw  
       2017-02-05 03:44:20 +08:00 via Android
    建议你在骂语言辣鸡的之前 好好学一下
    tairan2006
        40
    tairan2006  
       2017-02-05 07:01:49 +08:00 via Android
    Python 的思路和 Java 完全不一样…另外楼主你的用法有问题
    ryd994
        41
    ryd994  
       2017-02-05 08:36:48 +08:00 via Android
    道理很简单,因为你在子类里又声明了一套同名变量,而父类里试图打印的是父类里的变量。名可名非常名
    你怎么不在 C++里继承然后声明同名变量试试? C++也辣鸡咯?
    palmers
        42
    palmers  
    OP
       2017-02-05 13:16:15 +08:00
    @greatonce 非常感谢! 我知道了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1187 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 17:51 PVG 01:51 LAX 10:51 JFK 13:51
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86