python早期学习笔记
python早期学习笔记:
1 ''' 2 类和对象 3 类其实就是模板,对象就是通过模板造出来的看得见摸得着的东西, 4 如通过图纸造飞机,通过月饼模子印月饼。 5 类Class的组成: 6 1、类的名称:类名 7 2、类的属性:一组数据,变量 8 3、类的方法:进行操作的方法或行为 9 如人类,身高年龄是人的属性,吃喝拉撒是行为 10 11 12 ''' 13 14 class P: 15 def eat(self): 16 print("在吃东西。。。") 17 def introduce(self): 18 print("%s的年龄是:%s"%(self.name,self.age)) 19 def print_self(self): 20 print(self) 21 22 # 创建对象 23 tom = P() 24 # tom这个对象保存的是一串内存地址。 25 print(tom) # <__main__.P object at 0x0000023433CFEB00> 26 #调用对象里的方法 27 tom.eat() 28 # python内存分析: https://zhuanlan.zhihu.com/p/59599988 29 # 给对象添加属性 30 tom.name = "汤姆" 31 tom.age = 18 32 tom.introduce() 33 34 # 注意: 35 # 在类中定义的方法默认是实例方法,该方法与普通的函数只有一个区别,那就是他们必须要 36 # 有一个额外的第一参数,该参数保存的是类的实例化对象在计算机中的内存地址,通常被命名为self,也可以是其他名。 37 # 没有self参数的话,调用方法时会报错:takes 0 positional arguments but 1 was given 38 tom.print_self() #<__main__.P object at 0x000001D6BD4A1F28> 39 # 相当于tom.introduce(tom) 40 41 42 # __init__(self)方法 43 # 初始化方法,当类中有init方法时,在创建类的对象的时候会python会自动调用 44 # init方法,并把对象的引用(内存地址)传进去。在这个方法里面就可以直接初始化 45 # 一些属性,而不用在外面去添加了。在创建对象的时候直接把属性值通过参数传进来 46 47 48 class P1: 49 def __init__(self,name,age): 50 self.name = name 51 self.age = age 52 53 def __str__(self): 54 return "哈哈哈" 55 def introduce(self): 56 print("%s的年龄是:%s"%(self.name,self.age)) 57 58 lyf = P1("刘亦菲",22) 59 lyf.introduce() #刘亦菲的年龄是:22 60 61 # __str__(self)方法 62 # 当直接打印对象的时候,得到的是一个内存地址,当类中有str方法时,再去打印对象 63 # 得到的是str方法中return的值。 64 print(lyf) #哈哈哈 65 66 # 延伸:以前多个函数可以共用一个全局变量,现在一个对象里面的多个方法可以共用一个属性, 67 # 感觉对象就是把全局变量和函数打个包,多个对象就打多个包,直接互不影响。 68 69 70 # 隐藏属性 71 # 保护属性安全,即不能随意修改,一般处理方法为:1、将属性定义为私有属性;2、添加一个可调用的方法 72 # 73 # 直接对属性赋值可能会出现在代码语法上没问题,但在逻辑上行不通的问题。例如年龄 74 # 被错误的设置成222岁。可以在类里通过方法对传入的参数进行判断。 75 76 class P2: 77 78 def set_age(self,age): 79 if age>0 and age<=100: 80 self.age = age 81 else: 82 self.age = "年龄不合法" 83 84 def get_age(self): 85 return self.age 86 87 lyf = P2() 88 lyf.set_age(222) 89 age = lyf.get_age() 90 print(age) #年龄不合法 91 92 93 #私有方法 94 #当某个核心方法不想被外界直接调用,可以将此方法变为私有方法。再通过其他方法间接调用。 95 class P3: 96 # 私有属性 97 def __init__(self,name,age): 98 self.name = name 99 self.__age = age 100 # 私有方法 101 def __get_money(self): 102 print('正在取钱') 103 # 公有方法 104 def get_money(self,password): 105 ''' 通过判断后决定是否调用私有方法''' 106 if password==123456: 107 self.__get_money() 108 print(self.__age) #调用私有属性 109 else: 110 print("密码错误") 111 112 lyf=P3("刘亦菲",22) 113 lyf.get_money(123) #密码错误 114 lyf.get_money(123456) #正在取钱 115 print(lyf.name) # 刘亦菲 116 # print(lyf.__age) 报错 117 118 # __del__(self)方法 119 # 如果对象的引用计数变为0,就会自动调用__del__()方法 120 # getrefcount()方法可以查看引用计数 121 import sys 122 class P4: 123 def __del__(self): 124 print("over") 125 126 p1 = P4() 127 p2 = p1 128 print(sys.getrefcount(p1))# 3,该方法本身有一个变量接收对象,所以引用计数多1 129 print(p1,p2) 130 # 此时对象的引用计数为2,p1p2保存的是同一个地址。 131 del p1 132 #删除p1,引用计数变为1,对象还存在 133 print(p2) 134 del p2 135 #删除p2,引用计数为0,对象在系统中被删除,内存释放,此时执行类里面的__del__() 136 print("这句话出现在over后面") 137 138 139 # 继承 140 # 类可以继承自另一个类,继承是一种创建新的类的方式,可以减少代码冗余、提高重用性 141 # 如果一个类没有继承任何类,则默认继承object类。 142 class Fu(object): 143 a=1 144 print("我是父类,我继承自基类") 145 #注意:类在定义的时候就执行类体代码,执行顺序是从上到下 146 class Zi(Fu): 147 def zi(self): 148 print("我是子类,我继承自父类") 149 150 151 class Sun(Zi): 152 def sun(self): 153 print("我是孙子类,我继承自子类") 154 sun = Sun() 155 print(sun.a) # 1 156 sun.zi() #我是子类,我继承自父类 157 158 159 # 重写 160 # 当子类出现了跟父类同名的属性和方法时,优先调用子类的 161 class Dog: 162 a=1 163 def eat(self): 164 print("吃骨头") 165 166 class Uzi(Dog): 167 a=2 168 def eat(self): 169 print("uzi不吃骨头") 170 # Dog.eat(self) 171 172 uzi = Uzi() 173 uzi.eat() #uzi不吃骨头 174 print(uzi.a) #2 175 # 如果非要调用Dog类的eat该怎么办呢? 176 # 调用被重写的方法: 177 # 1、类名.方法名(self) 178 # 2、super().方法名() 179 class Animal: 180 def eat(self): 181 print("吃东西") 182 183 class Dog(Animal): 184 a=1 185 def eat(self): 186 print("吃骨头") 187 188 class Uzi(Dog): 189 a=2 190 def eat(self): 191 print("uzi不吃骨头") 192 Dog.eat(self) 193 Animal.eat(self) 194 super().eat() 195 uzi = Uzi() 196 uzi.eat() 197 198 # 注意,用类名.方法名(self)有弊端,假如类名改了,那继承自它的所有类调用时都需要修改类名, 199 # 很麻烦。并且在多继承下还会出现重复调用的问题。这时候用super()就好了。 200 201 202 # 私有方法和属性的继承 203 class A: 204 def __init__(self): 205 self.num1 = 1 206 self.__num2 = 2 207 def test1(self): 208 print("test1") 209 def __test2(self): 210 print("test2") 211 def test3(self): 212 self.__test2() 213 print(self.__num2) 214 215 216 class B(A): 217 def test4(self): 218 self.__test2() 219 print(self.__num2) 220 221 222 b=B() 223 b.test3() 224 # b.test4() 225 # b.__test2() 226 227 # 私有方法和属性不会被继承,子类中的方法不能调用父类的私有方法和私有属性,父类的方法 228 # 可以直接调用私有方法和私有属性。 229 230 231 232 # 多继承 233 class Base(object): 234 def test(self): 235 print("base") 236 class A(Base): 237 def test(self): 238 print("A") 239 class B(Base): 240 def test(self): 241 print("B") 242 class C(object): 243 def test(self): 244 print("C") 245 class D(A,B,C): 246 def test(self): 247 print("D") 248 249 d = D() 250 d.test() # D 251 print(D.__mro__) # 类名.__mro__ :查看调用方法的顺序 252 # (<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, 253 # <class '__main__.Base'>, <class '__main__.C'>, <class 'object'>) 254 255 256 257 258 # 多态 259 # 多态是建立在继承和重写的基础上的。 260 # 面向对象三要素:封装继承多态 261 class A(object): 262 def print_self(self): 263 print("====A====") 264 265 266 class B(A): 267 def print_self(self): 268 print("====B====") 269 270 class C(object): 271 def print_self(self): 272 print("====C====") 273 274 def test(obj): 275 obj.print_self() 276 a=A() 277 b=B() 278 c=C() 279 test(a) 280 test(b) 281 test(c) 282 ''' 283 定义test函数的时候并未声明传入的是什么类型的参数,不过只要传入的实例对象 284 里面有print_self方法即可,不管他是A类型还是A的子类B类型还是C类型。在真正调用 285 的时候才会确定实际的类型。这就是多态的体现。即见人说人话见鬼说鬼话。 286 注意:当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型 287 和Python自带的数据类型,比如str、list、dict没什么两样。 288 ''' 289 print(type(a)) # <class '__main__.A'> 290 print(type(c)) # <class '__main__.C'> 291 292 293 294 # 实例属性和类属性 295 class Dog(object): 296 a = 1 297 __b = 2 298 def __init__(self,name): 299 self.name = name 300 301 302 d=Dog("zw") # 创建实例对象 303 print(d.a) # 因为实例对象没有属性a,所以用到类对象的属性a 304 print(Dog.a) #直接调用类的属性 305 d.a = 18 # 给实例对象添加实例属性a 306 print(d.a) # 实例对象有属性a则不用类属性a 307 print(Dog.a) # 类属性a不变,还是1 308 Dog.a = 11 # 修改类属性 309 print(Dog.a) # 11 310 311 ''' 312 总结: 313 实例属性属于实例对象所有,各实例对象之间互不干扰; 314 类属性属于类对象所有,所有实例对象共享类属性; 315 取名时尽量避免实例属性和类属性重名。 316 ''' 317 318 # 类方法、实例方法、静态方法 319 320 # 对类属性进行操作常用到类方法 321 # 为避免代码中函数和类并存的乱象,将普通函数转为静态方法放到类里面 322 323 class Test(object): 324 num = 0 325 # 实例方法 326 def __init__(self): 327 pass 328 329 # 类方法,加装饰器 330 @classmethod 331 def modify_num(cls): 332 cls.num+=100 333 334 # 静态方法,加装饰器 335 @staticmethod 336 def sta(): 337 print("hahahhahahah") 338 339 t = Test() 340 # 直接通过类名调用类方法: 341 Test.modify_num() 342 print(Test.num) # 100 343 # 通过类创建出来的对象调用类方法: 344 t.modify_num() 345 print(Test.num) # 200 346 347 #调用静态方法:两者都行 348 Test.sta() 349 t.sta() 350 351 352 353 # __new__(cls)方法 354 355 class Test(object): 356 def __init__(self): 357 pass 358 359 def __new__(cls): # 此处接收的实参为类对象的引用 360 return object.__new__(cls) 361 # 调用基类的new方法来创建实例对象 362 363 print(id(Test)) 364 t=Test() 365 print(id(t)) 366 ''' 367 程序从上往下: 368 1、先创建一个类对象,Test存引用; 369 2、执行 Test(),传入实参Test引用,调用__new__方法来创建实例对象, 370 返回实例对象的引用; 371 3、执行__init__方法,传入实例对象的引用; 372 373 创建和初始化两个方法合起来相当于Java里面的构造方法。 374 ''' 375 376 # 单例 377 # 做到类的实例对象只创建一次 378 # 让类属性保存第一次创建的实例的引用,以后每次调用new方法都不会去创建新的实例, 379 # 而是返回第一次的实例 380 class Dog(object): 381 __instance = None 382 def __new__(cls): 383 if cls.__instance == None: 384 cls.__instance = object.__new__(cls) 385 return cls.__instance 386 else: 387 return cls.__instance 388 389 a = Dog() 390 print(id(a)) #2884513002720 391 b = Dog() 392 print(id(b)) #2884513002720 393 394 # 单例初始化 395 396 class Dog(object): 397 __instance = None 398 def __new__(cls,name): 399 # 这个形参name别忘了,虽然用不到 400 if cls.__instance == None: 401 cls.__instance = object.__new__(cls) 402 return cls.__instance 403 else: 404 return cls.__instance 405 def __init__(self,name): 406 self.name = name 407 408 a=Dog("张三") 409 print(a.name) #张三 410 b=Dog("李四") 411 print(b.name) #李四 412 print(a.name) #李四 每次初始化覆盖上次的实例属性的值 413 414 # 只初始化一次 415 class Dog(object): 416 __instance = None 417 __init_flag = False 418 def __new__(cls,name): 419 # 这个形参name别忘了,虽然用不到 420 if cls.__instance == None: 421 cls.__instance = object.__new__(cls) 422 return cls.__instance 423 else: 424 return cls.__instance 425 def __init__(self,name): 426 if Dog.__init_flag == False: 427 self.name = name 428 Dog.__init_flag = True 429 430 a=Dog("张三") 431 print(a.name) #张三 432 b=Dog("李四") 433 print(b.name) #张三 434 435 436 # 异常处理 437 try: 438 #这里输入有潜在异常的代码,要有针对性 439 1/0 440 print(wy) 441 442 except(NameError,FileNotFoundError): 443 print("捕获到这两种异常后的处理操作。。。") 444 except Exception as err_message: 445 print("这里可捕获除上面两个之外的所有异常。。。") 446 print(err_message) # 输出原来的异常信息 447 else: 448 print("没有异常才会执行这个") 449 finally: 450 print("无论有没有异常都会执行finally") 451 452 # 出现1/0的异常后立马执行Exception,然后finally,print(wy)不会执行。 453 # Exception是所有异常的基类 454 455 # 异常传递 456 def test1(): 457 print(haha) 458 459 def test2(): 460 try: 461 test1() 462 except Exception as a: 463 print("处理异常") 464 print(a) # name 'haha' is not defined 465 466 test2() 467 468 469 # 自定义异常并抛出异常 470 """ 471 class InputException(Exception): 472 ''' 自定义异常类,继承自异常基类Exception''' 473 def __init__(self,age,max_age): 474 self.age = age 475 self.max_age = max_age 476 477 class Test(object): 478 def __init__(self,switch): # 异常处理开关 479 self.switch = switch 480 def handle(self): 481 try: 482 age = input("请输入你的年龄:") 483 if int(age)>=120: 484 # 创建自定义异常类的实例对象,传参,抛出自定义异常 485 raise InputException(age,120) 486 487 except InputException as result: 488 ''' 捕获异常,将实例对象的引用存入到变量result ''' 489 if self.switch: 490 print("InputException:输入的年龄%s不在合理范围之内,最大为%d"%(result.age,result.max_age)) 491 else: 492 print("异常捕获开关已关闭") 493 t1=Test(False) 494 t1.handle() 495 t2=Test(True) 496 t2.handle() 497 """ 498 499 ''' 500 请输入你的年龄:150 501 异常捕获开关已关闭 502 请输入你的年龄:150 503 InputException:输入的年龄150不在合理范围之内,最大为120 504 ''' 505 506 # 模块 507 508 ''' 509 # 新建一个mod1.py文件,里面代码如下: 510 def test1(): 511 print("这是mod1模块里的test1函数体") 512 513 print(__name__) 514 if __name__ == "__main__": 515 test1() 516 517 ''' 518 import mod1 # 导入新建的模块 519 mod1.test1() 520 521 # __name__方法: 522 # 当自己调用自己时,__name__ == "__main__"; 523 # 当其他模块调用自己时,__name__ == "自己模块名" 524 525 # 模块导入方式 526 527 # 1、import 模块名 调用:模块名.函数名() 528 # 2、from 模块名 import 函数名 调用:函数名() 529 # 注意:from xxx import * ----此方式只能导入公有的属性、方法、类, 530 # 无法导入以单下划线开头(protected)或以双下划线开头(private)的属性、方法、类, 531 # 加了all变量可以实现非公有属性方法类的导入 532 533 ''' 534 # 模块 mod2.py 535 536 __all__ = ['a','__a',"__test4",'_A'] 537 538 # public变量 539 a = 100 540 # protected变量 541 _a = 200 542 # private变量 543 __a = 300 544 545 def test2(): 546 print("这是mod2模块里的test2函数体") 547 def _test3(): 548 print("这是mod2模块里的test3函数体") 549 def __test4(): 550 print("这是mod2模块里的test4函数体") 551 552 553 class A: 554 def pri(self): 555 print("这是类A") 556 class _A: 557 def pri(self): 558 print("这是类_A") 559 class __A: 560 def pri(self): 561 print("这是类__A") 562 563 ''' 564 # __all__变量 565 # 模块里加入__all__变量,表示用from...import * 导入时只能导入all 566 # 里面保存的对象,防止导入不需要的东西。没有all则会导入所有公有的属性方法类 567 568 569 # 包 570 # 包:多个模块放在同一个文件夹下(其中包含初始化模块),则该文件夹就成了一个包。 571 # 在包的__init__.py模块里面的__all__变量还决定着包里的哪些模块可以被外界调用 572 ''' 573 注意:多种导入方式的区别 574 1、用from packag import * 这种方式只能从包里面导入__init__.py中__all__变量 575 保存的模块,其他模块无法导入。 576 2、from packag import module,调用时用module.method() 577 3、可以用from packag.packag2.module import * 从包下面的指定模块里导入所有, 578 这种导入方式不需要在__init__.py中指定模块名。 579 4、import packag.module,调用时用packag.module.method() 580 581 个人建议用第二种方式最好。 582 583 个人建的包是无法在python交互式模式下导入的,若想在交互模式下使用,则应该构建发布模块。 584 具体的发布过程见另一篇博客:https://www.cnblogs.com/wangyi0419/p/12495814.html 585 ''' 586 587 588 # 导入模块的搜索路径 589 # 在python中导入自己的模块时有时导不进来,可以在sys.path中添加自己模块的路径,这样 590 # python就能够找到了。 591 import sys 592 a = sys.path 593 print(a) 594 ''' 595 [ 596 'C:\\develop\\sublime2020\\python_file', 597 'C:\\develop\\devesoftware\\python3.7\\python37.zip', 598 'C:\\develop\\devesoftware\\python3.7\\DLLs', 599 'C:\\develop\\devesoftware\\python3.7\\lib', 600 'C:\\develop\\devesoftware\\python3.7', 601 'C:\\develop\\devesoftware\\python3.7\\lib\\site-packages' 602 ]''' 603 # sys.path.append("个人路径") 添加 604 605 606 # 列表生成式 607 # 608 a=[i for i in range(2,8)] 609 print(a) 610 a=list(range(1,10)) 611 print(a) 612 a=[i*j for i in range(1,5) for j in range(1,5)] 613 print(a) 614 615 # 输出九九乘法表 616 print('\n'.join([' '.join(['%s*%s=%-2s '%(j,i,j*i) for j in range(1,i+1)])for i in range(1,10)])) 617 618 a = [i if i%2==0 else -i for i in range(1,11)] 619 print(a) #[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10] 620 a = [i for i in range(1,11) if i%2==0 ] 621 print(a) #[2, 4, 6, 8, 10] 622 # 注意: 623 # 第一个if...else...是表达式,写在for前面; 624 # 写在for后面的if是过滤条件,不能带else 625 626 627 628 # 字典生成式 629 cook_str='BIDUPSID=D0727533D7147B7;PSTM=1530348042;BAIDUID=B1005C9BC2EB28' 630 dic = {i.split('=')[0]:i.split('=')[1] for i in cook_str.split(";")} 631 print(dic) 632 #{'BIDUPSID': 'D0727533D7147B7', 'PSTM': '1530348042', 'BAIDUID': 'B1005C9BC2EB28'} 633 634 635 636 # 模块循环导入 637 # 在a模块中导入b模块,在b模块中又导入了a模块,这就是循环导入,陷入死循环了,无解。 638 # 在程序设计中要避免出现这种情况,设计上分层,降低耦合。 639 640 641 # 集合 642 # set,{},集合里的元素不会重复 643 a=[1,2,3,2,1] 644 # 怎么对列表a去重呢? 645 # 方法一 646 b=[] 647 for i in a: 648 if i not in b: 649 b.append(i) 650 print(b) # [1, 2, 3] 651 # 方法二 652 s = set(a) 653 print(s) # {1, 2, 3} 654 L = list(s) 655 print(L) # [1, 2, 3] 656 657 658 659 # == 和is 660 # is 是比较两个引用是否指向了同一个对象(引用比较)。 661 # == 是比较两个对象是否相等。 662 a=1.1 663 b=1.1 664 print(a is b) # False 665 print(a==b) # True 666 a=[1] 667 b=[1] 668 print(a is b) # False 669 print(a==b) # True 670 a=100 671 b=100 672 print(a is b) # True 673 674 # 为什么这个是true呢?到底哪些数字不会新建对象? 675 # 写个程序测一下: 676 a = 1 677 b = 1 678 while id(a) == id(b): 679 a+=1 680 b+=1 681 print(a-1) # 256 682 683 a = 1 684 b = 1 685 while id(a) == id(b): 686 a-=1 687 b-=1 688 print(a+1) # -5 689 # 发现只有-5 到 256这之间的整数才不会新建对象,is的结果是true。 690 691 a=555 692 b=555 693 print(a is b) # False 694 695 696 # 关于变量 697 ''' 698 1、Python的变量创建过程是在代码第一次给他赋值就创建了变量, 699 之后的赋值会改变已经创建的变量名的值; 700 2、Python的变量是没有类型的,变量是通用的,只是在一个特定的时间点, 701 引用了一个特定的对象; 702 3、Python中 使用变量的时候,当变量出现在表达式中时,它会马上被所引用的对象所替代。 703 ''' 704 705 # 深拷贝和浅拷贝 706 import copy 707 a = [1,2,3] 708 b = [4,5,6] 709 c=[a,b] 710 d=c # 赋值, 711 e=copy.copy(c) # 浅拷贝,e和c指向不同内存,但是内部元素指向相同 712 f=copy.deepcopy(c) # 深拷贝,即递归拷贝,拷贝一切,f指向新的内存 713 a.append('haha') 714 print(c) # [[1, 2, 3, 'haha'], [4, 5, 6]] 715 print(e) # [[1, 2, 3, 'haha'], [4, 5, 6]] 716 print(f) # [[1, 2, 3], [4, 5, 6]] 717 print(id(c)) 718 print(id(e)) 719 print(id(f))# 三个不同的地址 720 721 # 深浅拷贝是对于可变类型对象而言的,不可变类型对象在python中没有拷贝一说。 722 a = (1,2) 723 b = a 724 c = copy.copy(a) 725 d = copy.deepcopy(a) 726 print(id(a)) # 三个地址相同 727 print(id(c)) 728 print(id(d)) 729 730 # 私有化 731 732 # 给实例对象添加与私有属性同名的公有属性 733 class Test(object): 734 def __init__(self): 735 self.__a = 1 736 self.b=2 737 def get(self): 738 print(self.__a) 739 print(self.b) 740 t=Test() 741 t.__a = 10 742 t.b=20 743 print(t.__a) 744 print(t.b) 745 t.get() 746 747 748 # property 749 # 正常情况下通过set设置私有属性的值,get来获取值,不让外界直接获取,同时设置的 750 # 时候也会对传入的实参进行必要的判断 751 class Goddess(object): 752 def __init__(self): 753 self.__age = 22 754 755 def get_age(self): 756 return self.__age 757 def set_age(self,age): 758 if age>=30 or age<=18: 759 print("年龄不在合理区间内") 760 else: 761 self.__age = age 762 print("年龄已保存") 763 764 g = Goddess() 765 print(g.get_age()) # 22 766 g.set_age(28) # 年龄已保存 767 print(g.get_age()) # 28 768 769 770 # 但这种做法每次都要调用set、get函数,稍微有点麻烦。可以通过property封装实现 771 # 像修改公有属性那样的用对象.属性名直接修改私有属性。 772 class Goddess(object): 773 def __init__(self): 774 self.__age = 22 775 776 def get_age(self): 777 return self.__age 778 def set_age(self,age): 779 if age>=30 or age<=18: 780 print("年龄不在合理区间内") 781 else: 782 self.__age = age 783 print("年龄已保存") 784 age = property(get_age,set_age) # 这里的变量名age可以随意取 785 g = Goddess() 786 g.age = 25 # 相当于 g.set_age(25) 787 print(g.age) # 25 ,相当于 g.get_age() 788 789 # property的第二种实现方式:装饰器 790 # 这里的set和get方法都要使用同一个名字age 791 # 792 class Goddess(object): 793 def __init__(self): 794 self.__age = 22 795 796 @property 797 def age(self): 798 return self.__age 799 800 @age.setter 801 def age(self,age): 802 if age>=30 or age<=18: 803 print("年龄不在合理区间内") 804 else: 805 self.__age = age 806 print("年龄已保存") 807 808 g = Goddess() 809 g.age = 27 # 调用第一个age方法 810 print(g.age) # 27 调用第二个age方法 811 812 # 元组的标志是逗号,而不是小括号。