当前位置: 首页 > news >正文

python总结(3)

创建自定义类

终于要创建自定义类了!下面是一个简单的示例:

class Person:

    def set_name(self, name):

        self.name = name

    def get_name(self):

        return self.name

    def greet(self):

        print("Hello, world! I'm {}.".format(self.name))

这个示例包含三个方法定义,它们类似于函数定义,但位于class语句内。Person当然是类的名称。class语句创建独立的命名空间,用于在其中定义函数。一切看起来都挺好,但你可能想知道参数self是什么。它指向对象本身。那么是哪个对象呢?下面通过创建两个实例来说明这一点。

foo = Person()

bar = Person()

foo.set_name('Luke Skywalker’)

bar.set_name("Anakin Skywalker’)

 foo.greet()

Hello, world! I'm Luke Skywalker.

 bar. greet()

Hello, world! I'm Anakin Skywalker.

这个示例可能有点简单,但澄清了self是什么。对foo调用set name和greet时,foo都会作为第一个参数自动传递给它们。我将这个参数命名为self,这非常贴切。实际上,可以随便给这个参数命名,但鉴于它总是指向对象本身,因此习惯上将其命名为self.显然,self很有用,甚至必不可少。如果没有它,所有的方法都无法访问对象本身–要操作的属性所属的对象。与以前一样,也可以从外部访问这些属性。

 foo. name

Luke Skywalker

bar.name ='Yoda

bar.greet()

Hello, world! I'm Yoda.

提示 如果foo是一个Person实例,可将foo.greet0)视为Person.greet(foo)的简写,但后者的多态性更低。

属性、函数和方法

实际上,方法和函数的区别表现在前面提到的参数self上。方法(更准确地说是关联的方法)将其第-个参数关联到它所属的实例,因此无需提供这个参数。无疑可以将对象的属性关联到一个普通函数,但这样就没有特殊的self参数了。

class Class:

    def method(self):

    ...

    print('I have a self!’)



def function():

    print("I don't...")



instance = Class()

instance.method() 



instance.method = function

instance.method() I don't...

请注意,有没有参数self并不取决于是否以刚才使用的方式(如instance.method)调用方法。实际上完全可以让另一个变量指向同一个方法。

 class Bird:

    song =’Squaawk!’

    def sing(self):

        print(self. song)

bird = Bird()

bird. sing()

Squaawk!

birdsong = bird.sing

birdsong()

Squaawk!

虽然最后一个方法调用看起来很像函数调用,但变量birdsong指向的是关联的方法bird.sing,这意味着它也能够访问参数self(即它也被关联到类的实例)。

再谈隐藏

默认情况下,可从外部访问对象的属性。再来看一下前面讨论封装时使用的示例。

c.name

Sir Lancelot

c.name ='Sir Gumby’

 c.get name()

Sir Gumby

有些程序员认为这没问题,但有些程序员(如Smalltalk雅之父)认为这违反了封装原则。他们认为应该对外部完全隐藏对象的状态(即不能从外部访问它们)。你可能会问,为何他们的立场如此极端?由每个对象管理自己的属性还不够吗?为何要向外部隐藏属性?毕竟,如果能直接访问ClosedObject(对象c所属的类)的属性name,就不需要创建方法setName和getName了,关键是其他程序员可能不知道(也不应知道)对象内部发生的情况。例如,ClosedObject可能在对象修改其名称时向管理员发送电子邮件。这种功能可能包含在方法set_name中。但如果直接设置c.name,结果将如何呢?什么都不会发生–根本不会发送电子邮件。为避免这类问题,可将属性定义为私有。私有属性不能从对象外部访问,而只能通过存取器方法(如get name和set name)来访问。

Python没有为私有属性提供直接的支持,而是要求程序员知道在什么情况下从外部修改属性是安全的,。毕竟,你必须在知道如何使用对象之后才能使用它。然而,通过玩点小花招,可获得类似于私有属性的效果。要让方法或属性成为私有的(不能从外部访问),只需让其名称以两个下划线打头即可。

class Secretive:

    def __inaccessible(self):

        print("Bet you can't see me ...")

    def accessible(self):

        print( The secret message is:")

        self.__inaccessible()

现在从外部不能访问 inaccessible,但在类中(如accessible中)依然可以使用它

s= Secretive()

s.inaccessible()

s.accessible()

The secret message is:

Bet you can't see me ..

虽然以两个下划线打头有点怪异,但这样的方法类似于其他语言中的标准私有方法。然而,幕后的处理手法并不标准:在类定义中,对所有以两个下划线打头的名称都进行转换,即在开头加上一个下划线和类名。

Secretive.__Secretive__inaccessible

只要知道这种幕后处理手法,就能从类外访问私有方法,然而不应这样做。

s. __Secretive__inaccessible()

Bet you can't see me .

总之,你无法禁止别人访问对象的私有方法和属性,但这种名称修改方式发出了强烈的信号,让他们不要这样做。

类的命名空间

下面两条语句大致等价:

def foo(x): return x*x

foo=lambda x:x*x

它们都创建一个返回参数平方的函数,并将这个函数关联到变量foo。可以在全局(模块)作用域内定义名称foo,也可以在函数或方法内定义。定义类时情况亦如此:在class语句中定义的代码都是在一个特殊的命名空间(类的命名空间)内执行的,而类的所有成员都可访问这个命名空间。类定义其实就是要执行的代码段,并非所有的Python程序员都知道这一点,但知道这一点很有帮助。例如,在类定义中,并非只能包含def语句。

class C:

      print('Class C being defined...)

Class C being defined.

这有点傻,但请看下面的代码:

class MemberCounter:

    members=0

    def init(self):

        MemberCounter.members += 1

m1 = MemberCounter()

ml.init()



MemberCounter.members

1

m2 = MemberCounter()

 m2.init()

2

MemberCounter.members

上述代码在类作用域内定义了一个变量,所有的成员(实例)都可访问它,这里使用它来计算类实例的数量。注意到这里使用了init来初始化所有实例,每个实例都可访问这个类作用域内的变量,就像方法一样。

m1.members

m2.members

如果你在一个实例中给属性members赋值,结果将如何呢?

 m1.members ='Two'

m1.members

Two

m2.members

2

新值被写入m1的一个属性中,这个属性遮住了类级变量。

指定超类

本章前面讨论过,子类扩展了超类的定义。要指定超类,可在class语句中的类名后加上超类名,并将其用圆括号括起。

class Filter:

    def init(self):

        self.blocked=[]

    def filter(self,sequence):

        return [x for x in sequence if x not in self.blocked

# SPAMFilter是Filter的子类

class SPAMFilter(Filter):

    def init(self):#重写超类Filter的方法init

    self.blocked = ['SPAM’]

Filter是一个过滤序列的通用类。实际上,它不会过滤掉任何东西。

f = Filter()

f.init ()

f.filter([1, 2,3])

[1,2,3]

Filter类的用途在于可用作其他类(如将’SPAM’从序列中过滤掉的SPAMFilter类)的基类(超类)

s=SPAMFilter()

s.init()

 s.filter(['SPAM'.'SPAM','SPAM','SPAM','eggs’,’SPAM,’bacon '])



bacon’

"eggs

请注意SPAMFilter类的定义中有两个要点。

口 以提供新定义的方式重写了Filter类中方法init的定义

口 直接从Filter类继承了方法filter的定义,因此无需重新编写其定义。

第二点说明了继承很有用的原因:可以创建大量不同的过滤器类,它们都从Filter类派生而来,并且都使用已编写好的方法filter。这就是懒惰的好处。

面向对象设计总结:

口将相关的东西放在一起。如果一个函数操作一个全局变量,最好将它们作为一个类的属性和方法,。

口 不要让对象之间过于亲密。方法应只关心其所属实例的属性,对于其他实例的状态,让它们自己去管

理就好了。

口慎用继承,尤其是多重继承。继承有时很有用,但在有些情况下可能带来不必要的复杂性。要正确地

使用多重继承很难,要排除其中的bug更难。

口 保持简单。让方法短小紧凑。一般而言,应确保大多数方法都能在30秒内读完并理解。对于其余的方法,尽可能将其篇幅控制在一页或一屏内。

确定需要哪些类以及这些类应包含哪些方法时,尝试像下面这样做,

(1)将有关问题的描述(程序需要做什么)记录下来,并给所有的名词、动词和形容词加上标记

(2)在名词中找出可能的类。

(3)在动词中找出可能的方法。

(4)在形容词中找出可能的属性

(5)将找出的方法和属性分配给各个类.

有了面向对象模型的草图后,还需考虑类和对象之间的关系(如继承或协作)以及它们的职责。为进-步改进模型,可像下面这样做。

(1)记录(或设想)一系列用例,即使用程序的场景,并尽力确保这些用例涵盖了所有的功能,

(2)透彻而仔细地考虑每个场景,确保模型包含了所需的一切。如果有遗漏,就加上;如果有不太对的地方,就修改。不断地重复这个过程,直到对模型满意为止。

有了你认为行之有效的模型后,就可以着手编写程序了。你很可能需要修改模型或程序的某些部分,所幸这在Python中很容易,请不用担心。只管按这里说的去做就好。

相关文章:

  • QT工程打开、编译、运行流程
  • Netty基础—2.网络编程基础三
  • Dify平台训练个人文档助手
  • 2024年群智能SCI1区TOP:混沌可行性恢复粒子群算法CEPSO,深度解析+性能实测
  • 20250212:linux系统DNS解析卡顿5秒的bug
  • 关于mybatis查询时,时间字段的映射问题
  • Java 集合框架大师课:集合框架源码解剖室(五)
  • 内网安全防护新思路 —— HFish + ELK 与 T-Pot 全面蜜罐系统比较分析
  • Ollama杂记
  • bin/python: bad interpreter: No such file or directory
  • Python:正则表达式
  • Java数据结构第二十二期:Map与Set的高效应用之道(一)
  • Nginx正向代理HTTPS配置指南(仅供参考)
  • K8s 1.27.1 实战系列(十)PV PVC
  • 三角形页面
  • DeepSeek API 客户端使用文档
  • 重生之我在学Vue--第7天 Vue 3 数据请求(Axios)
  • Unity辅助工具_头部与svn
  • DeepIn Wps 字体缺失问题
  • 安全焊接,智慧监管
  • ps怎么做网站模板/网站浏览器
  • 网站转让 备案/seo分析报告
  • 做h5商城网站/怎么样在百度上推广自己的产品
  • 自己ip做网站/阿里云搜索引擎网址
  • 什么网站可以接活在家做/爱站网域名查询
  • 最低成本做企业网站 白之家/新浪微指数